Commit 31dcb0dde7

Jakub Konka <kubkon@jakubkonka.com>
2021-09-11 01:18:37
macho: change all occurrences of TextBlock into Atom
and unify allocateAtom with allocateTextBlock.
1 parent 6e0c395
Changed files (1)
src
src/link/MachO.zig
@@ -158,8 +158,8 @@ stub_preamble_sym_index: ?u32 = null,
 strtab: std.ArrayListUnmanaged(u8) = .{},
 strtab_dir: std.HashMapUnmanaged(u32, u32, StringIndexContext, std.hash_map.default_max_load_percentage) = .{},
 
-got_entries_map: std.AutoArrayHashMapUnmanaged(GotIndirectionKey, *TextBlock) = .{},
-stubs_map: std.AutoArrayHashMapUnmanaged(u32, *TextBlock) = .{},
+got_entries_map: std.AutoArrayHashMapUnmanaged(GotIndirectionKey, *Atom) = .{},
+stubs_map: std.AutoArrayHashMapUnmanaged(u32, *Atom) = .{},
 
 error_flags: File.ErrorFlags = File.ErrorFlags{},
 
@@ -171,12 +171,12 @@ has_stabs: bool = false,
 
 section_ordinals: std.AutoArrayHashMapUnmanaged(MatchingSection, void) = .{},
 
-/// A list of text blocks that have surplus capacity. This list can have false
+/// A list of atoms that have surplus capacity. This list can have false
 /// positives, as functions grow and shrink over time, only sometimes being added
 /// or removed from the freelist.
 ///
-/// A text block has surplus capacity when its overcapacity value is greater than
-/// padToIdeal(minimum_text_block_size). That is, when it has so
+/// An atom has surplus capacity when its overcapacity value is greater than
+/// padToIdeal(minimum_atom_size). That is, when it has so
 /// much extra capacity, that we could fit a small new symbol in it, itself with
 /// ideal_capacity or more.
 ///
@@ -184,23 +184,23 @@ section_ordinals: std.AutoArrayHashMapUnmanaged(MatchingSection, void) = .{},
 ///
 /// Overcapacity is measured by actual_capacity - ideal_capacity. Note that
 /// overcapacity can be negative. A simple way to have negative overcapacity is to
-/// allocate a fresh text block, which will have ideal capacity, and then grow it
+/// allocate a fresh atom, which will have ideal capacity, and then grow it
 /// by 1 byte. It will then have -1 overcapacity.
-block_free_lists: std.AutoHashMapUnmanaged(MatchingSection, std.ArrayListUnmanaged(*TextBlock)) = .{},
+atom_free_lists: std.AutoHashMapUnmanaged(MatchingSection, std.ArrayListUnmanaged(*Atom)) = .{},
 
-/// Pointer to the last allocated text block
-blocks: std.AutoHashMapUnmanaged(MatchingSection, *TextBlock) = .{},
+/// Pointer to the last allocated atom
+atoms: std.AutoHashMapUnmanaged(MatchingSection, *Atom) = .{},
 
-/// List of TextBlocks that are owned directly by the linker.
-/// Currently these are only TextBlocks that are the result of linking
-/// object files. TextBlock which take part in incremental linking are 
+/// List of atoms that are owned directly by the linker.
+/// Currently these are only atoms that are the result of linking
+/// object files. Atoms which take part in incremental linking are 
 /// at present owned by Module.Decl.
 /// TODO consolidate this.
-managed_blocks: std.ArrayListUnmanaged(*TextBlock) = .{},
+managed_atoms: std.ArrayListUnmanaged(*Atom) = .{},
 
 /// Table of Decls that are currently alive.
 /// We store them here so that we can properly dispose of any allocated
-/// memory within the TextBlock in the incremental linker.
+/// memory within the atom in the incremental linker.
 /// TODO consolidate this.
 decls: std.AutoArrayHashMapUnmanaged(*Module.Decl, void) = .{},
 
