authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-09-11 01:18:37+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-09-11 02:03:25+02:00
log31dcb0dde71e7c6968a9ee902782783b139c4900
treeb832dbe9b676a6e248c8c09409749d7582218466
parent6e0c3950b8115e1e274214447763733b3d3055d6

macho: change all occurrences of TextBlock into Atom

and unify allocateAtom with allocateTextBlock.

1 files changed, 237 insertions(+), 271 deletions(-)

src/link/MachO.zig+237-271
...@@ -158,8 +158,8 @@ stub_preamble_sym_index: ?u32 = null,...@@ -158,8 +158,8 @@ stub_preamble_sym_index: ?u32 = null,
158strtab: std.ArrayListUnmanaged(u8) = .{},158strtab: std.ArrayListUnmanaged(u8) = .{},
159strtab_dir: std.HashMapUnmanaged(u32, u32, StringIndexContext, std.hash_map.default_max_load_percentage) = .{},159strtab_dir: std.HashMapUnmanaged(u32, u32, StringIndexContext, std.hash_map.default_max_load_percentage) = .{},
160160
161got_entries_map: std.AutoArrayHashMapUnmanaged(GotIndirectionKey, *TextBlock) = .{},161got_entries_map: std.AutoArrayHashMapUnmanaged(GotIndirectionKey, *Atom) = .{},
162stubs_map: std.AutoArrayHashMapUnmanaged(u32, *TextBlock) = .{},162stubs_map: std.AutoArrayHashMapUnmanaged(u32, *Atom) = .{},
163163
164error_flags: File.ErrorFlags = File.ErrorFlags{},164error_flags: File.ErrorFlags = File.ErrorFlags{},
165165
...@@ -171,12 +171,12 @@ has_stabs: bool = false,...@@ -171,12 +171,12 @@ has_stabs: bool = false,
171171
172section_ordinals: std.AutoArrayHashMapUnmanaged(MatchingSection, void) = .{},172section_ordinals: std.AutoArrayHashMapUnmanaged(MatchingSection, void) = .{},
173173
174/// A list of text blocks that have surplus capacity. This list can have false174/// A list of atoms that have surplus capacity. This list can have false
175/// positives, as functions grow and shrink over time, only sometimes being added175/// positives, as functions grow and shrink over time, only sometimes being added
176/// or removed from the freelist.176/// or removed from the freelist.
177///177///
178/// A text block has surplus capacity when its overcapacity value is greater than178/// An atom has surplus capacity when its overcapacity value is greater than
179/// padToIdeal(minimum_text_block_size). That is, when it has so179/// padToIdeal(minimum_atom_size). That is, when it has so
180/// much extra capacity, that we could fit a small new symbol in it, itself with180/// much extra capacity, that we could fit a small new symbol in it, itself with
181/// ideal_capacity or more.181/// ideal_capacity or more.
182///182///
...@@ -184,23 +184,23 @@ section_ordinals: std.AutoArrayHashMapUnmanaged(MatchingSection, void) = .{},...@@ -184,23 +184,23 @@ section_ordinals: std.AutoArrayHashMapUnmanaged(MatchingSection, void) = .{},
184///184///
185/// Overcapacity is measured by actual_capacity - ideal_capacity. Note that185/// Overcapacity is measured by actual_capacity - ideal_capacity. Note that
186/// overcapacity can be negative. A simple way to have negative overcapacity is to186/// overcapacity can be negative. A simple way to have negative overcapacity is to
187/// allocate a fresh text block, which will have ideal capacity, and then grow it187/// allocate a fresh atom, which will have ideal capacity, and then grow it
188/// by 1 byte. It will then have -1 overcapacity.188/// by 1 byte. It will then have -1 overcapacity.
189block_free_lists: std.AutoHashMapUnmanaged(MatchingSection, std.ArrayListUnmanaged(*TextBlock)) = .{},189atom_free_lists: std.AutoHashMapUnmanaged(MatchingSection, std.ArrayListUnmanaged(*Atom)) = .{},
190190
191/// Pointer to the last allocated text block191/// Pointer to the last allocated atom
192blocks: std.AutoHashMapUnmanaged(MatchingSection, *TextBlock) = .{},192atoms: std.AutoHashMapUnmanaged(MatchingSection, *Atom) = .{},
193193
194/// List of TextBlocks that are owned directly by the linker.194/// List of atoms that are owned directly by the linker.
195/// Currently these are only TextBlocks that are the result of linking195/// Currently these are only atoms that are the result of linking
196/// object files. TextBlock which take part in incremental linking are 196/// object files. Atoms which take part in incremental linking are
197/// at present owned by Module.Decl.197/// at present owned by Module.Decl.
198/// TODO consolidate this.198/// TODO consolidate this.
199managed_blocks: std.ArrayListUnmanaged(*TextBlock) = .{},199managed_atoms: std.ArrayListUnmanaged(*Atom) = .{},
200200
201/// Table of Decls that are currently alive.201/// Table of Decls that are currently alive.
202/// We store them here so that we can properly dispose of any allocated202/// We store them here so that we can properly dispose of any allocated
203/// memory within the TextBlock in the incremental linker.203/// memory within the atom in the incremental linker.
204/// TODO consolidate this.204/// TODO consolidate this.
205decls: std.AutoArrayHashMapUnmanaged(*Module.Decl, void) = .{},205decls: std.AutoArrayHashMapUnmanaged(*Module.Decl, void) = .{},
206206
...@@ -768,31 +768,8 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {...@@ -768,31 +768,8 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {
768 try self.addDataInCodeLC();768 try self.addDataInCodeLC();
769 try self.addCodeSignatureLC();769 try self.addCodeSignatureLC();
770770
771 try self.parseTextBlocks();771 try self.parseObjectsIntoAtoms();
772 try self.allocateGlobalSymbols();772 try self.allocateGlobalSymbols();
773 {
774 log.debug("locals:", .{});
775 for (self.locals.items) |sym| {
776 log.debug(" {s}: {}", .{ self.getString(sym.n_strx), sym });
777 }
778 log.debug("globals:", .{});
779 for (self.globals.items) |sym| {
780 log.debug(" {s}: {}", .{ self.getString(sym.n_strx), sym });
781 }
782 log.debug("undefs:", .{});
783 for (self.undefs.items) |sym| {
784 log.debug(" {s}: {}", .{ self.getString(sym.n_strx), sym });
785 }
786 log.debug("unresolved:", .{});
787 for (self.unresolved.keys()) |key| {
788 log.debug(" {d} => {s}", .{ key, self.unresolved.get(key).? });
789 }
790 log.debug("resolved:", .{});
791 var it = self.symbol_resolver.iterator();
792 while (it.next()) |entry| {
793 log.debug(" {s} => {}", .{ self.getString(entry.key_ptr.*), entry.value_ptr.* });
794 }
795 }
796 try self.writeAtoms();773 try self.writeAtoms();
797774
798 if (self.bss_section_index) |idx| {775 if (self.bss_section_index) |idx| {
...@@ -1637,87 +1614,24 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1637,87 +1614,24 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1637 return res;1614 return res;
1638}1615}
16391616
1640pub fn createEmptyAtom(self: *MachO, local_sym_index: u32, size: u64, alignment: u32) !*TextBlock {1617pub fn createEmptyAtom(self: *MachO, local_sym_index: u32, size: u64, alignment: u32) !*Atom {
1641 const code = try self.base.allocator.alloc(u8, size);1618 const code = try self.base.allocator.alloc(u8, size);
1642 defer self.base.allocator.free(code);1619 defer self.base.allocator.free(code);
1643 mem.set(u8, code, 0);1620 mem.set(u8, code, 0);
16441621
1645 const atom = try self.base.allocator.create(TextBlock);1622 const atom = try self.base.allocator.create(Atom);
1646 errdefer self.base.allocator.destroy(atom);1623 errdefer self.base.allocator.destroy(atom);
1647 atom.* = TextBlock.empty;1624 atom.* = Atom.empty;
1648 atom.local_sym_index = local_sym_index;1625 atom.local_sym_index = local_sym_index;
1649 atom.size = size;1626 atom.size = size;
1650 atom.alignment = alignment;1627 atom.alignment = alignment;
1651 try atom.code.appendSlice(self.base.allocator, code);1628 try atom.code.appendSlice(self.base.allocator, code);
1652 try self.managed_blocks.append(self.base.allocator, atom);1629 try self.managed_atoms.append(self.base.allocator, atom);
16531630
1654 return atom;1631 return atom;
1655}1632}
16561633
1657pub fn allocateAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !u64 {1634pub fn writeAtom(self: *MachO, atom: *Atom, match: MatchingSection) !void {
1658 const seg = &self.load_commands.items[match.seg].Segment;
1659 const sect = &seg.sections.items[match.sect];
1660
1661 const sym = &self.locals.items[atom.local_sym_index];
1662 const needs_padding = match.seg == self.text_segment_cmd_index.? and match.sect == self.text_section_index.?;
1663
1664 var atom_placement: ?*TextBlock = null;
1665 const atom_alignment = try math.powi(u32, 2, atom.alignment);
1666
1667 // TODO converge with `allocateTextBlock` and handle free list
1668 var vaddr = if (self.blocks.get(match)) |last| blk: {
1669 const last_atom_sym = self.locals.items[last.local_sym_index];
1670 const ideal_capacity = if (needs_padding) padToIdeal(last.size) else last.size;
1671 const ideal_capacity_end_vaddr = last_atom_sym.n_value + ideal_capacity;
1672 const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, atom_alignment);
1673 atom_placement = last;
1674 break :blk new_start_vaddr;
1675 } else mem.alignForwardGeneric(u64, sect.addr, atom_alignment);
1676
1677 // TODO what if the section which was preallocated is not aligned to the maximum (section) alignment?
1678 // Should we move the section?
1679
1680 log.debug("allocating atom for symbol {s} at address 0x{x}", .{ self.getString(sym.n_strx), vaddr });
1681
1682 const expand_section = atom_placement == null or atom_placement.?.next == null;
1683 if (expand_section) {
1684 const needed_size = @intCast(u32, (vaddr + atom.size) - sect.addr);
1685 try self.growSection(match, needed_size);
1686 sect.size = needed_size;
1687 self.load_commands_dirty = true;
1688 }
1689 sect.@"align" = math.max(sect.@"align", atom.alignment);
1690
1691 const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
1692 sym.n_value = vaddr;
1693 sym.n_sect = n_sect;
1694
1695 // Update each alias (if any)
1696 for (atom.aliases.items) |index| {
1697 const alias_sym = &self.locals.items[index];
1698 alias_sym.n_value = vaddr;
1699 alias_sym.n_sect = n_sect;
1700 }
1701
1702 // Update each symbol contained within the TextBlock
1703 for (atom.contained.items) |sym_at_off| {
1704 const contained_sym = &self.locals.items[sym_at_off.local_sym_index];
1705 contained_sym.n_value = vaddr + sym_at_off.offset;
1706 contained_sym.n_sect = n_sect;
1707 }
1708
1709 if (self.blocks.getPtr(match)) |last| {
1710 last.*.next = atom;
1711 atom.prev = last.*;
1712 last.* = atom;
1713 } else {
1714 try self.blocks.putNoClobber(self.base.allocator, match, atom);
1715 }
1716
1717 return vaddr;
1718}
1719
1720pub fn writeAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !void {
1721 const seg = self.load_commands.items[match.seg].Segment;1635 const seg = self.load_commands.items[match.seg].Segment;
1722 const sect = seg.sections.items[match.sect];1636 const sect = seg.sections.items[match.sect];
1723 const sym = self.locals.items[atom.local_sym_index];1637 const sym = self.locals.items[atom.local_sym_index];
...@@ -1728,7 +1642,7 @@ pub fn writeAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !void {...@@ -1728,7 +1642,7 @@ pub fn writeAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !void {
1728}1642}
17291643
1730fn allocateLocalSymbols(self: *MachO, match: MatchingSection, offset: i64) !void {1644fn allocateLocalSymbols(self: *MachO, match: MatchingSection, offset: i64) !void {
1731 var atom = self.blocks.get(match) orelse return;1645 var atom = self.atoms.get(match) orelse return;
17321646
1733 while (true) {1647 while (true) {
1734 const atom_sym = &self.locals.items[atom.local_sym_index];1648 const atom_sym = &self.locals.items[atom.local_sym_index];
...@@ -1751,8 +1665,6 @@ fn allocateLocalSymbols(self: *MachO, match: MatchingSection, offset: i64) !void...@@ -1751,8 +1665,6 @@ fn allocateLocalSymbols(self: *MachO, match: MatchingSection, offset: i64) !void
1751}1665}
17521666
1753fn allocateGlobalSymbols(self: *MachO) !void {1667fn allocateGlobalSymbols(self: *MachO) !void {
1754 // TODO should we do this in `allocateAtom` (or similar)? Then, we would need to
1755 // store the link atom -> globals somewhere.
1756 var sym_it = self.symbol_resolver.valueIterator();1668 var sym_it = self.symbol_resolver.valueIterator();
1757 while (sym_it.next()) |resolv| {1669 while (sym_it.next()) |resolv| {
1758 if (resolv.where != .global) continue;1670 if (resolv.where != .global) continue;
...@@ -1770,12 +1682,14 @@ fn writeAtoms(self: *MachO) !void {...@@ -1770,12 +1682,14 @@ fn writeAtoms(self: *MachO) !void {
1770 defer buffer.deinit();1682 defer buffer.deinit();
1771 var file_offset: ?u64 = null;1683 var file_offset: ?u64 = null;
17721684
1773 var it = self.blocks.iterator();1685 var it = self.atoms.iterator();
1774 while (it.next()) |entry| {1686 while (it.next()) |entry| {
1775 const match = entry.key_ptr.*;1687 const match = entry.key_ptr.*;
1776 const seg = self.load_commands.items[match.seg].Segment;1688 const seg = self.load_commands.items[match.seg].Segment;
1777 const sect = seg.sections.items[match.sect];1689 const sect = seg.sections.items[match.sect];
1778 var atom: *TextBlock = entry.value_ptr.*;1690 var atom: *Atom = entry.value_ptr.*;
1691
1692 log.debug("writing atoms in {s},{s}", .{ commands.segmentName(sect), commands.sectionName(sect) });
17791693
1780 while (atom.prev) |prev| {1694 while (atom.prev) |prev| {
1781 atom = prev;1695 atom = prev;
...@@ -1789,6 +1703,8 @@ fn writeAtoms(self: *MachO) !void {...@@ -1789,6 +1703,8 @@ fn writeAtoms(self: *MachO) !void {
1789 break :blk next_sym.n_value - (atom_sym.n_value + atom.size);1703 break :blk next_sym.n_value - (atom_sym.n_value + atom.size);
1790 } else 0;1704 } else 0;
17911705
1706 log.debug(" (adding atom {s} to buffer: {})", .{ self.getString(atom_sym.n_strx), atom_sym });
1707
1792 try atom.resolveRelocs(self);1708 try atom.resolveRelocs(self);
1793 try buffer.appendSlice(atom.code.items);1709 try buffer.appendSlice(atom.code.items);
1794 try buffer.ensureUnusedCapacity(padding_size);1710 try buffer.ensureUnusedCapacity(padding_size);
...@@ -1824,7 +1740,7 @@ fn writeAtoms(self: *MachO) !void {...@@ -1824,7 +1740,7 @@ fn writeAtoms(self: *MachO) !void {
1824 }1740 }
1825}1741}
18261742
1827pub fn createGotAtom(self: *MachO, key: GotIndirectionKey) !*TextBlock {1743pub fn createGotAtom(self: *MachO, key: GotIndirectionKey) !*Atom {
1828 const local_sym_index = @intCast(u32, self.locals.items.len);1744 const local_sym_index = @intCast(u32, self.locals.items.len);
1829 try self.locals.append(self.base.allocator, .{1745 try self.locals.append(self.base.allocator, .{
1830 .n_strx = try self.makeString("l_zld_got_entry"),1746 .n_strx = try self.makeString("l_zld_got_entry"),
...@@ -1860,7 +1776,7 @@ pub fn createGotAtom(self: *MachO, key: GotIndirectionKey) !*TextBlock {...@@ -1860,7 +1776,7 @@ pub fn createGotAtom(self: *MachO, key: GotIndirectionKey) !*TextBlock {
1860 return atom;1776 return atom;
1861}1777}
18621778
1863fn createDyldPrivateAtom(self: *MachO) !*TextBlock {1779fn createDyldPrivateAtom(self: *MachO) !*Atom {
1864 const local_sym_index = @intCast(u32, self.locals.items.len);1780 const local_sym_index = @intCast(u32, self.locals.items.len);
1865 try self.locals.append(self.base.allocator, .{1781 try self.locals.append(self.base.allocator, .{
1866 .n_strx = try self.makeString("l_zld_dyld_private"),1782 .n_strx = try self.makeString("l_zld_dyld_private"),
...@@ -1873,7 +1789,7 @@ fn createDyldPrivateAtom(self: *MachO) !*TextBlock {...@@ -1873,7 +1789,7 @@ fn createDyldPrivateAtom(self: *MachO) !*TextBlock {
1873 return self.createEmptyAtom(local_sym_index, @sizeOf(u64), 3);1789 return self.createEmptyAtom(local_sym_index, @sizeOf(u64), 3);
1874}1790}
18751791
1876fn createStubHelperPreambleAtom(self: *MachO) !*TextBlock {1792fn createStubHelperPreambleAtom(self: *MachO) !*Atom {
1877 const arch = self.base.options.target.cpu.arch;1793 const arch = self.base.options.target.cpu.arch;
1878 const size: u64 = switch (arch) {1794 const size: u64 = switch (arch) {
1879 .x86_64 => 15,1795 .x86_64 => 15,
...@@ -2006,7 +1922,7 @@ fn createStubHelperPreambleAtom(self: *MachO) !*TextBlock {...@@ -2006,7 +1922,7 @@ fn createStubHelperPreambleAtom(self: *MachO) !*TextBlock {
2006 return atom;1922 return atom;
2007}1923}
20081924
2009pub fn createStubHelperAtom(self: *MachO) !*TextBlock {1925pub fn createStubHelperAtom(self: *MachO) !*Atom {
2010 const arch = self.base.options.target.cpu.arch;1926 const arch = self.base.options.target.cpu.arch;
2011 const stub_size: u4 = switch (arch) {1927 const stub_size: u4 = switch (arch) {
2012 .x86_64 => 10,1928 .x86_64 => 10,
...@@ -2072,7 +1988,7 @@ pub fn createStubHelperAtom(self: *MachO) !*TextBlock {...@@ -2072,7 +1988,7 @@ pub fn createStubHelperAtom(self: *MachO) !*TextBlock {
2072 return atom;1988 return atom;
2073}1989}
20741990
2075pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, lazy_binding_sym_index: u32) !*TextBlock {1991pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, lazy_binding_sym_index: u32) !*Atom {
2076 const local_sym_index = @intCast(u32, self.locals.items.len);1992 const local_sym_index = @intCast(u32, self.locals.items.len);
2077 try self.locals.append(self.base.allocator, .{1993 try self.locals.append(self.base.allocator, .{
2078 .n_strx = try self.makeString("l_zld_lazy_ptr"),1994 .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...@@ -2102,7 +2018,7 @@ pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, lazy_binding_sym
2102 return atom;2018 return atom;
2103}2019}
21042020
2105pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*TextBlock {2021pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {
2106 const arch = self.base.options.target.cpu.arch;2022 const arch = self.base.options.target.cpu.arch;
2107 const alignment: u2 = switch (arch) {2023 const alignment: u2 = switch (arch) {
2108 .x86_64 => 0,2024 .x86_64 => 0,
...@@ -2273,14 +2189,6 @@ fn resolveSymbolsInObject(...@@ -2273,14 +2189,6 @@ fn resolveSymbolsInObject(
2273 continue;2189 continue;
2274 },2190 },
2275 .undef => {2191 .undef => {
2276 // const undef = &self.undefs.items[resolv.where_index];
2277 // undef.* = .{
2278 // .n_strx = 0,
2279 // .n_type = macho.N_UNDF,
2280 // .n_sect = 0,
2281 // .n_desc = 0,
2282 // .n_value = 0,
2283 // };
2284 _ = self.unresolved.fetchSwapRemove(resolv.where_index);2192 _ = self.unresolved.fetchSwapRemove(resolv.where_index);
2285 },2193 },
2286 }2194 }
...@@ -2437,23 +2345,36 @@ fn resolveSymbols(self: *MachO) !void {...@@ -2437,23 +2345,36 @@ fn resolveSymbols(self: *MachO) !void {
2437 resolv.local_sym_index = local_sym_index;2345 resolv.local_sym_index = local_sym_index;
24382346
2439 const atom = try self.createEmptyAtom(local_sym_index, size, alignment);2347 const atom = try self.createEmptyAtom(local_sym_index, size, alignment);
2440 _ = try self.allocateAtom(atom, match);2348 const alignment_pow_2 = try math.powi(u32, 2, alignment);
2349 const vaddr = try self.allocateAtom(atom, size, alignment_pow_2, match);
2350 sym.n_value = vaddr;
2441 }2351 }
24422352
2443 try self.resolveDyldStubBinder();2353 try self.resolveDyldStubBinder();
2444 {2354 {
2445 const atom = try self.createDyldPrivateAtom();2355 const match = MatchingSection{
2446 _ = try self.allocateAtom(atom, .{
2447 .seg = self.data_segment_cmd_index.?,2356 .seg = self.data_segment_cmd_index.?,
2448 .sect = self.data_section_index.?,2357 .sect = self.data_section_index.?,
2449 });2358 };
2359 const atom = try self.createDyldPrivateAtom();
2360 const sym = &self.locals.items[atom.local_sym_index];
2361 const vaddr = try self.allocateAtom(atom, @sizeOf(u64), 8, match);
2362 sym.n_value = vaddr;
2363 sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
2364 log.debug("allocated {s} atom at 0x{x}", .{ self.getString(sym.n_strx), vaddr });
2450 }2365 }
2451 {2366 {
2452 const atom = try self.createStubHelperPreambleAtom();2367 const match = MatchingSection{
2453 _ = try self.allocateAtom(atom, .{
2454 .seg = self.text_segment_cmd_index.?,2368 .seg = self.text_segment_cmd_index.?,
2455 .sect = self.stub_helper_section_index.?,2369 .sect = self.stub_helper_section_index.?,
2456 });2370 };
2371 const atom = try self.createStubHelperPreambleAtom();
2372 const sym = &self.locals.items[atom.local_sym_index];
2373 const alignment = try math.powi(u32, 2, atom.alignment);
2374 const vaddr = try self.allocateAtom(atom, atom.size, alignment, match);
2375 sym.n_value = vaddr;
2376 sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
2377 log.debug("allocated {s} atom at 0x{x}", .{ self.getString(sym.n_strx), vaddr });
2457 }2378 }
24582379
2459 // Third pass, resolve symbols in dynamic libraries.2380 // Third pass, resolve symbols in dynamic libraries.
...@@ -2483,30 +2404,45 @@ fn resolveSymbols(self: *MachO) !void {...@@ -2483,30 +2404,45 @@ fn resolveSymbols(self: *MachO) !void {
2483 .stub => {2404 .stub => {
2484 if (self.stubs_map.contains(resolv.where_index)) break :outer_blk;2405 if (self.stubs_map.contains(resolv.where_index)) break :outer_blk;
2485 const stub_helper_atom = blk: {2406 const stub_helper_atom = blk: {
2486 const atom = try self.createStubHelperAtom();2407 const match = MatchingSection{
2487 _ = try self.allocateAtom(atom, .{
2488 .seg = self.text_segment_cmd_index.?,2408 .seg = self.text_segment_cmd_index.?,
2489 .sect = self.stub_helper_section_index.?,2409 .sect = self.stub_helper_section_index.?,
2490 });2410 };
2411 const atom = try self.createStubHelperAtom();
2412 const atom_sym = &self.locals.items[atom.local_sym_index];
2413 const alignment = try math.powi(u32, 2, atom.alignment);
2414 const vaddr = try self.allocateAtom(atom, atom.size, alignment, match);
2415 atom_sym.n_value = vaddr;
2416 atom_sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
2491 break :blk atom;2417 break :blk atom;
2492 };2418 };
2493 const laptr_atom = blk: {2419 const laptr_atom = blk: {
2420 const match = MatchingSection{
2421 .seg = self.data_segment_cmd_index.?,
2422 .sect = self.la_symbol_ptr_section_index.?,
2423 };
2494 const atom = try self.createLazyPointerAtom(2424 const atom = try self.createLazyPointerAtom(
2495 stub_helper_atom.local_sym_index,2425 stub_helper_atom.local_sym_index,
2496 resolv.where_index,2426 resolv.where_index,
2497 );2427 );
2498 _ = try self.allocateAtom(atom, .{2428 const atom_sym = &self.locals.items[atom.local_sym_index];
2499 .seg = self.data_segment_cmd_index.?,2429 const alignment = try math.powi(u32, 2, atom.alignment);
2500 .sect = self.la_symbol_ptr_section_index.?,2430 const vaddr = try self.allocateAtom(atom, atom.size, alignment, match);
2501 });2431 atom_sym.n_value = vaddr;
2432 atom_sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
2502 break :blk atom;2433 break :blk atom;
2503 };2434 };
2504 const stub_atom = blk: {2435 const stub_atom = blk: {
2505 const atom = try self.createStubAtom(laptr_atom.local_sym_index);2436 const match = MatchingSection{
2506 _ = try self.allocateAtom(atom, .{
2507 .seg = self.text_segment_cmd_index.?,2437 .seg = self.text_segment_cmd_index.?,
2508 .sect = self.stubs_section_index.?,2438 .sect = self.stubs_section_index.?,
2509 });2439 };
2440 const atom = try self.createStubAtom(laptr_atom.local_sym_index);
2441 const atom_sym = &self.locals.items[atom.local_sym_index];
2442 const alignment = try math.powi(u32, 2, atom.alignment);
2443 const vaddr = try self.allocateAtom(atom, atom.size, alignment, match);
2444 atom_sym.n_value = vaddr;
2445 atom_sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
2510 break :blk atom;2446 break :blk atom;
2511 };2447 };
2512 try self.stubs_map.putNoClobber(self.base.allocator, resolv.where_index, stub_atom);2448 try self.stubs_map.putNoClobber(self.base.allocator, resolv.where_index, stub_atom);
...@@ -2565,7 +2501,10 @@ fn resolveSymbols(self: *MachO) !void {...@@ -2565,7 +2501,10 @@ fn resolveSymbols(self: *MachO) !void {
2565 // TODO perhaps we should special-case special symbols? Create a separate2501 // TODO perhaps we should special-case special symbols? Create a separate
2566 // linked list of atoms?2502 // linked list of atoms?
2567 const atom = try self.createEmptyAtom(local_sym_index, 0, 0);2503 const atom = try self.createEmptyAtom(local_sym_index, 0, 0);
2568 _ = try self.allocateAtom(atom, match);2504 const sym = &self.locals.items[local_sym_index];
2505 const vaddr = try self.allocateAtom(atom, 0, 1, match);
2506 sym.n_value = vaddr;
2507 atom.dirty = false; // We don't really want to write it to file.
2569 }2508 }
25702509
2571 for (self.unresolved.keys()) |index| {2510 for (self.unresolved.keys()) |index| {
...@@ -2632,10 +2571,14 @@ fn resolveDyldStubBinder(self: *MachO) !void {...@@ -2632,10 +2571,14 @@ fn resolveDyldStubBinder(self: *MachO) !void {
2632 .seg = self.data_const_segment_cmd_index.?,2571 .seg = self.data_const_segment_cmd_index.?,
2633 .sect = self.got_section_index.?,2572 .sect = self.got_section_index.?,
2634 };2573 };
2635 _ = try self.allocateAtom(atom, match);2574 const atom_sym = &self.locals.items[atom.local_sym_index];
2575 const vaddr = try self.allocateAtom(atom, @sizeOf(u64), 8, match);
2576 atom_sym.n_value = vaddr;
2577 atom_sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
2578 log.debug("allocated {s} atom at 0x{x}", .{ self.getString(sym.n_strx), vaddr });
2636}2579}
26372580
2638fn parseTextBlocks(self: *MachO) !void {2581fn parseObjectsIntoAtoms(self: *MachO) !void {
2639 var parsed_atoms = Object.ParsedAtoms.init(self.base.allocator);2582 var parsed_atoms = Object.ParsedAtoms.init(self.base.allocator);
2640 defer parsed_atoms.deinit();2583 defer parsed_atoms.deinit();
26412584
...@@ -2710,7 +2653,7 @@ fn parseTextBlocks(self: *MachO) !void {...@@ -2710,7 +2653,7 @@ fn parseTextBlocks(self: *MachO) !void {
2710 metadata.alignment,2653 metadata.alignment,
2711 });2654 });
27122655
2713 const sect_size = if (self.blocks.get(match)) |last| blk: {2656 const sect_size = if (self.atoms.get(match)) |last| blk: {
2714 const last_atom_sym = self.locals.items[last.local_sym_index];2657 const last_atom_sym = self.locals.items[last.local_sym_index];
2715 break :blk last_atom_sym.n_value + last.size - sect.addr;2658 break :blk last_atom_sym.n_value + last.size - sect.addr;
2716 } else 0;2659 } else 0;
...@@ -2720,7 +2663,7 @@ fn parseTextBlocks(self: *MachO) !void {...@@ -2720,7 +2663,7 @@ fn parseTextBlocks(self: *MachO) !void {
2720 try self.growSection(match, needed_size);2663 try self.growSection(match, needed_size);
2721 sect.size = needed_size;2664 sect.size = needed_size;
27222665
2723 var base_vaddr = if (self.blocks.get(match)) |last| blk: {2666 var base_vaddr = if (self.atoms.get(match)) |last| blk: {
2724 const last_atom_sym = self.locals.items[last.local_sym_index];2667 const last_atom_sym = self.locals.items[last.local_sym_index];
2725 break :blk last_atom_sym.n_value + last.size;2668 break :blk last_atom_sym.n_value + last.size;
2726 } else sect.addr;2669 } else sect.addr;
...@@ -2750,7 +2693,7 @@ fn parseTextBlocks(self: *MachO) !void {...@@ -2750,7 +2693,7 @@ fn parseTextBlocks(self: *MachO) !void {
2750 alias_sym.n_sect = n_sect;2693 alias_sym.n_sect = n_sect;
2751 }2694 }
27522695
2753 // Update each symbol contained within the TextBlock2696 // Update each symbol contained within the atom
2754 for (atom.contained.items) |sym_at_off| {2697 for (atom.contained.items) |sym_at_off| {
2755 const contained_sym = &self.locals.items[sym_at_off.local_sym_index];2698 const contained_sym = &self.locals.items[sym_at_off.local_sym_index];
2756 contained_sym.n_value = base_vaddr + sym_at_off.offset;2699 contained_sym.n_value = base_vaddr + sym_at_off.offset;
...@@ -2764,13 +2707,13 @@ fn parseTextBlocks(self: *MachO) !void {...@@ -2764,13 +2707,13 @@ fn parseTextBlocks(self: *MachO) !void {
2764 } else break;2707 } else break;
2765 }2708 }
27662709
2767 if (self.blocks.getPtr(match)) |last| {2710 if (self.atoms.getPtr(match)) |last| {
2768 const first_atom = first_atoms.get(match).?;2711 const first_atom = first_atoms.get(match).?;
2769 last.*.next = first_atom;2712 last.*.next = first_atom;
2770 first_atom.prev = last.*;2713 first_atom.prev = last.*;
2771 last.* = first_atom;2714 last.* = first_atom;
2772 }2715 }
2773 _ = try self.blocks.put(self.base.allocator, match, parsed_atoms.get(match).?);2716 _ = try self.atoms.put(self.base.allocator, match, parsed_atoms.get(match).?);
2774 }2717 }
2775}2718}
27762719
...@@ -2905,18 +2848,18 @@ pub fn deinit(self: *MachO) void {...@@ -2905,18 +2848,18 @@ pub fn deinit(self: *MachO) void {
2905 }2848 }
2906 self.load_commands.deinit(self.base.allocator);2849 self.load_commands.deinit(self.base.allocator);
29072850
2908 for (self.managed_blocks.items) |block| {2851 for (self.managed_atoms.items) |atom| {
2909 block.deinit(self.base.allocator);2852 atom.deinit(self.base.allocator);
2910 self.base.allocator.destroy(block);2853 self.base.allocator.destroy(atom);
2911 }2854 }
2912 self.managed_blocks.deinit(self.base.allocator);2855 self.managed_atoms.deinit(self.base.allocator);
2913 self.blocks.deinit(self.base.allocator);2856 self.atoms.deinit(self.base.allocator);
2914 {2857 {
2915 var it = self.block_free_lists.valueIterator();2858 var it = self.atom_free_lists.valueIterator();
2916 while (it.next()) |free_list| {2859 while (it.next()) |free_list| {
2917 free_list.deinit(self.base.allocator);2860 free_list.deinit(self.base.allocator);
2918 }2861 }
2919 self.block_free_lists.deinit(self.base.allocator);2862 self.atom_free_lists.deinit(self.base.allocator);
2920 }2863 }
2921 for (self.decls.keys()) |decl| {2864 for (self.decls.keys()) |decl| {
2922 decl.link.macho.deinit(self.base.allocator);2865 decl.link.macho.deinit(self.base.allocator);
...@@ -2936,25 +2879,21 @@ pub fn closeFiles(self: MachO) void {...@@ -2936,25 +2879,21 @@ pub fn closeFiles(self: MachO) void {
2936 }2879 }
2937}2880}
29382881
2939fn freeTextBlock(self: *MachO, text_block: *TextBlock) void {2882fn freeAtom(self: *MachO, atom: *Atom, match: MatchingSection) void {
2940 log.debug("freeTextBlock {*}", .{text_block});2883 log.debug("freeAtom {*}", .{atom});
2941 text_block.deinit(self.base.allocator);2884 atom.deinit(self.base.allocator);
29422885
2943 const match = MatchingSection{2886 const free_list = self.atom_free_lists.getPtr(match).?;
2944 .seg = self.text_segment_cmd_index.?,
2945 .sect = self.text_section_index.?,
2946 };
2947 const text_block_free_list = self.block_free_lists.getPtr(match).?;
2948 var already_have_free_list_node = false;2887 var already_have_free_list_node = false;
2949 {2888 {
2950 var i: usize = 0;2889 var i: usize = 0;
2951 // TODO turn text_block_free_list into a hash map2890 // TODO turn free_list into a hash map
2952 while (i < text_block_free_list.items.len) {2891 while (i < free_list.items.len) {
2953 if (text_block_free_list.items[i] == text_block) {2892 if (free_list.items[i] == atom) {
2954 _ = text_block_free_list.swapRemove(i);2893 _ = free_list.swapRemove(i);
2955 continue;2894 continue;
2956 }2895 }
2957 if (text_block_free_list.items[i] == text_block.prev) {2896 if (free_list.items[i] == atom.prev) {
2958 already_have_free_list_node = true;2897 already_have_free_list_node = true;
2959 }2898 }
2960 i += 1;2899 i += 1;
...@@ -2962,72 +2901,73 @@ fn freeTextBlock(self: *MachO, text_block: *TextBlock) void {...@@ -2962,72 +2901,73 @@ fn freeTextBlock(self: *MachO, text_block: *TextBlock) void {
2962 }2901 }
2963 // TODO process free list for dbg info just like we do above for vaddrs2902 // TODO process free list for dbg info just like we do above for vaddrs
29642903
2965 if (self.blocks.getPtr(match)) |last_text_block| {2904 if (self.atoms.getPtr(match)) |last_atom| {
2966 if (last_text_block.* == text_block) {2905 if (last_atom.* == atom) {
2967 if (text_block.prev) |prev| {2906 if (atom.prev) |prev| {
2968 // TODO shrink the __text section size here2907 // TODO shrink the section size here
2969 last_text_block.* = prev;2908 last_atom.* = prev;
2970 }2909 }
2971 }2910 }
2972 }2911 }
29732912
2974 if (self.d_sym) |*ds| {2913 if (self.d_sym) |*ds| {
2975 if (ds.dbg_info_decl_first == text_block) {2914 if (ds.dbg_info_decl_first == atom) {
2976 ds.dbg_info_decl_first = text_block.dbg_info_next;2915 ds.dbg_info_decl_first = atom.dbg_info_next;
2977 }2916 }
2978 if (ds.dbg_info_decl_last == text_block) {2917 if (ds.dbg_info_decl_last == atom) {
2979 // TODO shrink the .debug_info section size here2918 // TODO shrink the .debug_info section size here
2980 ds.dbg_info_decl_last = text_block.dbg_info_prev;2919 ds.dbg_info_decl_last = atom.dbg_info_prev;
2981 }2920 }
2982 }2921 }
29832922
2984 if (text_block.prev) |prev| {2923 if (atom.prev) |prev| {
2985 prev.next = text_block.next;2924 prev.next = atom.next;
29862925
2987 if (!already_have_free_list_node and prev.freeListEligible(self.*)) {2926 if (!already_have_free_list_node and prev.freeListEligible(self.*)) {
2988 // The free list is heuristics, it doesn't have to be perfect, so we can ignore2927 // The free list is heuristics, it doesn't have to be perfect, so we can ignore
2989 // the OOM here.2928 // the OOM here.
2990 text_block_free_list.append(self.base.allocator, prev) catch {};2929 free_list.append(self.base.allocator, prev) catch {};
2991 }2930 }
2992 } else {2931 } else {
2993 text_block.prev = null;2932 atom.prev = null;
2994 }2933 }
29952934
2996 if (text_block.next) |next| {2935 if (atom.next) |next| {
2997 next.prev = text_block.prev;2936 next.prev = atom.prev;
2998 } else {2937 } else {
2999 text_block.next = null;2938 atom.next = null;
3000 }2939 }
30012940
3002 if (text_block.dbg_info_prev) |prev| {2941 if (atom.dbg_info_prev) |prev| {
3003 prev.dbg_info_next = text_block.dbg_info_next;2942 prev.dbg_info_next = atom.dbg_info_next;
30042943
3005 // TODO the free list logic like we do for text blocks above2944 // TODO the free list logic like we do for atoms above
3006 } else {2945 } else {
3007 text_block.dbg_info_prev = null;2946 atom.dbg_info_prev = null;
3008 }2947 }
30092948
3010 if (text_block.dbg_info_next) |next| {2949 if (atom.dbg_info_next) |next| {
3011 next.dbg_info_prev = text_block.dbg_info_prev;2950 next.dbg_info_prev = atom.dbg_info_prev;
3012 } else {2951 } else {
3013 text_block.dbg_info_next = null;2952 atom.dbg_info_next = null;
3014 }2953 }
3015}2954}
30162955
3017fn shrinkTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64) void {2956fn shrinkAtom(self: *MachO, atom: *Atom, new_block_size: u64, match: MatchingSection) void {
3018 _ = self;2957 _ = self;
3019 _ = text_block;2958 _ = atom;
3020 _ = new_block_size;2959 _ = new_block_size;
2960 _ = match;
3021 // TODO check the new capacity, and if it crosses the size threshold into a big enough2961 // TODO check the new capacity, and if it crosses the size threshold into a big enough
3022 // capacity, insert a free list node for it.2962 // capacity, insert a free list node for it.
3023}2963}
30242964
3025fn growTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 {2965fn growAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, match: MatchingSection) !u64 {
3026 const sym = self.locals.items[text_block.local_sym_index];2966 const sym = self.locals.items[atom.local_sym_index];
3027 const align_ok = mem.alignBackwardGeneric(u64, sym.n_value, alignment) == sym.n_value;2967 const align_ok = mem.alignBackwardGeneric(u64, sym.n_value, alignment) == sym.n_value;
3028 const need_realloc = !align_ok or new_block_size > text_block.capacity(self.*);2968 const need_realloc = !align_ok or new_atom_size > atom.capacity(self.*);
3029 if (!need_realloc) return sym.n_value;2969 if (!need_realloc) return sym.n_value;
3030 return self.allocateTextBlock(text_block, new_block_size, alignment);2970 return self.allocateAtom(atom, new_atom_size, alignment, match);
3031}2971}
30322972
3033pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {2973pub 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...@@ -3112,7 +3052,7 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv
3112 // in a different, smarter, more automatic way somewhere else, in a more centralised3052 // in a different, smarter, more automatic way somewhere else, in a more centralised
3113 // way than this.3053 // way than this.
3114 // If we don't clear the buffers here, we are up for some nasty surprises when3054 // If we don't clear the buffers here, we are up for some nasty surprises when
3115 // this TextBlock is reused later on and was not freed by freeTextBlock().3055 // this atom is reused later on and was not freed by freeAtom().
3116 decl.link.macho.code.clearAndFree(self.base.allocator);3056 decl.link.macho.code.clearAndFree(self.base.allocator);
3117 try decl.link.macho.code.appendSlice(self.base.allocator, code_buffer.items);3057 try decl.link.macho.code.appendSlice(self.base.allocator, code_buffer.items);
3118 },3058 },
...@@ -3202,7 +3142,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -3202,7 +3142,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
3202 // in a different, smarter, more automatic way somewhere else, in a more centralised3142 // in a different, smarter, more automatic way somewhere else, in a more centralised
3203 // way than this.3143 // way than this.
3204 // If we don't clear the buffers here, we are up for some nasty surprises when3144 // If we don't clear the buffers here, we are up for some nasty surprises when
3205 // this TextBlock is reused later on and was not freed by freeTextBlock().3145 // this atom is reused later on and was not freed by freeAtom().
3206 decl.link.macho.code.clearAndFree(self.base.allocator);3146 decl.link.macho.code.clearAndFree(self.base.allocator);
3207 try decl.link.macho.code.appendSlice(self.base.allocator, code_buffer.items);3147 try decl.link.macho.code.appendSlice(self.base.allocator, code_buffer.items);
3208 break :blk decl.link.macho.code.items;3148 break :blk decl.link.macho.code.items;
...@@ -3231,7 +3171,10 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64...@@ -3231,7 +3171,10 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64
3231 const capacity = decl.link.macho.capacity(self.*);3171 const capacity = decl.link.macho.capacity(self.*);
3232 const need_realloc = code_len > capacity or !mem.isAlignedGeneric(u64, symbol.n_value, required_alignment);3172 const need_realloc = code_len > capacity or !mem.isAlignedGeneric(u64, symbol.n_value, required_alignment);
3233 if (need_realloc) {3173 if (need_realloc) {
3234 const vaddr = try self.growTextBlock(&decl.link.macho, code_len, required_alignment);3174 const vaddr = try self.growAtom(&decl.link.macho, code_len, required_alignment, .{
3175 .seg = self.text_segment_cmd_index.?,
3176 .sect = self.text_section_index.?,
3177 });
32353178
3236 log.debug("growing {s} and moving from 0x{x} to 0x{x}", .{ decl.name, symbol.n_value, vaddr });3179 log.debug("growing {s} and moving from 0x{x} to 0x{x}", .{ decl.name, symbol.n_value, vaddr });
32373180
...@@ -3241,15 +3184,24 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64...@@ -3241,15 +3184,24 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64
3241 .where = .local,3184 .where = .local,
3242 .where_index = decl.link.macho.local_sym_index,3185 .where_index = decl.link.macho.local_sym_index,
3243 }) orelse unreachable;3186 }) orelse unreachable;
3244 _ = try self.allocateAtom(got_atom, .{3187 const got_sym = &self.locals.items[got_atom.local_sym_index];
3188 const got_vaddr = try self.allocateAtom(got_atom, @sizeOf(u64), 8, .{
3245 .seg = self.data_const_segment_cmd_index.?,3189 .seg = self.data_const_segment_cmd_index.?,
3246 .sect = self.got_section_index.?,3190 .sect = self.got_section_index.?,
3247 });3191 });
3192 got_sym.n_value = got_vaddr;
3193 got_sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(.{
3194 .seg = self.data_const_segment_cmd_index.?,
3195 .sect = self.got_section_index.?,
3196 }).? + 1);
3248 }3197 }
32493198
3250 symbol.n_value = vaddr;3199 symbol.n_value = vaddr;
3251 } else if (code_len < decl.link.macho.size) {3200 } else if (code_len < decl.link.macho.size) {
3252 self.shrinkTextBlock(&decl.link.macho, code_len);3201 self.shrinkAtom(&decl.link.macho, code_len, .{
3202 .seg = self.text_segment_cmd_index.?,
3203 .sect = self.text_section_index.?,
3204 });
3253 }3205 }
3254 decl.link.macho.size = code_len;3206 decl.link.macho.size = code_len;
32553207
...@@ -3265,11 +3217,17 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64...@@ -3265,11 +3217,17 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64
3265 defer self.base.allocator.free(decl_name);3217 defer self.base.allocator.free(decl_name);
32663218
3267 const name_str_index = try self.makeString(decl_name);3219 const name_str_index = try self.makeString(decl_name);
3268 const addr = try self.allocateTextBlock(&decl.link.macho, code_len, required_alignment);3220 const addr = try self.allocateAtom(&decl.link.macho, code_len, required_alignment, .{
3221 .seg = self.text_segment_cmd_index.?,
3222 .sect = self.text_section_index.?,
3223 });
32693224
3270 log.debug("allocated text block for {s} at 0x{x}", .{ decl_name, addr });3225 log.debug("allocated atom for {s} at 0x{x}", .{ decl_name, addr });
32713226
3272 errdefer self.freeTextBlock(&decl.link.macho);3227 errdefer self.freeAtom(&decl.link.macho, .{
3228 .seg = self.text_segment_cmd_index.?,
3229 .sect = self.text_section_index.?,
3230 });
32733231
3274 symbol.* = .{3232 symbol.* = .{
3275 .n_strx = name_str_index,3233 .n_strx = name_str_index,
...@@ -3282,10 +3240,16 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64...@@ -3282,10 +3240,16 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64
3282 .where = .local,3240 .where = .local,
3283 .where_index = decl.link.macho.local_sym_index,3241 .where_index = decl.link.macho.local_sym_index,
3284 }) orelse unreachable;3242 }) orelse unreachable;
3285 _ = try self.allocateAtom(got_atom, .{3243 const got_sym = &self.locals.items[got_atom.local_sym_index];
3244 const vaddr = try self.allocateAtom(got_atom, @sizeOf(u64), 8, .{
3286 .seg = self.data_const_segment_cmd_index.?,3245 .seg = self.data_const_segment_cmd_index.?,
3287 .sect = self.got_section_index.?,3246 .sect = self.got_section_index.?,
3288 });3247 });
3248 got_sym.n_value = vaddr;
3249 got_sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(.{
3250 .seg = self.data_const_segment_cmd_index.?,
3251 .sect = self.got_section_index.?,
3252 }).? + 1);
3289 }3253 }
32903254
3291 return symbol;3255 return symbol;
...@@ -3402,7 +3366,10 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {...@@ -3402,7 +3366,10 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {
3402 log.debug("freeDecl {*}", .{decl});3366 log.debug("freeDecl {*}", .{decl});
3403 _ = self.decls.swapRemove(decl);3367 _ = self.decls.swapRemove(decl);
3404 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.3368 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
3405 self.freeTextBlock(&decl.link.macho);3369 self.freeAtom(&decl.link.macho, .{
3370 .seg = self.text_segment_cmd_index.?,
3371 .sect = self.text_section_index.?,
3372 });
3406 if (decl.link.macho.local_sym_index != 0) {3373 if (decl.link.macho.local_sym_index != 0) {
3407 self.locals_free_list.append(self.base.allocator, decl.link.macho.local_sym_index) catch {};3374 self.locals_free_list.append(self.base.allocator, decl.link.macho.local_sym_index) catch {};
34083375
...@@ -3412,7 +3379,7 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {...@@ -3412,7 +3379,7 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {
3412 decl.link.macho.local_sym_index = 0;3379 decl.link.macho.local_sym_index = 0;
3413 }3380 }
3414 if (self.d_sym) |*ds| {3381 if (self.d_sym) |*ds| {
3415 // TODO make this logic match freeTextBlock. Maybe abstract the logic3382 // TODO make this logic match freeAtom. Maybe abstract the logic
3416 // out since the same thing is desired for both.3383 // out since the same thing is desired for both.
3417 _ = ds.dbg_line_fn_free_list.remove(&decl.fn_link.macho);3384 _ = ds.dbg_line_fn_free_list.remove(&decl.fn_link.macho);
3418 if (decl.fn_link.macho.prev) |prev| {3385 if (decl.fn_link.macho.prev) |prev| {
...@@ -3947,7 +3914,7 @@ fn allocateSection(...@@ -3947,7 +3914,7 @@ fn allocateSection(
3947 .sect = index,3914 .sect = index,
3948 };3915 };
3949 _ = try self.section_ordinals.getOrPut(self.base.allocator, match);3916 _ = try self.section_ordinals.getOrPut(self.base.allocator, match);
3950 try self.block_free_lists.putNoClobber(self.base.allocator, match, .{});3917 try self.atom_free_lists.putNoClobber(self.base.allocator, match, .{});
39513918
3952 self.load_commands_dirty = true;3919 self.load_commands_dirty = true;
3953 self.sections_order_dirty = true;3920 self.sections_order_dirty = true;
...@@ -4113,106 +4080,105 @@ fn getSectionMaxAlignment(self: *MachO, segment_id: u16, start_sect_id: u16) !u3...@@ -4113,106 +4080,105 @@ fn getSectionMaxAlignment(self: *MachO, segment_id: u16, start_sect_id: u16) !u3
4113 return max_alignment;4080 return max_alignment;
4114}4081}
41154082
4116fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 {4083fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, match: MatchingSection) !u64 {
4117 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;4084 const seg = &self.load_commands.items[match.seg].Segment;
4118 const text_section = &text_segment.sections.items[self.text_section_index.?];4085 const sect = &seg.sections.items[match.sect];
4119 const match = MatchingSection{4086 var free_list = self.atom_free_lists.get(match).?;
4120 .seg = self.text_segment_cmd_index.?,4087 const needs_padding = match.seg == self.text_segment_cmd_index.? and match.sect == self.text_section_index.?;
4121 .sect = self.text_section_index.?,4088 const new_atom_ideal_capacity = if (needs_padding) padToIdeal(new_atom_size) else new_atom_size;
4122 };
4123 var text_block_free_list = self.block_free_lists.get(match).?;
4124 const new_block_ideal_capacity = padToIdeal(new_block_size);
41254089
4126 // We use these to indicate our intention to update metadata, placing the new block,4090 // We use these to indicate our intention to update metadata, placing the new atom,
4127 // and possibly removing a free list node.4091 // and possibly removing a free list node.
4128 // It would be simpler to do it inside the for loop below, but that would cause a4092 // It would be simpler to do it inside the for loop below, but that would cause a
4129 // problem if an error was returned later in the function. So this action4093 // problem if an error was returned later in the function. So this action
4130 // is actually carried out at the end of the function, when errors are no longer possible.4094 // is actually carried out at the end of the function, when errors are no longer possible.
4131 var block_placement: ?*TextBlock = null;4095 var atom_placement: ?*Atom = null;
4132 var free_list_removal: ?usize = null;4096 var free_list_removal: ?usize = null;
41334097
4134 // First we look for an appropriately sized free list node.4098 // First we look for an appropriately sized free list node.
4135 // The list is unordered. We'll just take the first thing that works.4099 // The list is unordered. We'll just take the first thing that works.
4136 var vaddr = blk: {4100 var vaddr = blk: {
4137 var i: usize = 0;4101 var i: usize = 0;
4138 while (i < text_block_free_list.items.len) {4102 while (i < free_list.items.len) {
4139 const big_block = text_block_free_list.items[i];4103 const big_atom = free_list.items[i];
4140 // We now have a pointer to a live text block that has too much capacity.4104 // We now have a pointer to a live atom that has too much capacity.
4141 // Is it enough that we could fit this new text block?4105 // Is it enough that we could fit this new atom?
4142 const sym = self.locals.items[big_block.local_sym_index];4106 const sym = self.locals.items[big_atom.local_sym_index];
4143 const capacity = big_block.capacity(self.*);4107 const capacity = big_atom.capacity(self.*);
4144 const ideal_capacity = padToIdeal(capacity);4108 const ideal_capacity = if (needs_padding) padToIdeal(capacity) else capacity;
4145 const ideal_capacity_end_vaddr = sym.n_value + ideal_capacity;4109 const ideal_capacity_end_vaddr = sym.n_value + ideal_capacity;
4146 const capacity_end_vaddr = sym.n_value + capacity;4110 const capacity_end_vaddr = sym.n_value + capacity;
4147 const new_start_vaddr_unaligned = capacity_end_vaddr - new_block_ideal_capacity;4111 const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity;
4148 const new_start_vaddr = mem.alignBackwardGeneric(u64, new_start_vaddr_unaligned, alignment);4112 const new_start_vaddr = mem.alignBackwardGeneric(u64, new_start_vaddr_unaligned, alignment);
4149 if (new_start_vaddr < ideal_capacity_end_vaddr) {4113 if (new_start_vaddr < ideal_capacity_end_vaddr) {
4150 // Additional bookkeeping here to notice if this free list node4114 // Additional bookkeeping here to notice if this free list node
4151 // should be deleted because the block that it points to has grown to take up4115 // should be deleted because the atom that it points to has grown to take up
4152 // more of the extra capacity.4116 // more of the extra capacity.
4153 if (!big_block.freeListEligible(self.*)) {4117 if (!big_atom.freeListEligible(self.*)) {
4154 const bl = text_block_free_list.swapRemove(i);4118 const bl = free_list.swapRemove(i);
4155 bl.deinit(self.base.allocator);4119 bl.deinit(self.base.allocator);
4156 } else {4120 } else {
4157 i += 1;4121 i += 1;
4158 }4122 }
4159 continue;4123 continue;
4160 }4124 }
4161 // At this point we know that we will place the new block here. But the4125 // At this point we know that we will place the new atom here. But the
4162 // remaining question is whether there is still yet enough capacity left4126 // remaining question is whether there is still yet enough capacity left
4163 // over for there to still be a free list node.4127 // over for there to still be a free list node.
4164 const remaining_capacity = new_start_vaddr - ideal_capacity_end_vaddr;4128 const remaining_capacity = new_start_vaddr - ideal_capacity_end_vaddr;
4165 const keep_free_list_node = remaining_capacity >= min_text_capacity;4129 const keep_free_list_node = remaining_capacity >= min_text_capacity;
41664130
4167 // Set up the metadata to be updated, after errors are no longer possible.4131 // Set up the metadata to be updated, after errors are no longer possible.
4168 block_placement = big_block;4132 atom_placement = big_atom;
4169 if (!keep_free_list_node) {4133 if (!keep_free_list_node) {
4170 free_list_removal = i;4134 free_list_removal = i;
4171 }4135 }
4172 break :blk new_start_vaddr;4136 break :blk new_start_vaddr;
4173 } else if (self.blocks.get(match)) |last| {4137 } else if (self.atoms.get(match)) |last| {
4174 const last_symbol = self.locals.items[last.local_sym_index];4138 const last_symbol = self.locals.items[last.local_sym_index];
4175 // TODO We should pad out the excess capacity with NOPs. For executables,4139 const ideal_capacity = if (needs_padding) padToIdeal(last.size) else last.size;
4176 // no padding seems to be OK, but it will probably not be for objects.
4177 const ideal_capacity = padToIdeal(last.size);
4178 const ideal_capacity_end_vaddr = last_symbol.n_value + ideal_capacity;4140 const ideal_capacity_end_vaddr = last_symbol.n_value + ideal_capacity;
4179 const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment);4141 const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment);
4180 block_placement = last;4142 atom_placement = last;
4181 break :blk new_start_vaddr;4143 break :blk new_start_vaddr;
4182 } else {4144 } else {
4183 break :blk text_section.addr;4145 break :blk mem.alignForwardGeneric(u64, sect.addr, alignment);
4184 }4146 }
4185 };4147 };
41864148
4187 const expand_text_section = block_placement == null or block_placement.?.next == null;4149 const expand_section = atom_placement == null or atom_placement.?.next == null;
4188 if (expand_text_section) {4150 if (expand_section) {
4189 const needed_size = @intCast(u32, (vaddr + new_block_size) - text_section.addr);4151 const needed_size = @intCast(u32, (vaddr + new_atom_size) - sect.addr);
4190 try self.growSection(match, needed_size);4152 try self.growSection(match, needed_size);
4191 _ = try self.blocks.put(self.base.allocator, match, text_block);4153 _ = try self.atoms.put(self.base.allocator, match, atom);
4192 text_section.size = needed_size;4154 sect.size = needed_size;
4193 self.load_commands_dirty = true;4155 self.load_commands_dirty = true;
4194 }4156 }
4195 const align_pow = @intCast(u32, math.log2(alignment));4157 const align_pow = @intCast(u32, math.log2(alignment));
4196 text_section.@"align" = math.max(text_section.@"align", align_pow);4158 if (sect.@"align" < align_pow) {
4197 text_block.size = new_block_size;4159 sect.@"align" = align_pow;
4160 self.load_commands_dirty = true;
4161 }
4162 atom.size = new_atom_size;
4163 atom.alignment = align_pow;
41984164
4199 if (text_block.prev) |prev| {4165 if (atom.prev) |prev| {
4200 prev.next = text_block.next;4166 prev.next = atom.next;
4201 }4167 }
4202 if (text_block.next) |next| {4168 if (atom.next) |next| {
4203 next.prev = text_block.prev;4169 next.prev = atom.prev;
4204 }4170 }
42054171
4206 if (block_placement) |big_block| {4172 if (atom_placement) |big_atom| {
4207 text_block.prev = big_block;4173 atom.prev = big_atom;
4208 text_block.next = big_block.next;4174 atom.next = big_atom.next;
4209 big_block.next = text_block;4175 big_atom.next = atom;
4210 } else {4176 } else {
4211 text_block.prev = null;4177 atom.prev = null;
4212 text_block.next = null;4178 atom.next = null;
4213 }4179 }
4214 if (free_list_removal) |i| {4180 if (free_list_removal) |i| {
4215 _ = text_block_free_list.swapRemove(i);4181 _ = free_list.swapRemove(i);
4216 }4182 }
42174183
4218 return vaddr;4184 return vaddr;
...@@ -4319,10 +4285,10 @@ fn writeDyldInfoData(self: *MachO) !void {...@@ -4319,10 +4285,10 @@ fn writeDyldInfoData(self: *MachO) !void {
4319 defer lazy_bind_pointers.deinit();4285 defer lazy_bind_pointers.deinit();
43204286
4321 {4287 {
4322 var it = self.blocks.iterator();4288 var it = self.atoms.iterator();
4323 while (it.next()) |entry| {4289 while (it.next()) |entry| {
4324 const match = entry.key_ptr.*;4290 const match = entry.key_ptr.*;
4325 var atom: *TextBlock = entry.value_ptr.*;4291 var atom: *Atom = entry.value_ptr.*;
43264292
4327 if (match.seg == self.text_segment_cmd_index.?) continue; // __TEXT is non-writable4293 if (match.seg == self.text_segment_cmd_index.?) continue; // __TEXT is non-writable
43284294
...@@ -4444,7 +4410,7 @@ fn writeDyldInfoData(self: *MachO) !void {...@@ -4444,7 +4410,7 @@ fn writeDyldInfoData(self: *MachO) !void {
4444}4410}
44454411
4446fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {4412fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
4447 const last_atom = self.blocks.get(.{4413 const last_atom = self.atoms.get(.{
4448 .seg = self.text_segment_cmd_index.?,4414 .seg = self.text_segment_cmd_index.?,
4449 .sect = self.stub_helper_section_index.?,4415 .sect = self.stub_helper_section_index.?,
4450 }) orelse return;4416 }) orelse return;
...@@ -4538,25 +4504,25 @@ fn writeDices(self: *MachO) !void {...@@ -4538,25 +4504,25 @@ fn writeDices(self: *MachO) !void {
4538 var buf = std.ArrayList(u8).init(self.base.allocator);4504 var buf = std.ArrayList(u8).init(self.base.allocator);
4539 defer buf.deinit();4505 defer buf.deinit();
45404506
4541 var block: *TextBlock = self.blocks.get(.{4507 var atom: *Atom = self.atoms.get(.{
4542 .seg = self.text_segment_cmd_index orelse return,4508 .seg = self.text_segment_cmd_index orelse return,
4543 .sect = self.text_section_index orelse return,4509 .sect = self.text_section_index orelse return,
4544 }) orelse return;4510 }) orelse return;
45454511
4546 while (block.prev) |prev| {4512 while (atom.prev) |prev| {
4547 block = prev;4513 atom = prev;
4548 }4514 }
45494515
4550 const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;4516 const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
4551 const text_sect = text_seg.sections.items[self.text_section_index.?];4517 const text_sect = text_seg.sections.items[self.text_section_index.?];
45524518
4553 while (true) {4519 while (true) {
4554 if (block.dices.items.len > 0) {4520 if (atom.dices.items.len > 0) {
4555 const sym = self.locals.items[block.local_sym_index];4521 const sym = self.locals.items[atom.local_sym_index];
4556 const base_off = try math.cast(u32, sym.n_value - text_sect.addr + text_sect.offset);4522 const base_off = try math.cast(u32, sym.n_value - text_sect.addr + text_sect.offset);
45574523
4558 try buf.ensureUnusedCapacity(block.dices.items.len * @sizeOf(macho.data_in_code_entry));4524 try buf.ensureUnusedCapacity(atom.dices.items.len * @sizeOf(macho.data_in_code_entry));
4559 for (block.dices.items) |dice| {4525 for (atom.dices.items) |dice| {
4560 const rebased_dice = macho.data_in_code_entry{4526 const rebased_dice = macho.data_in_code_entry{
4561 .offset = base_off + dice.offset,4527 .offset = base_off + dice.offset,
4562 .length = dice.length,4528 .length = dice.length,
...@@ -4566,8 +4532,8 @@ fn writeDices(self: *MachO) !void {...@@ -4566,8 +4532,8 @@ fn writeDices(self: *MachO) !void {
4566 }4532 }
4567 }4533 }
45684534
4569 if (block.next) |next| {4535 if (atom.next) |next| {
4570 block = next;4536 atom = next;
4571 } else break;4537 } else break;
4572 }4538 }
45734539