| ... | ... | @@ -158,8 +158,8 @@ stub_preamble_sym_index: ?u32 = null, |
| 158 | 158 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| 159 | 159 | strtab_dir: std.HashMapUnmanaged(u32, u32, StringIndexContext, std.hash_map.default_max_load_percentage) = .{}, |
| 160 | 160 | |
| 161 | | got_entries_map: std.AutoArrayHashMapUnmanaged(GotIndirectionKey, *TextBlock) = .{}, |
| 162 | | stubs_map: std.AutoArrayHashMapUnmanaged(u32, *TextBlock) = .{}, |
| 161 | got_entries_map: std.AutoArrayHashMapUnmanaged(GotIndirectionKey, *Atom) = .{}, |
| 162 | stubs_map: std.AutoArrayHashMapUnmanaged(u32, *Atom) = .{}, |
| 163 | 163 | |
| 164 | 164 | error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 165 | 165 | |
| ... | ... | @@ -171,12 +171,12 @@ has_stabs: bool = false, |
| 171 | 171 | |
| 172 | 172 | section_ordinals: std.AutoArrayHashMapUnmanaged(MatchingSection, void) = .{}, |
| 173 | 173 | |
| 174 | | /// A list of text blocks that have surplus capacity. This list can have false |
| 174 | /// A list of atoms that have surplus capacity. This list can have false |
| 175 | 175 | /// positives, as functions grow and shrink over time, only sometimes being added |
| 176 | 176 | /// or removed from the freelist. |
| 177 | 177 | /// |
| 178 | | /// A text block has surplus capacity when its overcapacity value is greater than |
| 179 | | /// padToIdeal(minimum_text_block_size). That is, when it has so |
| 178 | /// An atom has surplus capacity when its overcapacity value is greater than |
| 179 | /// padToIdeal(minimum_atom_size). That is, when it has so |
| 180 | 180 | /// much extra capacity, that we could fit a small new symbol in it, itself with |
| 181 | 181 | /// ideal_capacity or more. |
| 182 | 182 | /// |
| ... | ... | @@ -184,23 +184,23 @@ section_ordinals: std.AutoArrayHashMapUnmanaged(MatchingSection, void) = .{}, |
| 184 | 184 | /// |
| 185 | 185 | /// Overcapacity is measured by actual_capacity - ideal_capacity. Note that |
| 186 | 186 | /// 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 it |
| 187 | /// allocate a fresh atom, which will have ideal capacity, and then grow it |
| 188 | 188 | /// by 1 byte. It will then have -1 overcapacity. |
| 189 | | block_free_lists: std.AutoHashMapUnmanaged(MatchingSection, std.ArrayListUnmanaged(*TextBlock)) = .{}, |
| 189 | atom_free_lists: std.AutoHashMapUnmanaged(MatchingSection, std.ArrayListUnmanaged(*Atom)) = .{}, |
| 190 | 190 | |
| 191 | | /// Pointer to the last allocated text block |
| 192 | | blocks: std.AutoHashMapUnmanaged(MatchingSection, *TextBlock) = .{}, |
| 191 | /// Pointer to the last allocated atom |
| 192 | atoms: std.AutoHashMapUnmanaged(MatchingSection, *Atom) = .{}, |
| 193 | 193 | |
| 194 | | /// List of TextBlocks that are owned directly by the linker. |
| 195 | | /// Currently these are only TextBlocks that are the result of linking |
| 196 | | /// object files. TextBlock which take part in incremental linking are |
| 194 | /// List of atoms that are owned directly by the linker. |
| 195 | /// Currently these are only atoms that are the result of linking |
| 196 | /// object files. Atoms which take part in incremental linking are |
| 197 | 197 | /// at present owned by Module.Decl. |
| 198 | 198 | /// TODO consolidate this. |
| 199 | | managed_blocks: std.ArrayListUnmanaged(*TextBlock) = .{}, |
| 199 | managed_atoms: std.ArrayListUnmanaged(*Atom) = .{}, |
| 200 | 200 | |
| 201 | 201 | /// Table of Decls that are currently alive. |
| 202 | 202 | /// 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 | 204 | /// TODO consolidate this. |
| 205 | 205 | decls: std.AutoArrayHashMapUnmanaged(*Module.Decl, void) = .{}, |
| 206 | 206 | |
| ... | ... | @@ -768,31 +768,8 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 768 | 768 | try self.addDataInCodeLC(); |
| 769 | 769 | try self.addCodeSignatureLC(); |
| 770 | 770 | |
| 771 | | try self.parseTextBlocks(); |
| 771 | try self.parseObjectsIntoAtoms(); |
| 772 | 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 | 773 | try self.writeAtoms(); |
| 797 | 774 | |
| 798 | 775 | if (self.bss_section_index) |idx| { |
| ... | ... | @@ -1637,87 +1614,24 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1637 | 1614 | return res; |
| 1638 | 1615 | } |
| 1639 | 1616 | |
| 1640 | | pub fn createEmptyAtom(self: *MachO, local_sym_index: u32, size: u64, alignment: u32) !*TextBlock { |
| 1617 | pub fn createEmptyAtom(self: *MachO, local_sym_index: u32, size: u64, alignment: u32) !*Atom { |
| 1641 | 1618 | const code = try self.base.allocator.alloc(u8, size); |
| 1642 | 1619 | defer self.base.allocator.free(code); |
| 1643 | 1620 | mem.set(u8, code, 0); |
| 1644 | 1621 | |
| 1645 | | const atom = try self.base.allocator.create(TextBlock); |
| 1622 | const atom = try self.base.allocator.create(Atom); |
| 1646 | 1623 | errdefer self.base.allocator.destroy(atom); |
| 1647 | | atom.* = TextBlock.empty; |
| 1624 | atom.* = Atom.empty; |
| 1648 | 1625 | atom.local_sym_index = local_sym_index; |
| 1649 | 1626 | atom.size = size; |
| 1650 | 1627 | atom.alignment = alignment; |
| 1651 | 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); |
| 1653 | 1630 | |
| 1654 | 1631 | return atom; |
| 1655 | 1632 | } |
| 1656 | 1633 | |
| 1657 | | pub fn allocateAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !u64 { |
| 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 | | |
| 1720 | | pub fn writeAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !void { |
| 1634 | pub fn writeAtom(self: *MachO, atom: *Atom, match: MatchingSection) !void { |
| 1721 | 1635 | const seg = self.load_commands.items[match.seg].Segment; |
| 1722 | 1636 | const sect = seg.sections.items[match.sect]; |
| 1723 | 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 | 1642 | } |
| 1729 | 1643 | |
| 1730 | 1644 | fn 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; |
| 1732 | 1646 | |
| 1733 | 1647 | while (true) { |
| 1734 | 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 | 1665 | } |
| 1752 | 1666 | |
| 1753 | 1667 | fn 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 | 1668 | var sym_it = self.symbol_resolver.valueIterator(); |
| 1757 | 1669 | while (sym_it.next()) |resolv| { |
| 1758 | 1670 | if (resolv.where != .global) continue; |
| ... | ... | @@ -1770,12 +1682,14 @@ fn writeAtoms(self: *MachO) !void { |
| 1770 | 1682 | defer buffer.deinit(); |
| 1771 | 1683 | var file_offset: ?u64 = null; |
| 1772 | 1684 | |
| 1773 | | var it = self.blocks.iterator(); |
| 1685 | var it = self.atoms.iterator(); |
| 1774 | 1686 | while (it.next()) |entry| { |
| 1775 | 1687 | const match = entry.key_ptr.*; |
| 1776 | 1688 | const seg = self.load_commands.items[match.seg].Segment; |
| 1777 | 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) }); |
| 1779 | 1693 | |
| 1780 | 1694 | while (atom.prev) |prev| { |
| 1781 | 1695 | atom = prev; |
| ... | ... | @@ -1789,6 +1703,8 @@ fn writeAtoms(self: *MachO) !void { |
| 1789 | 1703 | break :blk next_sym.n_value - (atom_sym.n_value + atom.size); |
| 1790 | 1704 | } else 0; |
| 1791 | 1705 | |
| 1706 | log.debug(" (adding atom {s} to buffer: {})", .{ self.getString(atom_sym.n_strx), atom_sym }); |
| 1707 | |
| 1792 | 1708 | try atom.resolveRelocs(self); |
| 1793 | 1709 | try buffer.appendSlice(atom.code.items); |
| 1794 | 1710 | try buffer.ensureUnusedCapacity(padding_size); |
| ... | ... | @@ -1824,7 +1740,7 @@ fn writeAtoms(self: *MachO) !void { |
| 1824 | 1740 | } |
| 1825 | 1741 | } |
| 1826 | 1742 | |
| 1827 | | pub fn createGotAtom(self: *MachO, key: GotIndirectionKey) !*TextBlock { |
| 1743 | pub fn createGotAtom(self: *MachO, key: GotIndirectionKey) !*Atom { |
| 1828 | 1744 | const local_sym_index = @intCast(u32, self.locals.items.len); |
| 1829 | 1745 | try self.locals.append(self.base.allocator, .{ |
| 1830 | 1746 | .n_strx = try self.makeString("l_zld_got_entry"), |
| ... | ... | @@ -1860,7 +1776,7 @@ pub fn createGotAtom(self: *MachO, key: GotIndirectionKey) !*TextBlock { |
| 1860 | 1776 | return atom; |
| 1861 | 1777 | } |
| 1862 | 1778 | |
| 1863 | | fn createDyldPrivateAtom(self: *MachO) !*TextBlock { |
| 1779 | fn createDyldPrivateAtom(self: *MachO) !*Atom { |
| 1864 | 1780 | const local_sym_index = @intCast(u32, self.locals.items.len); |
| 1865 | 1781 | try self.locals.append(self.base.allocator, .{ |
| 1866 | 1782 | .n_strx = try self.makeString("l_zld_dyld_private"), |
| ... | ... | @@ -1873,7 +1789,7 @@ fn createDyldPrivateAtom(self: *MachO) !*TextBlock { |
| 1873 | 1789 | return self.createEmptyAtom(local_sym_index, @sizeOf(u64), 3); |
| 1874 | 1790 | } |
| 1875 | 1791 | |
| 1876 | | fn createStubHelperPreambleAtom(self: *MachO) !*TextBlock { |
| 1792 | fn createStubHelperPreambleAtom(self: *MachO) !*Atom { |
| 1877 | 1793 | const arch = self.base.options.target.cpu.arch; |
| 1878 | 1794 | const size: u64 = switch (arch) { |
| 1879 | 1795 | .x86_64 => 15, |
| ... | ... | @@ -2006,7 +1922,7 @@ fn createStubHelperPreambleAtom(self: *MachO) !*TextBlock { |
| 2006 | 1922 | return atom; |
| 2007 | 1923 | } |
| 2008 | 1924 | |
| 2009 | | pub fn createStubHelperAtom(self: *MachO) !*TextBlock { |
| 1925 | pub fn createStubHelperAtom(self: *MachO) !*Atom { |
| 2010 | 1926 | const arch = self.base.options.target.cpu.arch; |
| 2011 | 1927 | const stub_size: u4 = switch (arch) { |
| 2012 | 1928 | .x86_64 => 10, |
| ... | ... | @@ -2072,7 +1988,7 @@ pub fn createStubHelperAtom(self: *MachO) !*TextBlock { |
| 2072 | 1988 | return atom; |
| 2073 | 1989 | } |
| 2074 | 1990 | |
| 2075 | | pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, lazy_binding_sym_index: u32) !*TextBlock { |
| 1991 | pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, lazy_binding_sym_index: u32) !*Atom { |
| 2076 | 1992 | const local_sym_index = @intCast(u32, self.locals.items.len); |
| 2077 | 1993 | try self.locals.append(self.base.allocator, .{ |
| 2078 | 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 | 2018 | return atom; |
| 2103 | 2019 | } |
| 2104 | 2020 | |
| 2105 | | pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*TextBlock { |
| 2021 | pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom { |
| 2106 | 2022 | const arch = self.base.options.target.cpu.arch; |
| 2107 | 2023 | const alignment: u2 = switch (arch) { |
| 2108 | 2024 | .x86_64 => 0, |
| ... | ... | @@ -2273,14 +2189,6 @@ fn resolveSymbolsInObject( |
| 2273 | 2189 | continue; |
| 2274 | 2190 | }, |
| 2275 | 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 | 2192 | _ = self.unresolved.fetchSwapRemove(resolv.where_index); |
| 2285 | 2193 | }, |
| 2286 | 2194 | } |
| ... | ... | @@ -2437,23 +2345,36 @@ fn resolveSymbols(self: *MachO) !void { |
| 2437 | 2345 | resolv.local_sym_index = local_sym_index; |
| 2438 | 2346 | |
| 2439 | 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 | } |
| 2442 | 2352 | |
| 2443 | 2353 | try self.resolveDyldStubBinder(); |
| 2444 | 2354 | { |
| 2445 | | const atom = try self.createDyldPrivateAtom(); |
| 2446 | | _ = try self.allocateAtom(atom, .{ |
| 2355 | const match = MatchingSection{ |
| 2447 | 2356 | .seg = self.data_segment_cmd_index.?, |
| 2448 | 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(); |
| 2453 | | _ = try self.allocateAtom(atom, .{ |
| 2367 | const match = MatchingSection{ |
| 2454 | 2368 | .seg = self.text_segment_cmd_index.?, |
| 2455 | 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 | } |
| 2458 | 2379 | |
| 2459 | 2380 | // Third pass, resolve symbols in dynamic libraries. |
| ... | ... | @@ -2483,30 +2404,45 @@ fn resolveSymbols(self: *MachO) !void { |
| 2483 | 2404 | .stub => { |
| 2484 | 2405 | if (self.stubs_map.contains(resolv.where_index)) break :outer_blk; |
| 2485 | 2406 | const stub_helper_atom = blk: { |
| 2486 | | const atom = try self.createStubHelperAtom(); |
| 2487 | | _ = try self.allocateAtom(atom, .{ |
| 2407 | const match = MatchingSection{ |
| 2488 | 2408 | .seg = self.text_segment_cmd_index.?, |
| 2489 | 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 | 2417 | break :blk atom; |
| 2492 | 2418 | }; |
| 2493 | 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 | 2424 | const atom = try self.createLazyPointerAtom( |
| 2495 | 2425 | stub_helper_atom.local_sym_index, |
| 2496 | 2426 | resolv.where_index, |
| 2497 | 2427 | ); |
| 2498 | | _ = try self.allocateAtom(atom, .{ |
| 2499 | | .seg = self.data_segment_cmd_index.?, |
| 2500 | | .sect = self.la_symbol_ptr_section_index.?, |
| 2501 | | }); |
| 2428 | const atom_sym = &self.locals.items[atom.local_sym_index]; |
| 2429 | const alignment = try math.powi(u32, 2, atom.alignment); |
| 2430 | const vaddr = try self.allocateAtom(atom, atom.size, alignment, match); |
| 2431 | atom_sym.n_value = vaddr; |
| 2432 | atom_sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1); |
| 2502 | 2433 | break :blk atom; |
| 2503 | 2434 | }; |
| 2504 | 2435 | const stub_atom = blk: { |
| 2505 | | const atom = try self.createStubAtom(laptr_atom.local_sym_index); |
| 2506 | | _ = try self.allocateAtom(atom, .{ |
| 2436 | const match = MatchingSection{ |
| 2507 | 2437 | .seg = self.text_segment_cmd_index.?, |
| 2508 | 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 | 2446 | break :blk atom; |
| 2511 | 2447 | }; |
| 2512 | 2448 | try self.stubs_map.putNoClobber(self.base.allocator, resolv.where_index, stub_atom); |
| ... | ... | @@ -2565,7 +2501,10 @@ fn resolveSymbols(self: *MachO) !void { |
| 2565 | 2501 | // TODO perhaps we should special-case special symbols? Create a separate |
| 2566 | 2502 | // linked list of atoms? |
| 2567 | 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 | } |
| 2570 | 2509 | |
| 2571 | 2510 | for (self.unresolved.keys()) |index| { |
| ... | ... | @@ -2632,10 +2571,14 @@ fn resolveDyldStubBinder(self: *MachO) !void { |
| 2632 | 2571 | .seg = self.data_const_segment_cmd_index.?, |
| 2633 | 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 | } |
| 2637 | 2580 | |
| 2638 | | fn parseTextBlocks(self: *MachO) !void { |
| 2581 | fn parseObjectsIntoAtoms(self: *MachO) !void { |
| 2639 | 2582 | var parsed_atoms = Object.ParsedAtoms.init(self.base.allocator); |
| 2640 | 2583 | defer parsed_atoms.deinit(); |
| 2641 | 2584 | |
| ... | ... | @@ -2710,7 +2653,7 @@ fn parseTextBlocks(self: *MachO) !void { |
| 2710 | 2653 | metadata.alignment, |
| 2711 | 2654 | }); |
| 2712 | 2655 | |
| 2713 | | const sect_size = if (self.blocks.get(match)) |last| blk: { |
| 2656 | const sect_size = if (self.atoms.get(match)) |last| blk: { |
| 2714 | 2657 | const last_atom_sym = self.locals.items[last.local_sym_index]; |
| 2715 | 2658 | break :blk last_atom_sym.n_value + last.size - sect.addr; |
| 2716 | 2659 | } else 0; |
| ... | ... | @@ -2720,7 +2663,7 @@ fn parseTextBlocks(self: *MachO) !void { |
| 2720 | 2663 | try self.growSection(match, needed_size); |
| 2721 | 2664 | sect.size = needed_size; |
| 2722 | 2665 | |
| 2723 | | var base_vaddr = if (self.blocks.get(match)) |last| blk: { |
| 2666 | var base_vaddr = if (self.atoms.get(match)) |last| blk: { |
| 2724 | 2667 | const last_atom_sym = self.locals.items[last.local_sym_index]; |
| 2725 | 2668 | break :blk last_atom_sym.n_value + last.size; |
| 2726 | 2669 | } else sect.addr; |
| ... | ... | @@ -2750,7 +2693,7 @@ fn parseTextBlocks(self: *MachO) !void { |
| 2750 | 2693 | alias_sym.n_sect = n_sect; |
| 2751 | 2694 | } |
| 2752 | 2695 | |
| 2753 | | // Update each symbol contained within the TextBlock |
| 2696 | // Update each symbol contained within the atom |
| 2754 | 2697 | for (atom.contained.items) |sym_at_off| { |
| 2755 | 2698 | const contained_sym = &self.locals.items[sym_at_off.local_sym_index]; |
| 2756 | 2699 | contained_sym.n_value = base_vaddr + sym_at_off.offset; |
| ... | ... | @@ -2764,13 +2707,13 @@ fn parseTextBlocks(self: *MachO) !void { |
| 2764 | 2707 | } else break; |
| 2765 | 2708 | } |
| 2766 | 2709 | |
| 2767 | | if (self.blocks.getPtr(match)) |last| { |
| 2710 | if (self.atoms.getPtr(match)) |last| { |
| 2768 | 2711 | const first_atom = first_atoms.get(match).?; |
| 2769 | 2712 | last.*.next = first_atom; |
| 2770 | 2713 | first_atom.prev = last.*; |
| 2771 | 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 | } |
| 2776 | 2719 | |
| ... | ... | @@ -2905,18 +2848,18 @@ pub fn deinit(self: *MachO) void { |
| 2905 | 2848 | } |
| 2906 | 2849 | self.load_commands.deinit(self.base.allocator); |
| 2907 | 2850 | |
| 2908 | | for (self.managed_blocks.items) |block| { |
| 2909 | | block.deinit(self.base.allocator); |
| 2910 | | self.base.allocator.destroy(block); |
| 2851 | for (self.managed_atoms.items) |atom| { |
| 2852 | atom.deinit(self.base.allocator); |
| 2853 | self.base.allocator.destroy(atom); |
| 2911 | 2854 | } |
| 2912 | | self.managed_blocks.deinit(self.base.allocator); |
| 2913 | | self.blocks.deinit(self.base.allocator); |
| 2855 | self.managed_atoms.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 | 2859 | while (it.next()) |free_list| { |
| 2917 | 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 | 2864 | for (self.decls.keys()) |decl| { |
| 2922 | 2865 | decl.link.macho.deinit(self.base.allocator); |
| ... | ... | @@ -2936,25 +2879,21 @@ pub fn closeFiles(self: MachO) void { |
| 2936 | 2879 | } |
| 2937 | 2880 | } |
| 2938 | 2881 | |
| 2939 | | fn freeTextBlock(self: *MachO, text_block: *TextBlock) void { |
| 2940 | | log.debug("freeTextBlock {*}", .{text_block}); |
| 2941 | | text_block.deinit(self.base.allocator); |
| 2882 | fn freeAtom(self: *MachO, atom: *Atom, match: MatchingSection) void { |
| 2883 | log.debug("freeAtom {*}", .{atom}); |
| 2884 | atom.deinit(self.base.allocator); |
| 2942 | 2885 | |
| 2943 | | const match = MatchingSection{ |
| 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).?; |
| 2886 | const free_list = self.atom_free_lists.getPtr(match).?; |
| 2948 | 2887 | var already_have_free_list_node = false; |
| 2949 | 2888 | { |
| 2950 | 2889 | var i: usize = 0; |
| 2951 | | // TODO turn text_block_free_list into a hash map |
| 2952 | | while (i < text_block_free_list.items.len) { |
| 2953 | | if (text_block_free_list.items[i] == text_block) { |
| 2954 | | _ = text_block_free_list.swapRemove(i); |
| 2890 | // TODO turn free_list into a hash map |
| 2891 | while (i < free_list.items.len) { |
| 2892 | if (free_list.items[i] == atom) { |
| 2893 | _ = free_list.swapRemove(i); |
| 2955 | 2894 | continue; |
| 2956 | 2895 | } |
| 2957 | | if (text_block_free_list.items[i] == text_block.prev) { |
| 2896 | if (free_list.items[i] == atom.prev) { |
| 2958 | 2897 | already_have_free_list_node = true; |
| 2959 | 2898 | } |
| 2960 | 2899 | i += 1; |
| ... | ... | @@ -2962,72 +2901,73 @@ fn freeTextBlock(self: *MachO, text_block: *TextBlock) void { |
| 2962 | 2901 | } |
| 2963 | 2902 | // TODO process free list for dbg info just like we do above for vaddrs |
| 2964 | 2903 | |
| 2965 | | if (self.blocks.getPtr(match)) |last_text_block| { |
| 2966 | | if (last_text_block.* == text_block) { |
| 2967 | | if (text_block.prev) |prev| { |
| 2968 | | // TODO shrink the __text section size here |
| 2969 | | last_text_block.* = prev; |
| 2904 | if (self.atoms.getPtr(match)) |last_atom| { |
| 2905 | if (last_atom.* == atom) { |
| 2906 | if (atom.prev) |prev| { |
| 2907 | // TODO shrink the section size here |
| 2908 | last_atom.* = prev; |
| 2970 | 2909 | } |
| 2971 | 2910 | } |
| 2972 | 2911 | } |
| 2973 | 2912 | |
| 2974 | 2913 | if (self.d_sym) |*ds| { |
| 2975 | | if (ds.dbg_info_decl_first == text_block) { |
| 2976 | | ds.dbg_info_decl_first = text_block.dbg_info_next; |
| 2914 | if (ds.dbg_info_decl_first == atom) { |
| 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 | 2918 | // 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 | } |
| 2983 | 2922 | |
| 2984 | | if (text_block.prev) |prev| { |
| 2985 | | prev.next = text_block.next; |
| 2923 | if (atom.prev) |prev| { |
| 2924 | prev.next = atom.next; |
| 2986 | 2925 | |
| 2987 | 2926 | if (!already_have_free_list_node and prev.freeListEligible(self.*)) { |
| 2988 | 2927 | // The free list is heuristics, it doesn't have to be perfect, so we can ignore |
| 2989 | 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 | 2931 | } else { |
| 2993 | | text_block.prev = null; |
| 2932 | atom.prev = null; |
| 2994 | 2933 | } |
| 2995 | 2934 | |
| 2996 | | if (text_block.next) |next| { |
| 2997 | | next.prev = text_block.prev; |
| 2935 | if (atom.next) |next| { |
| 2936 | next.prev = atom.prev; |
| 2998 | 2937 | } else { |
| 2999 | | text_block.next = null; |
| 2938 | atom.next = null; |
| 3000 | 2939 | } |
| 3001 | 2940 | |
| 3002 | | if (text_block.dbg_info_prev) |prev| { |
| 3003 | | prev.dbg_info_next = text_block.dbg_info_next; |
| 2941 | if (atom.dbg_info_prev) |prev| { |
| 2942 | prev.dbg_info_next = atom.dbg_info_next; |
| 3004 | 2943 | |
| 3005 | | // TODO the free list logic like we do for text blocks above |
| 2944 | // TODO the free list logic like we do for atoms above |
| 3006 | 2945 | } else { |
| 3007 | | text_block.dbg_info_prev = null; |
| 2946 | atom.dbg_info_prev = null; |
| 3008 | 2947 | } |
| 3009 | 2948 | |
| 3010 | | if (text_block.dbg_info_next) |next| { |
| 3011 | | next.dbg_info_prev = text_block.dbg_info_prev; |
| 2949 | if (atom.dbg_info_next) |next| { |
| 2950 | next.dbg_info_prev = atom.dbg_info_prev; |
| 3012 | 2951 | } else { |
| 3013 | | text_block.dbg_info_next = null; |
| 2952 | atom.dbg_info_next = null; |
| 3014 | 2953 | } |
| 3015 | 2954 | } |
| 3016 | 2955 | |
| 3017 | | fn shrinkTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64) void { |
| 2956 | fn shrinkAtom(self: *MachO, atom: *Atom, new_block_size: u64, match: MatchingSection) void { |
| 3018 | 2957 | _ = self; |
| 3019 | | _ = text_block; |
| 2958 | _ = atom; |
| 3020 | 2959 | _ = new_block_size; |
| 2960 | _ = match; |
| 3021 | 2961 | // TODO check the new capacity, and if it crosses the size threshold into a big enough |
| 3022 | 2962 | // capacity, insert a free list node for it. |
| 3023 | 2963 | } |
| 3024 | 2964 | |
| 3025 | | fn growTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { |
| 3026 | | const sym = self.locals.items[text_block.local_sym_index]; |
| 2965 | fn growAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, match: MatchingSection) !u64 { |
| 2966 | const sym = self.locals.items[atom.local_sym_index]; |
| 3027 | 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 | 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 | } |
| 3032 | 2972 | |
| 3033 | 2973 | 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 |
| 3112 | 3052 | // in a different, smarter, more automatic way somewhere else, in a more centralised |
| 3113 | 3053 | // way than this. |
| 3114 | 3054 | // 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 | 3056 | decl.link.macho.code.clearAndFree(self.base.allocator); |
| 3117 | 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 | 3142 | // in a different, smarter, more automatic way somewhere else, in a more centralised |
| 3203 | 3143 | // way than this. |
| 3204 | 3144 | // 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 | 3146 | decl.link.macho.code.clearAndFree(self.base.allocator); |
| 3207 | 3147 | try decl.link.macho.code.appendSlice(self.base.allocator, code_buffer.items); |
| 3208 | 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 | 3171 | const capacity = decl.link.macho.capacity(self.*); |
| 3232 | 3172 | const need_realloc = code_len > capacity or !mem.isAlignedGeneric(u64, symbol.n_value, required_alignment); |
| 3233 | 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 | }); |
| 3235 | 3178 | |
| 3236 | 3179 | log.debug("growing {s} and moving from 0x{x} to 0x{x}", .{ decl.name, symbol.n_value, vaddr }); |
| 3237 | 3180 | |
| ... | ... | @@ -3241,15 +3184,24 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64 |
| 3241 | 3184 | .where = .local, |
| 3242 | 3185 | .where_index = decl.link.macho.local_sym_index, |
| 3243 | 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 | 3189 | .seg = self.data_const_segment_cmd_index.?, |
| 3246 | 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 | } |
| 3249 | 3198 | |
| 3250 | 3199 | symbol.n_value = vaddr; |
| 3251 | 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 | 3206 | decl.link.macho.size = code_len; |
| 3255 | 3207 | |
| ... | ... | @@ -3265,11 +3217,17 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64 |
| 3265 | 3217 | defer self.base.allocator.free(decl_name); |
| 3266 | 3218 | |
| 3267 | 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 | }); |
| 3269 | 3224 | |
| 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 }); |
| 3271 | 3226 | |
| 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 | }); |
| 3273 | 3231 | |
| 3274 | 3232 | symbol.* = .{ |
| 3275 | 3233 | .n_strx = name_str_index, |
| ... | ... | @@ -3282,10 +3240,16 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64 |
| 3282 | 3240 | .where = .local, |
| 3283 | 3241 | .where_index = decl.link.macho.local_sym_index, |
| 3284 | 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 | 3245 | .seg = self.data_const_segment_cmd_index.?, |
| 3287 | 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 | } |
| 3290 | 3254 | |
| 3291 | 3255 | return symbol; |
| ... | ... | @@ -3402,7 +3366,10 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void { |
| 3402 | 3366 | log.debug("freeDecl {*}", .{decl}); |
| 3403 | 3367 | _ = self.decls.swapRemove(decl); |
| 3404 | 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 | 3373 | if (decl.link.macho.local_sym_index != 0) { |
| 3407 | 3374 | self.locals_free_list.append(self.base.allocator, decl.link.macho.local_sym_index) catch {}; |
| 3408 | 3375 | |
| ... | ... | @@ -3412,7 +3379,7 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void { |
| 3412 | 3379 | decl.link.macho.local_sym_index = 0; |
| 3413 | 3380 | } |
| 3414 | 3381 | if (self.d_sym) |*ds| { |
| 3415 | | // TODO make this logic match freeTextBlock. Maybe abstract the logic |
| 3382 | // TODO make this logic match freeAtom. Maybe abstract the logic |
| 3416 | 3383 | // out since the same thing is desired for both. |
| 3417 | 3384 | _ = ds.dbg_line_fn_free_list.remove(&decl.fn_link.macho); |
| 3418 | 3385 | if (decl.fn_link.macho.prev) |prev| { |
| ... | ... | @@ -3947,7 +3914,7 @@ fn allocateSection( |
| 3947 | 3914 | .sect = index, |
| 3948 | 3915 | }; |
| 3949 | 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, .{}); |
| 3951 | 3918 | |
| 3952 | 3919 | self.load_commands_dirty = true; |
| 3953 | 3920 | self.sections_order_dirty = true; |
| ... | ... | @@ -4113,106 +4080,105 @@ fn getSectionMaxAlignment(self: *MachO, segment_id: u16, start_sect_id: u16) !u3 |
| 4113 | 4080 | return max_alignment; |
| 4114 | 4081 | } |
| 4115 | 4082 | |
| 4116 | | fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { |
| 4117 | | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 4118 | | const text_section = &text_segment.sections.items[self.text_section_index.?]; |
| 4119 | | const match = MatchingSection{ |
| 4120 | | .seg = self.text_segment_cmd_index.?, |
| 4121 | | .sect = self.text_section_index.?, |
| 4122 | | }; |
| 4123 | | var text_block_free_list = self.block_free_lists.get(match).?; |
| 4124 | | const new_block_ideal_capacity = padToIdeal(new_block_size); |
| 4083 | fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, match: MatchingSection) !u64 { |
| 4084 | const seg = &self.load_commands.items[match.seg].Segment; |
| 4085 | const sect = &seg.sections.items[match.sect]; |
| 4086 | var free_list = self.atom_free_lists.get(match).?; |
| 4087 | const needs_padding = match.seg == self.text_segment_cmd_index.? and match.sect == self.text_section_index.?; |
| 4088 | const new_atom_ideal_capacity = if (needs_padding) padToIdeal(new_atom_size) else new_atom_size; |
| 4125 | 4089 | |
| 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 | 4091 | // and possibly removing a free list node. |
| 4128 | 4092 | // It would be simpler to do it inside the for loop below, but that would cause a |
| 4129 | 4093 | // problem if an error was returned later in the function. So this action |
| 4130 | 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 | 4096 | var free_list_removal: ?usize = null; |
| 4133 | 4097 | |
| 4134 | 4098 | // First we look for an appropriately sized free list node. |
| 4135 | 4099 | // The list is unordered. We'll just take the first thing that works. |
| 4136 | 4100 | var vaddr = blk: { |
| 4137 | 4101 | var i: usize = 0; |
| 4138 | | while (i < text_block_free_list.items.len) { |
| 4139 | | const big_block = text_block_free_list.items[i]; |
| 4140 | | // We now have a pointer to a live text block that has too much capacity. |
| 4141 | | // Is it enough that we could fit this new text block? |
| 4142 | | const sym = self.locals.items[big_block.local_sym_index]; |
| 4143 | | const capacity = big_block.capacity(self.*); |
| 4144 | | const ideal_capacity = padToIdeal(capacity); |
| 4102 | while (i < free_list.items.len) { |
| 4103 | const big_atom = free_list.items[i]; |
| 4104 | // We now have a pointer to a live atom that has too much capacity. |
| 4105 | // Is it enough that we could fit this new atom? |
| 4106 | const sym = self.locals.items[big_atom.local_sym_index]; |
| 4107 | const capacity = big_atom.capacity(self.*); |
| 4108 | const ideal_capacity = if (needs_padding) padToIdeal(capacity) else capacity; |
| 4145 | 4109 | const ideal_capacity_end_vaddr = sym.n_value + ideal_capacity; |
| 4146 | 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 | 4112 | const new_start_vaddr = mem.alignBackwardGeneric(u64, new_start_vaddr_unaligned, alignment); |
| 4149 | 4113 | if (new_start_vaddr < ideal_capacity_end_vaddr) { |
| 4150 | 4114 | // 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 up |
| 4115 | // should be deleted because the atom that it points to has grown to take up |
| 4152 | 4116 | // more of the extra capacity. |
| 4153 | | if (!big_block.freeListEligible(self.*)) { |
| 4154 | | const bl = text_block_free_list.swapRemove(i); |
| 4117 | if (!big_atom.freeListEligible(self.*)) { |
| 4118 | const bl = free_list.swapRemove(i); |
| 4155 | 4119 | bl.deinit(self.base.allocator); |
| 4156 | 4120 | } else { |
| 4157 | 4121 | i += 1; |
| 4158 | 4122 | } |
| 4159 | 4123 | continue; |
| 4160 | 4124 | } |
| 4161 | | // At this point we know that we will place the new block here. But the |
| 4125 | // At this point we know that we will place the new atom here. But the |
| 4162 | 4126 | // remaining question is whether there is still yet enough capacity left |
| 4163 | 4127 | // over for there to still be a free list node. |
| 4164 | 4128 | const remaining_capacity = new_start_vaddr - ideal_capacity_end_vaddr; |
| 4165 | 4129 | const keep_free_list_node = remaining_capacity >= min_text_capacity; |
| 4166 | 4130 | |
| 4167 | 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 | 4133 | if (!keep_free_list_node) { |
| 4170 | 4134 | free_list_removal = i; |
| 4171 | 4135 | } |
| 4172 | 4136 | break :blk new_start_vaddr; |
| 4173 | | } else if (self.blocks.get(match)) |last| { |
| 4137 | } else if (self.atoms.get(match)) |last| { |
| 4174 | 4138 | const last_symbol = self.locals.items[last.local_sym_index]; |
| 4175 | | // TODO We should pad out the excess capacity with NOPs. For executables, |
| 4176 | | // no padding seems to be OK, but it will probably not be for objects. |
| 4177 | | const ideal_capacity = padToIdeal(last.size); |
| 4139 | const ideal_capacity = if (needs_padding) padToIdeal(last.size) else last.size; |
| 4178 | 4140 | const ideal_capacity_end_vaddr = last_symbol.n_value + ideal_capacity; |
| 4179 | 4141 | const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment); |
| 4180 | | block_placement = last; |
| 4142 | atom_placement = last; |
| 4181 | 4143 | break :blk new_start_vaddr; |
| 4182 | 4144 | } else { |
| 4183 | | break :blk text_section.addr; |
| 4145 | break :blk mem.alignForwardGeneric(u64, sect.addr, alignment); |
| 4184 | 4146 | } |
| 4185 | 4147 | }; |
| 4186 | 4148 | |
| 4187 | | const expand_text_section = block_placement == null or block_placement.?.next == null; |
| 4188 | | if (expand_text_section) { |
| 4189 | | const needed_size = @intCast(u32, (vaddr + new_block_size) - text_section.addr); |
| 4149 | const expand_section = atom_placement == null or atom_placement.?.next == null; |
| 4150 | if (expand_section) { |
| 4151 | const needed_size = @intCast(u32, (vaddr + new_atom_size) - sect.addr); |
| 4190 | 4152 | try self.growSection(match, needed_size); |
| 4191 | | _ = try self.blocks.put(self.base.allocator, match, text_block); |
| 4192 | | text_section.size = needed_size; |
| 4153 | _ = try self.atoms.put(self.base.allocator, match, atom); |
| 4154 | sect.size = needed_size; |
| 4193 | 4155 | self.load_commands_dirty = true; |
| 4194 | 4156 | } |
| 4195 | 4157 | const align_pow = @intCast(u32, math.log2(alignment)); |
| 4196 | | text_section.@"align" = math.max(text_section.@"align", align_pow); |
| 4197 | | text_block.size = new_block_size; |
| 4158 | if (sect.@"align" < align_pow) { |
| 4159 | sect.@"align" = align_pow; |
| 4160 | self.load_commands_dirty = true; |
| 4161 | } |
| 4162 | atom.size = new_atom_size; |
| 4163 | atom.alignment = align_pow; |
| 4198 | 4164 | |
| 4199 | | if (text_block.prev) |prev| { |
| 4200 | | prev.next = text_block.next; |
| 4165 | if (atom.prev) |prev| { |
| 4166 | prev.next = atom.next; |
| 4201 | 4167 | } |
| 4202 | | if (text_block.next) |next| { |
| 4203 | | next.prev = text_block.prev; |
| 4168 | if (atom.next) |next| { |
| 4169 | next.prev = atom.prev; |
| 4204 | 4170 | } |
| 4205 | 4171 | |
| 4206 | | if (block_placement) |big_block| { |
| 4207 | | text_block.prev = big_block; |
| 4208 | | text_block.next = big_block.next; |
| 4209 | | big_block.next = text_block; |
| 4172 | if (atom_placement) |big_atom| { |
| 4173 | atom.prev = big_atom; |
| 4174 | atom.next = big_atom.next; |
| 4175 | big_atom.next = atom; |
| 4210 | 4176 | } else { |
| 4211 | | text_block.prev = null; |
| 4212 | | text_block.next = null; |
| 4177 | atom.prev = null; |
| 4178 | atom.next = null; |
| 4213 | 4179 | } |
| 4214 | 4180 | if (free_list_removal) |i| { |
| 4215 | | _ = text_block_free_list.swapRemove(i); |
| 4181 | _ = free_list.swapRemove(i); |
| 4216 | 4182 | } |
| 4217 | 4183 | |
| 4218 | 4184 | return vaddr; |
| ... | ... | @@ -4319,10 +4285,10 @@ fn writeDyldInfoData(self: *MachO) !void { |
| 4319 | 4285 | defer lazy_bind_pointers.deinit(); |
| 4320 | 4286 | |
| 4321 | 4287 | { |
| 4322 | | var it = self.blocks.iterator(); |
| 4288 | var it = self.atoms.iterator(); |
| 4323 | 4289 | while (it.next()) |entry| { |
| 4324 | 4290 | const match = entry.key_ptr.*; |
| 4325 | | var atom: *TextBlock = entry.value_ptr.*; |
| 4291 | var atom: *Atom = entry.value_ptr.*; |
| 4326 | 4292 | |
| 4327 | 4293 | if (match.seg == self.text_segment_cmd_index.?) continue; // __TEXT is non-writable |
| 4328 | 4294 | |
| ... | ... | @@ -4444,7 +4410,7 @@ fn writeDyldInfoData(self: *MachO) !void { |
| 4444 | 4410 | } |
| 4445 | 4411 | |
| 4446 | 4412 | fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void { |
| 4447 | | const last_atom = self.blocks.get(.{ |
| 4413 | const last_atom = self.atoms.get(.{ |
| 4448 | 4414 | .seg = self.text_segment_cmd_index.?, |
| 4449 | 4415 | .sect = self.stub_helper_section_index.?, |
| 4450 | 4416 | }) orelse return; |
| ... | ... | @@ -4538,25 +4504,25 @@ fn writeDices(self: *MachO) !void { |
| 4538 | 4504 | var buf = std.ArrayList(u8).init(self.base.allocator); |
| 4539 | 4505 | defer buf.deinit(); |
| 4540 | 4506 | |
| 4541 | | var block: *TextBlock = self.blocks.get(.{ |
| 4507 | var atom: *Atom = self.atoms.get(.{ |
| 4542 | 4508 | .seg = self.text_segment_cmd_index orelse return, |
| 4543 | 4509 | .sect = self.text_section_index orelse return, |
| 4544 | 4510 | }) orelse return; |
| 4545 | 4511 | |
| 4546 | | while (block.prev) |prev| { |
| 4547 | | block = prev; |
| 4512 | while (atom.prev) |prev| { |
| 4513 | atom = prev; |
| 4548 | 4514 | } |
| 4549 | 4515 | |
| 4550 | 4516 | const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 4551 | 4517 | const text_sect = text_seg.sections.items[self.text_section_index.?]; |
| 4552 | 4518 | |
| 4553 | 4519 | while (true) { |
| 4554 | | if (block.dices.items.len > 0) { |
| 4555 | | const sym = self.locals.items[block.local_sym_index]; |
| 4520 | if (atom.dices.items.len > 0) { |
| 4521 | const sym = self.locals.items[atom.local_sym_index]; |
| 4556 | 4522 | const base_off = try math.cast(u32, sym.n_value - text_sect.addr + text_sect.offset); |
| 4557 | 4523 | |
| 4558 | | try buf.ensureUnusedCapacity(block.dices.items.len * @sizeOf(macho.data_in_code_entry)); |
| 4559 | | for (block.dices.items) |dice| { |
| 4524 | try buf.ensureUnusedCapacity(atom.dices.items.len * @sizeOf(macho.data_in_code_entry)); |
| 4525 | for (atom.dices.items) |dice| { |
| 4560 | 4526 | const rebased_dice = macho.data_in_code_entry{ |
| 4561 | 4527 | .offset = base_off + dice.offset, |
| 4562 | 4528 | .length = dice.length, |
| ... | ... | @@ -4566,8 +4532,8 @@ fn writeDices(self: *MachO) !void { |
| 4566 | 4532 | } |
| 4567 | 4533 | } |
| 4568 | 4534 | |
| 4569 | | if (block.next) |next| { |
| 4570 | | block = next; |
| 4535 | if (atom.next) |next| { |
| 4536 | atom = next; |
| 4571 | 4537 | } else break; |
| 4572 | 4538 | } |
| 4573 | 4539 | |