@@ -768,31 +768,8 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {
         try self.addDataInCodeLC();
         try self.addCodeSignatureLC();
 
-        try self.parseTextBlocks();
+        try self.parseObjectsIntoAtoms();
         try self.allocateGlobalSymbols();
-        {
-            log.debug("locals:", .{});
-            for (self.locals.items) |sym| {
-                log.debug("  {s}: {}", .{ self.getString(sym.n_strx), sym });
-            }
-            log.debug("globals:", .{});
-            for (self.globals.items) |sym| {
-                log.debug("  {s}: {}", .{ self.getString(sym.n_strx), sym });
-            }
-            log.debug("undefs:", .{});
-            for (self.undefs.items) |sym| {
-                log.debug("  {s}: {}", .{ self.getString(sym.n_strx), sym });
-            }
-            log.debug("unresolved:", .{});
-            for (self.unresolved.keys()) |key| {
-                log.debug("  {d} => {s}", .{ key, self.unresolved.get(key).? });
-            }
-            log.debug("resolved:", .{});
-            var it = self.symbol_resolver.iterator();
-            while (it.next()) |entry| {
-                log.debug("  {s} => {}", .{ self.getString(entry.key_ptr.*), entry.value_ptr.* });
-            }
-        }
         try self.writeAtoms();
 
         if (self.bss_section_index) |idx| {
@@ -1637,87 +1614,24 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
     return res;
 }
 
-pub fn createEmptyAtom(self: *MachO, local_sym_index: u32, size: u64, alignment: u32) !*TextBlock {
+pub fn createEmptyAtom(self: *MachO, local_sym_index: u32, size: u64, alignment: u32) !*Atom {
     const code = try self.base.allocator.alloc(u8, size);
     defer self.base.allocator.free(code);
     mem.set(u8, code, 0);
 
-    const atom = try self.base.allocator.create(TextBlock);
+    const atom = try self.base.allocator.create(Atom);
     errdefer self.base.allocator.destroy(atom);
-    atom.* = TextBlock.empty;
+    atom.* = Atom.empty;
     atom.local_sym_index = local_sym_index;
     atom.size = size;
     atom.alignment = alignment;
     try atom.code.appendSlice(self.base.allocator, code);
-    try self.managed_blocks.append(self.base.allocator, atom);
+    try self.managed_atoms.append(self.base.allocator, atom);
 
     return atom;
 }
 
-pub fn allocateAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !u64 {
-    const seg = &self.load_commands.items[match.seg].Segment;
-    const sect = &seg.sections.items[match.sect];
-
-    const sym = &self.locals.items[atom.local_sym_index];
-    const needs_padding = match.seg == self.text_segment_cmd_index.? and match.sect == self.text_section_index.?;
-
-    var atom_placement: ?*TextBlock = null;
-    const atom_alignment = try math.powi(u32, 2, atom.alignment);
-
-    // TODO converge with `allocateTextBlock` and handle free list
-    var vaddr = if (self.blocks.get(match)) |last| blk: {
-        const last_atom_sym = self.locals.items[last.local_sym_index];
-        const ideal_capacity = if (needs_padding) padToIdeal(last.size) else last.size;
-        const ideal_capacity_end_vaddr = last_atom_sym.n_value + ideal_capacity;
-        const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, atom_alignment);
-        atom_placement = last;
-        break :blk new_start_vaddr;
-    } else mem.alignForwardGeneric(u64, sect.addr, atom_alignment);
-
-    // TODO what if the section which was preallocated is not aligned to the maximum (section) alignment?
-    // Should we move the section?
-
-    log.debug("allocating atom for symbol {s} at address 0x{x}", .{ self.getString(sym.n_strx), vaddr });
-
-    const expand_section = atom_placement == null or atom_placement.?.next == null;
-    if (expand_section) {
-        const needed_size = @intCast(u32, (vaddr + atom.size) - sect.addr);
-        try self.growSection(match, needed_size);
-        sect.size = needed_size;
-        self.load_commands_dirty = true;
-    }
-    sect.@"align" = math.max(sect.@"align", atom.alignment);
-
-    const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
-    sym.n_value = vaddr;
-    sym.n_sect = n_sect;
-
-    // Update each alias (if any)
-    for (atom.aliases.items) |index| {
-        const alias_sym = &self.locals.items[index];
-        alias_sym.n_value = vaddr;
-        alias_sym.n_sect = n_sect;
-    }
-
-    // Update each symbol contained within the TextBlock
-    for (atom.contained.items) |sym_at_off| {
-        const contained_sym = &self.locals.items[sym_at_off.local_sym_index];
-        contained_sym.n_value = vaddr + sym_at_off.offset;
-        contained_sym.n_sect = n_sect;
-    }
-
-    if (self.blocks.getPtr(match)) |last| {
-        last.*.next = atom;
-        atom.prev = last.*;
-        last.* = atom;
-    } else {
-        try self.blocks.putNoClobber(self.base.allocator, match, atom);
-    }
-
-    return vaddr;
-}
-
-pub fn writeAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !void {
+pub fn writeAtom(self: *MachO, atom: *Atom, match: MatchingSection) !void {
     const seg = self.load_commands.items[match.seg].Segment;
     const sect = seg.sections.items[match.sect];
     const sym = self.locals.items[atom.local_sym_index];
@@ -1728,7 +1642,7 @@ pub fn writeAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !void {
 }
 
 fn allocateLocalSymbols(self: *MachO, match: MatchingSection, offset: i64) !void {
-    var atom = self.blocks.get(match) orelse return;
+    var atom = self.atoms.get(match) orelse return;
 
     while (true) {
         const atom_sym = &self.locals.items[atom.local_sym_index];
@@ -1751,8 +1665,6 @@ fn allocateLocalSymbols(self: *MachO, match: MatchingSection, offset: i64) !void
 }
 
 fn allocateGlobalSymbols(self: *MachO) !void {
-    // TODO should we do this in `allocateAtom` (or similar)? Then, we would need to
-    // store the link atom -> globals somewhere.
     var sym_it = self.symbol_resolver.valueIterator();
     while (sym_it.next()) |resolv| {
         if (resolv.where != .global) continue;
@@ -1770,12 +1682,14 @@ fn writeAtoms(self: *MachO) !void {
     defer buffer.deinit();
     var file_offset: ?u64 = null;
 
-    var it = self.blocks.iterator();
+    var it = self.atoms.iterator();
     while (it.next()) |entry| {
         const match = entry.key_ptr.*;
         const seg = self.load_commands.items[match.seg].Segment;
         const sect = seg.sections.items[match.sect];
-        var atom: *TextBlock = entry.value_ptr.*;
+        var atom: *Atom = entry.value_ptr.*;
+
+        log.debug("writing atoms in {s},{s}", .{ commands.segmentName(sect), commands.sectionName(sect) });
 
         while (atom.prev) |prev| {
             atom = prev;
@@ -1789,6 +1703,8 @@ fn writeAtoms(self: *MachO) !void {
                     break :blk next_sym.n_value - (atom_sym.n_value + atom.size);
                 } else 0;
 
+                log.debug("  (adding atom {s} to buffer: {})", .{ self.getString(atom_sym.n_strx), atom_sym });
+
                 try atom.resolveRelocs(self);
                 try buffer.appendSlice(atom.code.items);
                 try buffer.ensureUnusedCapacity(padding_size);
@@ -1824,7 +1740,7 @@ fn writeAtoms(self: *MachO) !void {
     }
 }
 
-pub fn createGotAtom(self: *MachO, key: GotIndirectionKey) !*TextBlock {
+pub fn createGotAtom(self: *MachO, key: GotIndirectionKey) !*Atom {
     const local_sym_index = @intCast(u32, self.locals.items.len);
     try self.locals.append(self.base.allocator, .{
         .n_strx = try self.makeString("l_zld_got_entry"),
@@ -1860,7 +1776,7 @@ pub fn createGotAtom(self: *MachO, key: GotIndirectionKey) !*TextBlock {
     return atom;
 }
 
-fn createDyldPrivateAtom(self: *MachO) !*TextBlock {
+fn createDyldPrivateAtom(self: *MachO) !*Atom {
     const local_sym_index = @intCast(u32, self.locals.items.len);
     try self.locals.append(self.base.allocator, .{
         .n_strx = try self.makeString("l_zld_dyld_private"),
@@ -1873,7 +1789,7 @@ fn createDyldPrivateAtom(self: *MachO) !*TextBlock {
     return self.createEmptyAtom(local_sym_index, @sizeOf(u64), 3);
 }
 
-fn createStubHelperPreambleAtom(self: *MachO) !*TextBlock {
+fn createStubHelperPreambleAtom(self: *MachO) !*Atom {
     const arch = self.base.options.target.cpu.arch;
     const size: u64 = switch (arch) {
         .x86_64 => 15,
@@ -2006,7 +1922,7 @@ fn createStubHelperPreambleAtom(self: *MachO) !*TextBlock {
     return atom;
 }
 
-pub fn createStubHelperAtom(self: *MachO) !*TextBlock {
+pub fn createStubHelperAtom(self: *MachO) !*Atom {
     const arch = self.base.options.target.cpu.arch;
     const stub_size: u4 = switch (arch) {
         .x86_64 => 10,
@@ -2072,7 +1988,7 @@ pub fn createStubHelperAtom(self: *MachO) !*TextBlock {
     return atom;
 }
 
-pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, lazy_binding_sym_index: u32) !*TextBlock {
+pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, lazy_binding_sym_index: u32) !*Atom {
     const local_sym_index = @intCast(u32, self.locals.items.len);
     try self.locals.append(self.base.allocator, .{
         .n_strx = try self.makeString("l_zld_lazy_ptr"),
@@ -2102,7 +2018,7 @@ pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, lazy_binding_sym
     return atom;
 }
 
-pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*TextBlock {
+pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {
     const arch = self.base.options.target.cpu.arch;
     const alignment: u2 = switch (arch) {
         .x86_64 => 0,
@@ -2273,14 +2189,6 @@ fn resolveSymbolsInObject(
                     continue;
                 },
                 .undef => {
-                    // const undef = &self.undefs.items[resolv.where_index];
-                    // undef.* = .{
-                    //     .n_strx = 0,
-                    //     .n_type = macho.N_UNDF,
-                    //     .n_sect = 0,
-                    //     .n_desc = 0,
-                    //     .n_value = 0,
-                    // };
                     _ = self.unresolved.fetchSwapRemove(resolv.where_index);
                 },
             }
@@ -2437,23 +2345,36 @@ fn resolveSymbols(self: *MachO) !void {
         resolv.local_sym_index = local_sym_index;
 
         const atom = try self.createEmptyAtom(local_sym_index, size, alignment);
-        _ = try self.allocateAtom(atom, match);
+        const alignment_pow_2 = try math.powi(u32, 2, alignment);
+        const vaddr = try self.allocateAtom(atom, size, alignment_pow_2, match);
+        sym.n_value = vaddr;
     }
 
     try self.resolveDyldStubBinder();
     {
-        const atom = try self.createDyldPrivateAtom();
-        _ = try self.allocateAtom(atom, .{
+        const match = MatchingSection{
             .seg = self.data_segment_cmd_index.?,
             .sect = self.data_section_index.?,
-        });
+        };
+        const atom = try self.createDyldPrivateAtom();
+        const sym = &self.locals.items[atom.local_sym_index];
+        const vaddr = try self.allocateAtom(atom, @sizeOf(u64), 8, match);
+        sym.n_value = vaddr;
+        sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
+        log.debug("allocated {s} atom at 0x{x}", .{ self.getString(sym.n_strx), vaddr });
     }
     {
-        const atom = try self.createStubHelperPreambleAtom();
-        _ = try self.allocateAtom(atom, .{
+        const match = MatchingSection{
             .seg = self.text_segment_cmd_index.?,
             .sect = self.stub_helper_section_index.?,
-        });
+        };
+        const atom = try self.createStubHelperPreambleAtom();
+        const sym = &self.locals.items[atom.local_sym_index];
+        const alignment = try math.powi(u32, 2, atom.alignment);
+        const vaddr = try self.allocateAtom(atom, atom.size, alignment, match);
+        sym.n_value = vaddr;
+        sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
+        log.debug("allocated {s} atom at 0x{x}", .{ self.getString(sym.n_strx), vaddr });
     }
 
     // Third pass, resolve symbols in dynamic libraries.
@@ -2483,30 +2404,45 @@ fn resolveSymbols(self: *MachO) !void {
                     .stub => {
                         if (self.stubs_map.contains(resolv.where_index)) break :outer_blk;
                         const stub_helper_atom = blk: {
-                            const atom = try self.createStubHelperAtom();
-                            _ = try self.allocateAtom(atom, .{
+                            const match = MatchingSection{
                                 .seg = self.text_segment_cmd_index.?,
                                 .sect = self.stub_helper_section_index.?,
-                            });
+                            };
+                            const atom = try self.createStubHelperAtom();
+                            const atom_sym = &self.locals.items[atom.local_sym_index];
+                            const alignment = try math.powi(u32, 2, atom.alignment);
+                            const vaddr = try self.allocateAtom(atom, atom.size, alignment, match);
+                            atom_sym.n_value = vaddr;
+                            atom_sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
                             break :blk atom;
                         };
                         const laptr_atom = blk: {
+                            const match = MatchingSection{
+                                .seg = self.data_segment_cmd_index.?,
+                                .sect = self.la_symbol_ptr_section_index.?,
+                            };
                             const atom = try self.createLazyPointerAtom(
                                 stub_helper_atom.local_sym_index,
                                 resolv.where_index,
                             );
-                            _ = try self.allocateAtom(atom, .{
-                                .seg = self.data_segment_cmd_index.?,
-                                .sect = self.la_symbol_ptr_section_index.?,
-                            });
+                            const atom_sym = &self.locals.items[atom.local_sym_index];
+                            const alignment = try math.powi(u32, 2, atom.alignment);
+                            const vaddr = try self.allocateAtom(atom, atom.size, alignment, match);
+                            atom_sym.n_value = vaddr;
+                            atom_sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
                             break :blk atom;
                         };
                         const stub_atom = blk: {
-                            const atom = try self.createStubAtom(laptr_atom.local_sym_index);
-                            _ = try self.allocateAtom(atom, .{
+                            const match = MatchingSection{
                                 .seg = self.text_segment_cmd_index.?,
                                 .sect = self.stubs_section_index.?,
-                            });
+                            };
+                            const atom = try self.createStubAtom(laptr_atom.local_sym_index);
+                            const atom_sym = &self.locals.items[atom.local_sym_index];
+                            const alignment = try math.powi(u32, 2, atom.alignment);
+                            const vaddr = try self.allocateAtom(atom, atom.size, alignment, match);
+                            atom_sym.n_value = vaddr;
+                            atom_sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
                             break :blk atom;
                         };
                         try self.stubs_map.putNoClobber(self.base.allocator, resolv.where_index, stub_atom);
@@ -2565,7 +2501,10 @@ fn resolveSymbols(self: *MachO) !void {
         // TODO perhaps we should special-case special symbols? Create a separate
         // linked list of atoms?
         const atom = try self.createEmptyAtom(local_sym_index, 0, 0);
-        _ = try self.allocateAtom(atom, match);
+        const sym = &self.locals.items[local_sym_index];
+        const vaddr = try self.allocateAtom(atom, 0, 1, match);
+        sym.n_value = vaddr;
+        atom.dirty = false; // We don't really want to write it to file.
     }
 
     for (self.unresolved.keys()) |index| {
@@ -2632,10 +2571,14 @@ fn resolveDyldStubBinder(self: *MachO) !void {
         .seg = self.data_const_segment_cmd_index.?,
         .sect = self.got_section_index.?,
     };
-    _ = try self.allocateAtom(atom, match);
+    const atom_sym = &self.locals.items[atom.local_sym_index];
+    const vaddr = try self.allocateAtom(atom, @sizeOf(u64), 8, match);
+    atom_sym.n_value = vaddr;
+    atom_sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
+    log.debug("allocated {s} atom at 0x{x}", .{ self.getString(sym.n_strx), vaddr });
 }
 
-fn parseTextBlocks(self: *MachO) !void {
+fn parseObjectsIntoAtoms(self: *MachO) !void {
     var parsed_atoms = Object.ParsedAtoms.init(self.base.allocator);
     defer parsed_atoms.deinit();
 
@@ -2710,7 +2653,7 @@ fn parseTextBlocks(self: *MachO) !void {
             metadata.alignment,
         });
 
-        const sect_size = if (self.blocks.get(match)) |last| blk: {
+        const sect_size = if (self.atoms.get(match)) |last| blk: {
             const last_atom_sym = self.locals.items[last.local_sym_index];
             break :blk last_atom_sym.n_value + last.size - sect.addr;
         } else 0;
@@ -2720,7 +2663,7 @@ fn parseTextBlocks(self: *MachO) !void {
         try self.growSection(match, needed_size);
         sect.size = needed_size;
 
-        var base_vaddr = if (self.blocks.get(match)) |last| blk: {
+        var base_vaddr = if (self.atoms.get(match)) |last| blk: {
             const last_atom_sym = self.locals.items[last.local_sym_index];
             break :blk last_atom_sym.n_value + last.size;
         } else sect.addr;
@@ -2750,7 +2693,7 @@ fn parseTextBlocks(self: *MachO) !void {
                 alias_sym.n_sect = n_sect;
             }
 
-            // Update each symbol contained within the TextBlock
+            // Update each symbol contained within the atom
             for (atom.contained.items) |sym_at_off| {
                 const contained_sym = &self.locals.items[sym_at_off.local_sym_index];
                 contained_sym.n_value = base_vaddr + sym_at_off.offset;
@@ -2764,13 +2707,13 @@ fn parseTextBlocks(self: *MachO) !void {
             } else break;
         }
 
-        if (self.blocks.getPtr(match)) |last| {
+        if (self.atoms.getPtr(match)) |last| {
             const first_atom = first_atoms.get(match).?;
             last.*.next = first_atom;
             first_atom.prev = last.*;
             last.* = first_atom;
         }
-        _ = try self.blocks.put(self.base.allocator, match, parsed_atoms.get(match).?);
+        _ = try self.atoms.put(self.base.allocator, match, parsed_atoms.get(match).?);
     }
 }
 
@@ -2905,18 +2848,18 @@ pub fn deinit(self: *MachO) void {
     }
     self.load_commands.deinit(self.base.allocator);
 
-    for (self.managed_blocks.items) |block| {
-        block.deinit(self.base.allocator);
-        self.base.allocator.destroy(block);
+    for (self.managed_atoms.items) |atom| {
+        atom.deinit(self.base.allocator);
+        self.base.allocator.destroy(atom);
     }
-    self.managed_blocks.deinit(self.base.allocator);
-    self.blocks.deinit(self.base.allocator);
+    self.managed_atoms.deinit(self.base.allocator);
+    self.atoms.deinit(self.base.allocator);
     {
-        var it = self.block_free_lists.valueIterator();
+        var it = self.atom_free_lists.valueIterator();
         while (it.next()) |free_list| {
             free_list.deinit(self.base.allocator);
         }
-        self.block_free_lists.deinit(self.base.allocator);
+        self.atom_free_lists.deinit(self.base.allocator);
     }
     for (self.decls.keys()) |decl| {
         decl.link.macho.deinit(self.base.allocator);
@@ -2936,25 +2879,21 @@ pub fn closeFiles(self: MachO) void {
     }
 }
 
-fn freeTextBlock(self: *MachO, text_block: *TextBlock) void {
-    log.debug("freeTextBlock {*}", .{text_block});
-    text_block.deinit(self.base.allocator);
+fn freeAtom(self: *MachO, atom: *Atom, match: MatchingSection) void {
+    log.debug("freeAtom {*}", .{atom});
+    atom.deinit(self.base.allocator);
 
-    const match = MatchingSection{
-        .seg = self.text_segment_cmd_index.?,
-        .sect = self.text_section_index.?,
-    };
-    const text_block_free_list = self.block_free_lists.getPtr(match).?;
+    const free_list = self.atom_free_lists.getPtr(match).?;
     var already_have_free_list_node = false;
     {
         var i: usize = 0;
-        // TODO turn text_block_free_list into a hash map
-        while (i < text_block_free_list.items.len) {
-            if (text_block_free_list.items[i] == text_block) {
-                _ = text_block_free_list.swapRemove(i);
+        // TODO turn free_list into a hash map
+        while (i < free_list.items.len) {
+            if (free_list.items[i] == atom) {
+                _ = free_list.swapRemove(i);
                 continue;
             }
-            if (text_block_free_list.items[i] == text_block.prev) {
+            if (free_list.items[i] == atom.prev) {
                 already_have_free_list_node = true;
             }
             i += 1;
@@ -2962,72 +2901,73 @@ fn freeTextBlock(self: *MachO, text_block: *TextBlock) void {
     }
     // TODO process free list for dbg info just like we do above for vaddrs
 
-    if (self.blocks.getPtr(match)) |last_text_block| {
-        if (last_text_block.* == text_block) {
-            if (text_block.prev) |prev| {
-                // TODO shrink the __text section size here
-                last_text_block.* = prev;
+    if (self.atoms.getPtr(match)) |last_atom| {
+        if (last_atom.* == atom) {
+            if (atom.prev) |prev| {
+                // TODO shrink the section size here
+                last_atom.* = prev;
             }
         }
     }
 
     if (self.d_sym) |*ds| {
-        if (ds.dbg_info_decl_first == text_block) {
-            ds.dbg_info_decl_first = text_block.dbg_info_next;
+        if (ds.dbg_info_decl_first == atom) {
+            ds.dbg_info_decl_first = atom.dbg_info_next;
         }
-        if (ds.dbg_info_decl_last == text_block) {
+        if (ds.dbg_info_decl_last == atom) {
             // TODO shrink the .debug_info section size here
-            ds.dbg_info_decl_last = text_block.dbg_info_prev;
+            ds.dbg_info_decl_last = atom.dbg_info_prev;
         }
     }
 
-    if (text_block.prev) |prev| {
-        prev.next = text_block.next;
+    if (atom.prev) |prev| {
+        prev.next = atom.next;
 
         if (!already_have_free_list_node and prev.freeListEligible(self.*)) {
             // The free list is heuristics, it doesn't have to be perfect, so we can ignore
             // the OOM here.
-            text_block_free_list.append(self.base.allocator, prev) catch {};
+            free_list.append(self.base.allocator, prev) catch {};
         }
     } else {
-        text_block.prev = null;
+        atom.prev = null;
     }
 
-    if (text_block.next) |next| {
-        next.prev = text_block.prev;
+    if (atom.next) |next| {
+        next.prev = atom.prev;
     } else {
-        text_block.next = null;
+        atom.next = null;
     }
 
-    if (text_block.dbg_info_prev) |prev| {
-        prev.dbg_info_next = text_block.dbg_info_next;
+    if (atom.dbg_info_prev) |prev| {
+        prev.dbg_info_next = atom.dbg_info_next;
 
-        // TODO the free list logic like we do for text blocks above
+        // TODO the free list logic like we do for atoms above
     } else {
-        text_block.dbg_info_prev = null;
+        atom.dbg_info_prev = null;
     }
 
-    if (text_block.dbg_info_next) |next| {
-        next.dbg_info_prev = text_block.dbg_info_prev;
+    if (atom.dbg_info_next) |next| {
+        next.dbg_info_prev = atom.dbg_info_prev;
     } else {
-        text_block.dbg_info_next = null;
+        atom.dbg_info_next = null;
     }
 }
 
-fn shrinkTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64) void {
+fn shrinkAtom(self: *MachO, atom: *Atom, new_block_size: u64, match: MatchingSection) void {
     _ = self;
-    _ = text_block;
+    _ = atom;
     _ = new_block_size;
+    _ = match;
     // TODO check the new capacity, and if it crosses the size threshold into a big enough
     // capacity, insert a free list node for it.
 }
 
-fn growTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 {
-    const sym = self.locals.items[text_block.local_sym_index];
+fn growAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, match: MatchingSection) !u64 {
+    const sym = self.locals.items[atom.local_sym_index];
     const align_ok = mem.alignBackwardGeneric(u64, sym.n_value, alignment) == sym.n_value;
-    const need_realloc = !align_ok or new_block_size > text_block.capacity(self.*);
+    const need_realloc = !align_ok or new_atom_size > atom.capacity(self.*);
     if (!need_realloc) return sym.n_value;
-    return self.allocateTextBlock(text_block, new_block_size, alignment);
+    return self.allocateAtom(atom, new_atom_size, alignment, match);
 }
 
 pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {
@@ -3112,7 +3052,7 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv
             // in a different, smarter, more automatic way somewhere else, in a more centralised
             // way than this.
             // If we don't clear the buffers here, we are up for some nasty surprises when
-            // this TextBlock is reused later on and was not freed by freeTextBlock().
+            // this atom is reused later on and was not freed by freeAtom().
             decl.link.macho.code.clearAndFree(self.base.allocator);
             try decl.link.macho.code.appendSlice(self.base.allocator, code_buffer.items);
         },
@@ -3202,7 +3142,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
                 // in a different, smarter, more automatic way somewhere else, in a more centralised
                 // way than this.
                 // If we don't clear the buffers here, we are up for some nasty surprises when
-                // this TextBlock is reused later on and was not freed by freeTextBlock().
+                // this atom is reused later on and was not freed by freeAtom().
                 decl.link.macho.code.clearAndFree(self.base.allocator);
                 try decl.link.macho.code.appendSlice(self.base.allocator, code_buffer.items);
                 break :blk decl.link.macho.code.items;
@@ -3231,7 +3171,10 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64
         const capacity = decl.link.macho.capacity(self.*);
         const need_realloc = code_len > capacity or !mem.isAlignedGeneric(u64, symbol.n_value, required_alignment);
         if (need_realloc) {
-            const vaddr = try self.growTextBlock(&decl.link.macho, code_len, required_alignment);
+            const vaddr = try self.growAtom(&decl.link.macho, code_len, required_alignment, .{
+                .seg = self.text_segment_cmd_index.?,
+                .sect = self.text_section_index.?,
+            });
 
             log.debug("growing {s} and moving from 0x{x} to 0x{x}", .{ decl.name, symbol.n_value, vaddr });
 
@@ -3241,15 +3184,24 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64
                     .where = .local,
                     .where_index = decl.link.macho.local_sym_index,
                 }) orelse unreachable;
-                _ = try self.allocateAtom(got_atom, .{
+                const got_sym = &self.locals.items[got_atom.local_sym_index];
+                const got_vaddr = try self.allocateAtom(got_atom, @sizeOf(u64), 8, .{
                     .seg = self.data_const_segment_cmd_index.?,
                     .sect = self.got_section_index.?,
                 });
+                got_sym.n_value = got_vaddr;
+                got_sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(.{
+                    .seg = self.data_const_segment_cmd_index.?,
+                    .sect = self.got_section_index.?,
+                }).? + 1);
             }
 
             symbol.n_value = vaddr;
         } else if (code_len < decl.link.macho.size) {
-            self.shrinkTextBlock(&decl.link.macho, code_len);
+            self.shrinkAtom(&decl.link.macho, code_len, .{
+                .seg = self.text_segment_cmd_index.?,
+                .sect = self.text_section_index.?,
+            });
         }
         decl.link.macho.size = code_len;
 
@@ -3265,11 +3217,17 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64
         defer self.base.allocator.free(decl_name);
 
         const name_str_index = try self.makeString(decl_name);
-        const addr = try self.allocateTextBlock(&decl.link.macho, code_len, required_alignment);
+        const addr = try self.allocateAtom(&decl.link.macho, code_len, required_alignment, .{
+            .seg = self.text_segment_cmd_index.?,
+            .sect = self.text_section_index.?,
+        });
 
-        log.debug("allocated text block for {s} at 0x{x}", .{ decl_name, addr });
+        log.debug("allocated atom for {s} at 0x{x}", .{ decl_name, addr });
 
-        errdefer self.freeTextBlock(&decl.link.macho);
+        errdefer self.freeAtom(&decl.link.macho, .{
+            .seg = self.text_segment_cmd_index.?,
+            .sect = self.text_section_index.?,
+        });
 
         symbol.* = .{
             .n_strx = name_str_index,
@@ -3282,10 +3240,16 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64
             .where = .local,
             .where_index = decl.link.macho.local_sym_index,
         }) orelse unreachable;
-        _ = try self.allocateAtom(got_atom, .{
+        const got_sym = &self.locals.items[got_atom.local_sym_index];
+        const vaddr = try self.allocateAtom(got_atom, @sizeOf(u64), 8, .{
             .seg = self.data_const_segment_cmd_index.?,
             .sect = self.got_section_index.?,
         });
+        got_sym.n_value = vaddr;
+        got_sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(.{
+            .seg = self.data_const_segment_cmd_index.?,
+            .sect = self.got_section_index.?,
+        }).? + 1);
     }
 
     return symbol;
@@ -3402,7 +3366,10 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {
     log.debug("freeDecl {*}", .{decl});
     _ = self.decls.swapRemove(decl);
     // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
-    self.freeTextBlock(&decl.link.macho);
+    self.freeAtom(&decl.link.macho, .{
+        .seg = self.text_segment_cmd_index.?,
+        .sect = self.text_section_index.?,
+    });
     if (decl.link.macho.local_sym_index != 0) {
         self.locals_free_list.append(self.base.allocator, decl.link.macho.local_sym_index) catch {};
 
@@ -3412,7 +3379,7 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {
         decl.link.macho.local_sym_index = 0;
     }
     if (self.d_sym) |*ds| {
-        // TODO make this logic match freeTextBlock. Maybe abstract the logic
+        // TODO make this logic match freeAtom. Maybe abstract the logic
         // out since the same thing is desired for both.
         _ = ds.dbg_line_fn_free_list.remove(&decl.fn_link.macho);
         if (decl.fn_link.macho.prev) |prev| {
@@ -3947,7 +3914,7 @@ fn allocateSection(
         .sect = index,
     };
     _ = try self.section_ordinals.getOrPut(self.base.allocator, match);
-    try self.block_free_lists.putNoClobber(self.base.allocator, match, .{});
+    try self.atom_free_lists.putNoClobber(self.base.allocator, match, .{});
 
     self.load_commands_dirty = true;
     self.sections_order_dirty = true;
@@ -4113,106 +4080,105 @@ fn getSectionMaxAlignment(self: *MachO, segment_id: u16, start_sect_id: u16) !u3
     return max_alignment;
 }
 
-fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 {
-    const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
-    const text_section = &text_segment.sections.items[self.text_section_index.?];
-    const match = MatchingSection{
-        .seg = self.text_segment_cmd_index.?,
-        .sect = self.text_section_index.?,
-    };
-    var text_block_free_list = self.block_free_lists.get(match).?;
-    const new_block_ideal_capacity = padToIdeal(new_block_size);
+fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, match: MatchingSection) !u64 {
+    const seg = &self.load_commands.items[match.seg].Segment;
+    const sect = &seg.sections.items[match.sect];
+    var free_list = self.atom_free_lists.get(match).?;
+    const needs_padding = match.seg == self.text_segment_cmd_index.? and match.sect == self.text_section_index.?;
+    const new_atom_ideal_capacity = if (needs_padding) padToIdeal(new_atom_size) else new_atom_size;
 
-    // We use these to indicate our intention to update metadata, placing the new block,
+    // We use these to indicate our intention to update metadata, placing the new atom,
     // and possibly removing a free list node.
     // It would be simpler to do it inside the for loop below, but that would cause a
     // problem if an error was returned later in the function. So this action
     // is actually carried out at the end of the function, when errors are no longer possible.
-    var block_placement: ?*TextBlock = null;
+    var atom_placement: ?*Atom = null;
     var free_list_removal: ?usize = null;
 
     // First we look for an appropriately sized free list node.
     // The list is unordered. We'll just take the first thing that works.
     var vaddr = blk: {
         var i: usize = 0;
-        while (i < text_block_free_list.items.len) {
-            const big_block = text_block_free_list.items[i];
-            // We now have a pointer to a live text block that has too much capacity.
-            // Is it enough that we could fit this new text block?
-            const sym = self.locals.items[big_block.local_sym_index];
-            const capacity = big_block.capacity(self.*);
-            const ideal_capacity = padToIdeal(capacity);
+        while (i < free_list.items.len) {
+            const big_atom = free_list.items[i];
+            // We now have a pointer to a live atom that has too much capacity.
+            // Is it enough that we could fit this new atom?
+            const sym = self.locals.items[big_atom.local_sym_index];
+            const capacity = big_atom.capacity(self.*);
+            const ideal_capacity = if (needs_padding) padToIdeal(capacity) else capacity;
             const ideal_capacity_end_vaddr = sym.n_value + ideal_capacity;
             const capacity_end_vaddr = sym.n_value + capacity;
-            const new_start_vaddr_unaligned = capacity_end_vaddr - new_block_ideal_capacity;
+            const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity;
             const new_start_vaddr = mem.alignBackwardGeneric(u64, new_start_vaddr_unaligned, alignment);
             if (new_start_vaddr < ideal_capacity_end_vaddr) {
                 // Additional bookkeeping here to notice if this free list node
-                // should be deleted because the block that it points to has grown to take up
+                // should be deleted because the atom that it points to has grown to take up
                 // more of the extra capacity.
-                if (!big_block.freeListEligible(self.*)) {
-                    const bl = text_block_free_list.swapRemove(i);
+                if (!big_atom.freeListEligible(self.*)) {
+                    const bl = free_list.swapRemove(i);
                     bl.deinit(self.base.allocator);
                 } else {
                     i += 1;
                 }
                 continue;
             }
-            // At this point we know that we will place the new block here. But the
+            // At this point we know that we will place the new atom here. But the
             // remaining question is whether there is still yet enough capacity left
             // over for there to still be a free list node.
             const remaining_capacity = new_start_vaddr - ideal_capacity_end_vaddr;
             const keep_free_list_node = remaining_capacity >= min_text_capacity;
 
             // Set up the metadata to be updated, after errors are no longer possible.
-            block_placement = big_block;
+            atom_placement = big_atom;
             if (!keep_free_list_node) {
                 free_list_removal = i;
             }
             break :blk new_start_vaddr;
-        } else if (self.blocks.get(match)) |last| {
+        } else if (self.atoms.get(match)) |last| {
             const last_symbol = self.locals.items[last.local_sym_index];
-            // TODO We should pad out the excess capacity with NOPs. For executables,
-            // no padding seems to be OK, but it will probably not be for objects.
-            const ideal_capacity = padToIdeal(last.size);
+            const ideal_capacity = if (needs_padding) padToIdeal(last.size) else last.size;
             const ideal_capacity_end_vaddr = last_symbol.n_value + ideal_capacity;
             const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment);
-            block_placement = last;
+            atom_placement = last;
             break :blk new_start_vaddr;
         } else {
-            break :blk text_section.addr;
+            break :blk mem.alignForwardGeneric(u64, sect.addr, alignment);
         }
     };
 
-    const expand_text_section = block_placement == null or block_placement.?.next == null;
-    if (expand_text_section) {
-        const needed_size = @intCast(u32, (vaddr + new_block_size) - text_section.addr);
+    const expand_section = atom_placement == null or atom_placement.?.next == null;
+    if (expand_section) {
+        const needed_size = @intCast(u32, (vaddr + new_atom_size) - sect.addr);
         try self.growSection(match, needed_size);
-        _ = try self.blocks.put(self.base.allocator, match, text_block);
-        text_section.size = needed_size;
+        _ = try self.atoms.put(self.base.allocator, match, atom);
+        sect.size = needed_size;
         self.load_commands_dirty = true;
     }
     const align_pow = @intCast(u32, math.log2(alignment));
-    text_section.@"align" = math.max(text_section.@"align", align_pow);
-    text_block.size = new_block_size;
+    if (sect.@"align" < align_pow) {
+        sect.@"align" = align_pow;
+        self.load_commands_dirty = true;
+    }
+    atom.size = new_atom_size;
+    atom.alignment = align_pow;
 
-    if (text_block.prev) |prev| {
-        prev.next = text_block.next;
+    if (atom.prev) |prev| {
+        prev.next = atom.next;
     }
-    if (text_block.next) |next| {
-        next.prev = text_block.prev;
+    if (atom.next) |next| {
+        next.prev = atom.prev;
     }
 
-    if (block_placement) |big_block| {
-        text_block.prev = big_block;
-        text_block.next = big_block.next;
-        big_block.next = text_block;
+    if (atom_placement) |big_atom| {
+        atom.prev = big_atom;
+        atom.next = big_atom.next;
+        big_atom.next = atom;
     } else {
-        text_block.prev = null;
-        text_block.next = null;
+        atom.prev = null;
+        atom.next = null;
     }
     if (free_list_removal) |i| {
-        _ = text_block_free_list.swapRemove(i);
+        _ = free_list.swapRemove(i);
     }
 
     return vaddr;
@@ -4319,10 +4285,10 @@ fn writeDyldInfoData(self: *MachO) !void {
     defer lazy_bind_pointers.deinit();
 
     {
-        var it = self.blocks.iterator();
+        var it = self.atoms.iterator();
         while (it.next()) |entry| {
             const match = entry.key_ptr.*;
-            var atom: *TextBlock = entry.value_ptr.*;
+            var atom: *Atom = entry.value_ptr.*;
 
             if (match.seg == self.text_segment_cmd_index.?) continue; // __TEXT is non-writable
 
@@ -4444,7 +4410,7 @@ fn writeDyldInfoData(self: *MachO) !void {
 }
 
 fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
-    const last_atom = self.blocks.get(.{
+    const last_atom = self.atoms.get(.{
         .seg = self.text_segment_cmd_index.?,
         .sect = self.stub_helper_section_index.?,
     }) orelse return;
@@ -4538,25 +4504,25 @@ fn writeDices(self: *MachO) !void {
     var buf = std.ArrayList(u8).init(self.base.allocator);
     defer buf.deinit();
 
-    var block: *TextBlock = self.blocks.get(.{
+    var atom: *Atom = self.atoms.get(.{
         .seg = self.text_segment_cmd_index orelse return,
         .sect = self.text_section_index orelse return,
     }) orelse return;
 
-    while (block.prev) |prev| {
-        block = prev;
+    while (atom.prev) |prev| {
+        atom = prev;
     }
 
     const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
     const text_sect = text_seg.sections.items[self.text_section_index.?];
 
     while (true) {
-        if (block.dices.items.len > 0) {
-            const sym = self.locals.items[block.local_sym_index];
+        if (atom.dices.items.len > 0) {
+            const sym = self.locals.items[atom.local_sym_index];
             const base_off = try math.cast(u32, sym.n_value - text_sect.addr + text_sect.offset);
 
-            try buf.ensureUnusedCapacity(block.dices.items.len * @sizeOf(macho.data_in_code_entry));
-            for (block.dices.items) |dice| {
+            try buf.ensureUnusedCapacity(atom.dices.items.len * @sizeOf(macho.data_in_code_entry));
+            for (atom.dices.items) |dice| {
                 const rebased_dice = macho.data_in_code_entry{
                     .offset = base_off + dice.offset,
                     .length = dice.length,
@@ -4566,8 +4532,8 @@ fn writeDices(self: *MachO) !void {
             }
         }
 
-        if (block.next) |next| {
-            block = next;
+        if (atom.next) |next| {
+            atom = next;
         } else break;
     }