| ... | ... | @@ -1,3 +1,9 @@ |
| 1 | //! An atom is a single smallest unit of measure that will get an |
| 2 | //! allocated virtual memory address in the final linked image. |
| 3 | //! For example, we parse each input section within an input relocatable |
| 4 | //! object file into a set of atoms which are then laid out contiguously |
| 5 | //! as they were defined in the input file. |
| 6 | |
| 1 | 7 | const Atom = @This(); |
| 2 | 8 | |
| 3 | 9 | const std = @import("std"); |
| ... | ... | @@ -17,33 +23,38 @@ const Object = @import("Object.zig"); |
| 17 | 23 | const SymbolWithLoc = @import("zld.zig").SymbolWithLoc; |
| 18 | 24 | const Zld = @import("zld.zig").Zld; |
| 19 | 25 | |
| 20 | | /// Each decl always gets a local symbol with the fully qualified name. |
| 21 | | /// The vaddr and size are found here directly. |
| 22 | | /// The file offset is found by computing the vaddr offset from the section vaddr |
| 23 | | /// the symbol references, and adding that to the file offset of the section. |
| 24 | | /// If this field is 0, it means the codegen size = 0 and there is no symbol or |
| 25 | | /// offset table entry. |
| 26 | /// Each Atom always gets a symbol with the fully qualified name. |
| 27 | /// The symbol can reside in any object file context structure in `symtab` array |
| 28 | /// (see `Object`), or if the symbol is a synthetic symbol such as a GOT cell or |
| 29 | /// a stub trampoline, it can be found in the linkers `locals` arraylist. |
| 26 | 30 | sym_index: u32, |
| 27 | 31 | |
| 28 | | /// If this Atom references a subsection in an Object file, `nsyms_trailing` |
| 29 | | /// tells how many symbols trailing `sym_index` fall within this Atom's address |
| 30 | | /// range. |
| 31 | | inner_sym_index: u32, |
| 32 | | inner_nsyms_trailing: u32, |
| 33 | | |
| 34 | | /// -1 means symbol defined by the linker. |
| 32 | /// -1 means an Atom is a synthetic Atom such as a GOT cell defined by the linker. |
| 35 | 33 | /// Otherwise, it is the index into appropriate object file. |
| 34 | /// Prefer using `getFile()` helper to get the file index out rather than using |
| 35 | /// the field directly. |
| 36 | 36 | file: i32, |
| 37 | 37 | |
| 38 | | /// Size and alignment of this atom |
| 39 | | /// Unlike in Elf, we need to store the size of this symbol as part of |
| 40 | | /// the atom since macho.nlist_64 lacks this information. |
| 38 | /// If this Atom is not a synthetic Atom, i.e., references a subsection in an |
| 39 | /// Object file, `inner_sym_index` and `inner_nsyms_trailing` tell where and if |
| 40 | /// this Atom contains any additional symbol references that fall within this Atom's |
| 41 | /// address range. These could for example be an alias symbol which can be used |
| 42 | /// internally by the relocation records, or if the Object file couldn't be split |
| 43 | /// into subsections, this Atom may encompass an entire input section. |
| 44 | inner_sym_index: u32, |
| 45 | inner_nsyms_trailing: u32, |
| 46 | |
| 47 | /// Size of this atom. |
| 41 | 48 | size: u64, |
| 42 | 49 | |
| 43 | 50 | /// Alignment of this atom as a power of 2. |
| 44 | 51 | /// For instance, aligmment of 0 should be read as 2^0 = 1 byte aligned. |
| 45 | 52 | alignment: u32, |
| 46 | 53 | |
| 54 | /// Cached index and length into the relocations records array that correspond to |
| 55 | /// this Atom and need to be resolved before the Atom can be committed into the |
| 56 | /// final linked image. |
| 57 | /// Do not use these fields directly. Instead, use `getAtomRelocs()` helper. |
| 47 | 58 | cached_relocs_start: i32, |
| 48 | 59 | cached_relocs_len: u32, |
| 49 | 60 | |
| ... | ... | @@ -64,6 +75,8 @@ pub const empty = Atom{ |
| 64 | 75 | .next_index = null, |
| 65 | 76 | }; |
| 66 | 77 | |
| 78 | /// Returns `null` if the Atom is a synthetic Atom. |
| 79 | /// Otherwise, returns an index into an array of Objects. |
| 67 | 80 | pub inline fn getFile(self: Atom) ?u31 { |
| 68 | 81 | if (self.file == -1) return null; |
| 69 | 82 | return @intCast(u31, self.file); |
| ... | ... | @@ -90,6 +103,8 @@ const InnerSymIterator = struct { |
| 90 | 103 | } |
| 91 | 104 | }; |
| 92 | 105 | |
| 106 | /// Returns an iterator over potentially contained symbols. |
| 107 | /// Panics when called on a synthetic Atom. |
| 93 | 108 | pub fn getInnerSymbolsIterator(zld: *Zld, atom_index: AtomIndex) InnerSymIterator { |
| 94 | 109 | const atom = zld.getAtom(atom_index); |
| 95 | 110 | assert(atom.getFile() != null); |
| ... | ... | @@ -100,6 +115,10 @@ pub fn getInnerSymbolsIterator(zld: *Zld, atom_index: AtomIndex) InnerSymIterato |
| 100 | 115 | }; |
| 101 | 116 | } |
| 102 | 117 | |
| 118 | /// Returns a section alias symbol if one is defined. |
| 119 | /// An alias symbol is used to represent the start of an input section |
| 120 | /// if there were no symbols defined within that range. |
| 121 | /// Alias symbols are only used on x86_64. |
| 103 | 122 | pub fn getSectionAlias(zld: *Zld, atom_index: AtomIndex) ?SymbolWithLoc { |
| 104 | 123 | const atom = zld.getAtom(atom_index); |
| 105 | 124 | assert(atom.getFile() != null); |
| ... | ... | @@ -119,6 +138,8 @@ pub fn getSectionAlias(zld: *Zld, atom_index: AtomIndex) ?SymbolWithLoc { |
| 119 | 138 | return null; |
| 120 | 139 | } |
| 121 | 140 | |
| 141 | /// Given an index into a contained symbol within, calculates an offset wrt |
| 142 | /// the start of this Atom. |
| 122 | 143 | pub fn calcInnerSymbolOffset(zld: *Zld, atom_index: AtomIndex, sym_index: u32) u64 { |
| 123 | 144 | const atom = zld.getAtom(atom_index); |
| 124 | 145 | assert(atom.getFile() != null); |