diff options
author | pommicket <pommicket@gmail.com> | 2022-11-06 21:52:27 -0500 |
---|---|---|
committer | pommicket <pommicket@gmail.com> | 2022-11-06 21:52:27 -0500 |
commit | dab85a8d1e9b99cbef225b8f5cc7fc001405828d (patch) | |
tree | 5075a75a7d18f44e7ee0c00b0d5441a13d225988 /src/linker.rs | |
parent | 6b7d46d33cdb9c99852f2d4378243ab08ba876ba (diff) |
docs done for now
Diffstat (limited to 'src/linker.rs')
-rw-r--r-- | src/linker.rs | 44 |
1 files changed, 28 insertions, 16 deletions
diff --git a/src/linker.rs b/src/linker.rs index 8aaff33..f8f5760 100644 --- a/src/linker.rs +++ b/src/linker.rs @@ -1,8 +1,9 @@ /*! Linker producing small executables. Smallness is the *only* goal. -This linker makes "bad" executables in many ways. -You shouldn't use it unless all you want is a tiny little executable file. +This linker makes "bad" executables in many ways. For example, +all initialized data will be executable. All code will be writable. +You shouldn't use this unless all you want is a tiny little executable file. Currently, only 32-bit ELF is supported. If you are using C, you will need `gcc-multilib` for the 32-bit headers. @@ -23,14 +24,13 @@ As such, the resulting executable will be difficult to debug and *C++ exceptions may not work*. */ -use crate::{elf, util}; +use crate::elf; use io::{BufRead, Seek, Write}; use std::collections::{BTreeMap, HashMap}; use std::{fmt, fs, io, mem, path}; use elf::Reader as ELFReader; use elf::ToBytes; -use util::u32_from_le_slice; pub enum LinkError { IO(io::Error), @@ -38,7 +38,7 @@ pub enum LinkError { TooLarge, /// entry point not found NoEntry(String), - /// entry point was declared, and (probably) used, but not defined + /// entry point was declared, but not defined EntryNotDefined(String), } @@ -71,10 +71,10 @@ impl From<&LinkError> for String { pub enum LinkWarning { /// unsupported relocation type RelUnsupported(u8), - /// relocation is too large to fit inside its owner + /// relocation is too large to fit inside its symbol RelOOB(String, u64), - /// relocation is in a BSS section or some shit - RelNoData(String, u64), + /// relocation does not take place in a symbol's data + RelNoSym(String, u64), } impl fmt::Display for LinkWarning { @@ -82,7 +82,7 @@ impl fmt::Display for LinkWarning { use LinkWarning::*; match self { RelOOB(text, offset) => write!(f, "relocation applied to {text}+0x{offset:x}, which goes outside of the symbol (it will be ignored)."), - RelNoData(source, offset) => write!( + RelNoSym(source, offset) => write!( f, "relocation {source}+0x{offset:x} not in a data/text section. it will be ignored." ), @@ -131,7 +131,8 @@ impl fmt::Display for ObjectError { type SymbolNameType = u32; /// To be more efficientâ„¢, we use integers to keep track of symbol names. -/// A SymbolName doesn't need to refer to a symbol which has been defined. +/// +/// A `SymbolName` doesn't need to refer to a symbol which has been defined. #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] struct SymbolName(SymbolNameType); /// Keeps track of string-[SymbolName] conversion. @@ -182,14 +183,18 @@ impl SourceId { } type SymbolIdType = u32; -//// A symbol ID refers to a symbol *which has a definition*, unlike [SymbolName]. + +/// A symbol ID refers to a specific *definition* of a symbol. +/// +/// There might be multiple `SymbolId`s corresponding to a single [SymbolName], +/// since local symbols with the same name can be defined in separate object files. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] struct SymbolId(SymbolIdType); /// Value of a symbol. #[derive(Debug)] enum SymbolValue { - /// We make one big BSS section, this is an offset into it. + /// offset into BSS section Bss(u64), /// Data associated with this symbol (machine code for functions, /// bytes making up string literals, etc.) @@ -317,8 +322,9 @@ pub struct Linker<'a> { warn: Box<dyn Fn(LinkWarning) + 'a>, } -/// maps between offsets in an object file and symbols defined in that file. -/// (Note: it is specific to a single object file, and only kept around temporarily +/// Maps between offsets in an object file and symbols defined in that file. +/// +/// (Note: this is specific to a single object file, and only kept around temporarily /// during a call to [Linker::add_object].) /// This is used to figure out where relocations are taking place. struct SymbolOffsetMap { @@ -353,6 +359,7 @@ impl SymbolOffsetMap { } /// Graph of which symbols depend on which symbols. +/// /// This is needed so we don't emit anything for unused symbols. struct SymbolGraph { graph: Vec<Vec<SymbolId>>, @@ -809,7 +816,7 @@ impl<'a> Linker<'a> { addend: rel.addend, }); } else { - self.emit_warning(LinkWarning::RelNoData( + self.emit_warning(LinkWarning::RelNoSym( self.source_name(source_id).into(), rel.entry_offset, )); @@ -905,6 +912,11 @@ impl<'a> Linker<'a> { // guarantee failure if apply_offset can't be converted to usize. let apply_start = apply_offset.try_into().unwrap_or(usize::MAX - 1000); + fn u32_from_le_slice(data: &[u8]) -> u32 { + u32::from_le_bytes([data[0], data[1], data[2], data[3]]) + } + + match apply_symbol_info.value { Data(_) => { let mut in_bounds = true; @@ -927,7 +939,7 @@ impl<'a> Linker<'a> { } } _ => { - self.emit_warning(LinkWarning::RelNoData( + self.emit_warning(LinkWarning::RelNoSym( self.source_name(rel.source_id).into(), apply_offset, )); |