| author | |
| committer | |
| log | 03feea0fb200f273dd74bf778997e6a6bead86cc |
| tree | c439ed641e01ec4d860abb181ee585a2a287494c |
| parent | d042b88c112aa919386bc76294225d4f7bd9a7b3 |
4 files changed, 515 insertions(+), 233 deletions(-)
src/link/MachO.zig+264-27| ... | ... | @@ -57,6 +57,8 @@ const SystemLib = struct { |
| 57 | 57 | weak: bool = false, |
| 58 | 58 | }; |
| 59 | 59 | |
| 60 | const N_DESC_GCED: u16 = @bitCast(u16, @as(i16, -1)); | |
| 61 | ||
| 60 | 62 | base: File, |
| 61 | 63 | |
| 62 | 64 | /// If this is not null, an object file is created by LLVM and linked with LLD afterwards. |
| ... | ... | @@ -256,6 +258,8 @@ unnamed_const_atoms: UnnamedConstTable = .{}, |
| 256 | 258 | /// TODO consolidate this. |
| 257 | 259 | decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, ?MatchingSection) = .{}, |
| 258 | 260 | |
| 261 | gc_roots: std.AutoHashMapUnmanaged(*Atom, void) = .{}, | |
| 262 | ||
| 259 | 263 | const Entry = struct { |
| 260 | 264 | target: Atom.Relocation.Target, |
| 261 | 265 | atom: *Atom, |
| ... | ... | @@ -1165,6 +1169,8 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 1165 | 1169 | |
| 1166 | 1170 | const use_llvm = build_options.have_llvm and self.base.options.use_llvm; |
| 1167 | 1171 | if (use_llvm or use_stage1) { |
| 1172 | self.logAtoms(); | |
| 1173 | try self.gcAtoms(); | |
| 1168 | 1174 | try self.pruneAndSortSections(); |
| 1169 | 1175 | try self.allocateSegments(); |
| 1170 | 1176 | try self.allocateLocals(); |
| ... | ... | @@ -1173,9 +1179,10 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 1173 | 1179 | try self.allocateSpecialSymbols(); |
| 1174 | 1180 | try self.allocateGlobals(); |
| 1175 | 1181 | |
| 1176 | if (build_options.enable_logging) { | |
| 1182 | if (build_options.enable_logging or true) { | |
| 1177 | 1183 | self.logSymtab(); |
| 1178 | 1184 | self.logSectionOrdinals(); |
| 1185 | self.logAtoms(); | |
| 1179 | 1186 | } |
| 1180 | 1187 | |
| 1181 | 1188 | if (use_llvm or use_stage1) { |
| ... | ... | @@ -2177,6 +2184,7 @@ pub fn createEmptyAtom(self: *MachO, local_sym_index: u32, size: u64, alignment: |
| 2177 | 2184 | try atom.code.resize(self.base.allocator, size_usize); |
| 2178 | 2185 | mem.set(u8, atom.code.items, 0); |
| 2179 | 2186 | |
| 2187 | try self.atom_by_index_table.putNoClobber(self.base.allocator, local_sym_index, atom); | |
| 2180 | 2188 | try self.managed_atoms.append(self.base.allocator, atom); |
| 2181 | 2189 | return atom; |
| 2182 | 2190 | } |
| ... | ... | @@ -3298,12 +3306,7 @@ fn resolveDyldStubBinder(self: *MachO) !void { |
| 3298 | 3306 | const vaddr = try self.allocateAtom(atom, @sizeOf(u64), 8, match); |
| 3299 | 3307 | log.debug("allocated {s} atom at 0x{x}", .{ self.getString(sym.n_strx), vaddr }); |
| 3300 | 3308 | atom_sym.n_value = vaddr; |
| 3301 | } else { | |
| 3302 | const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].segment; | |
| 3303 | const sect = &seg.sections.items[self.got_section_index.?]; | |
| 3304 | sect.size += atom.size; | |
| 3305 | try self.addAtomToSection(atom, match); | |
| 3306 | } | |
| 3309 | } else try self.addAtomToSection(atom, match); | |
| 3307 | 3310 | |
| 3308 | 3311 | atom_sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1); |
| 3309 | 3312 | } |
| ... | ... | @@ -3564,6 +3567,7 @@ pub fn deinit(self: *MachO) void { |
| 3564 | 3567 | self.symbol_resolver.deinit(self.base.allocator); |
| 3565 | 3568 | self.unresolved.deinit(self.base.allocator); |
| 3566 | 3569 | self.tentatives.deinit(self.base.allocator); |
| 3570 | self.gc_roots.deinit(self.base.allocator); | |
| 3567 | 3571 | |
| 3568 | 3572 | for (self.objects.items) |*object| { |
| 3569 | 3573 | object.deinit(self.base.allocator); |
| ... | ... | @@ -3916,7 +3920,6 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu |
| 3916 | 3920 | const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); |
| 3917 | 3921 | const local_sym_index = try self.allocateLocalSymbol(); |
| 3918 | 3922 | const atom = try self.createEmptyAtom(local_sym_index, @sizeOf(u64), math.log2(required_alignment)); |
| 3919 | try self.atom_by_index_table.putNoClobber(self.base.allocator, local_sym_index, atom); | |
| 3920 | 3923 | |
| 3921 | 3924 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .none, .{ |
| 3922 | 3925 | .parent_atom_index = local_sym_index, |
| ... | ... | @@ -5597,7 +5600,7 @@ fn pruneAndSortSectionsInSegment(self: *MachO, maybe_seg_id: *?u16, indices: []* |
| 5597 | 5600 | const old_idx = maybe_index.* orelse continue; |
| 5598 | 5601 | const sect = sections[old_idx]; |
| 5599 | 5602 | if (sect.size == 0) { |
| 5600 | log.debug("pruning section {s},{s}", .{ sect.segName(), sect.sectName() }); | |
| 5603 | log.warn("pruning section {s},{s}", .{ sect.segName(), sect.sectName() }); | |
| 5601 | 5604 | maybe_index.* = null; |
| 5602 | 5605 | seg.inner.cmdsize -= @sizeOf(macho.section_64); |
| 5603 | 5606 | seg.inner.nsects -= 1; |
| ... | ... | @@ -5630,7 +5633,7 @@ fn pruneAndSortSectionsInSegment(self: *MachO, maybe_seg_id: *?u16, indices: []* |
| 5630 | 5633 | |
| 5631 | 5634 | if (seg.inner.nsects == 0 and !mem.eql(u8, "__TEXT", seg.inner.segName())) { |
| 5632 | 5635 | // Segment has now become empty, so mark it as such |
| 5633 | log.debug("marking segment {s} as dead", .{seg.inner.segName()}); | |
| 5636 | log.warn("marking segment {s} as dead", .{seg.inner.segName()}); | |
| 5634 | 5637 | seg.inner.cmd = @intToEnum(macho.LC, 0); |
| 5635 | 5638 | maybe_seg_id.* = null; |
| 5636 | 5639 | } |
| ... | ... | @@ -5712,6 +5715,189 @@ fn pruneAndSortSections(self: *MachO) !void { |
| 5712 | 5715 | self.sections_order_dirty = false; |
| 5713 | 5716 | } |
| 5714 | 5717 | |
| 5718 | fn gcAtoms(self: *MachO) !void { | |
| 5719 | const dead_strip = self.base.options.gc_sections orelse false; | |
| 5720 | if (!dead_strip) return; | |
| 5721 | ||
| 5722 | // Add all exports as GC roots | |
| 5723 | for (self.globals.items) |sym| { | |
| 5724 | if (sym.n_type == 0) continue; | |
| 5725 | const resolv = self.symbol_resolver.get(sym.n_strx).?; | |
| 5726 | assert(resolv.where == .global); | |
| 5727 | const gc_root = self.atom_by_index_table.get(resolv.local_sym_index) orelse { | |
| 5728 | log.warn("skipping {s}", .{self.getString(sym.n_strx)}); | |
| 5729 | continue; | |
| 5730 | }; | |
| 5731 | _ = try self.gc_roots.getOrPut(self.base.allocator, gc_root); | |
| 5732 | } | |
| 5733 | ||
| 5734 | // if (self.tlv_ptrs_section_index) |sect| { | |
| 5735 | // var atom = self.atoms.get(.{ | |
| 5736 | // .seg = self.data_segment_cmd_index.?, | |
| 5737 | // .sect = sect, | |
| 5738 | // }).?; | |
| 5739 | ||
| 5740 | // while (true) { | |
| 5741 | // _ = try self.gc_roots.getOrPut(self.base.allocator, atom); | |
| 5742 | ||
| 5743 | // if (atom.prev) |prev| { | |
| 5744 | // atom = prev; | |
| 5745 | // } else break; | |
| 5746 | // } | |
| 5747 | // } | |
| 5748 | ||
| 5749 | // Add any atom targeting an import as GC root | |
| 5750 | var atoms_it = self.atoms.iterator(); | |
| 5751 | while (atoms_it.next()) |entry| { | |
| 5752 | var atom = entry.value_ptr.*; | |
| 5753 | ||
| 5754 | while (true) { | |
| 5755 | for (atom.relocs.items) |rel| { | |
| 5756 | if ((try Atom.getTargetAtom(rel, self)) == null) switch (rel.target) { | |
| 5757 | .local => {}, | |
| 5758 | .global => |n_strx| { | |
| 5759 | const resolv = self.symbol_resolver.get(n_strx).?; | |
| 5760 | switch (resolv.where) { | |
| 5761 | .global => {}, | |
| 5762 | .undef => { | |
| 5763 | _ = try self.gc_roots.getOrPut(self.base.allocator, atom); | |
| 5764 | break; | |
| 5765 | }, | |
| 5766 | } | |
| 5767 | }, | |
| 5768 | }; | |
| 5769 | } | |
| 5770 | ||
| 5771 | if (atom.prev) |prev| { | |
| 5772 | atom = prev; | |
| 5773 | } else break; | |
| 5774 | } | |
| 5775 | } | |
| 5776 | ||
| 5777 | var stack = std.ArrayList(*Atom).init(self.base.allocator); | |
| 5778 | defer stack.deinit(); | |
| 5779 | try stack.ensureUnusedCapacity(self.gc_roots.count()); | |
| 5780 | ||
| 5781 | var retained = std.AutoHashMap(*Atom, void).init(self.base.allocator); | |
| 5782 | defer retained.deinit(); | |
| 5783 | try retained.ensureUnusedCapacity(self.gc_roots.count()); | |
| 5784 | ||
| 5785 | log.warn("GC roots:", .{}); | |
| 5786 | var gc_roots_it = self.gc_roots.keyIterator(); | |
| 5787 | while (gc_roots_it.next()) |gc_root| { | |
| 5788 | self.logAtom(gc_root.*); | |
| 5789 | ||
| 5790 | stack.appendAssumeCapacity(gc_root.*); | |
| 5791 | retained.putAssumeCapacityNoClobber(gc_root.*, {}); | |
| 5792 | } | |
| 5793 | ||
| 5794 | log.warn("walking tree...", .{}); | |
| 5795 | while (stack.popOrNull()) |source_atom| { | |
| 5796 | for (source_atom.relocs.items) |rel| { | |
| 5797 | if (try Atom.getTargetAtom(rel, self)) |target_atom| { | |
| 5798 | const gop = try retained.getOrPut(target_atom); | |
| 5799 | if (!gop.found_existing) { | |
| 5800 | log.warn(" RETAINED ATOM(%{d}) -> ATOM(%{d})", .{ | |
| 5801 | source_atom.local_sym_index, | |
| 5802 | target_atom.local_sym_index, | |
| 5803 | }); | |
| 5804 | try stack.append(target_atom); | |
| 5805 | } | |
| 5806 | } | |
| 5807 | } | |
| 5808 | } | |
| 5809 | ||
| 5810 | atoms_it = self.atoms.iterator(); | |
| 5811 | while (atoms_it.next()) |entry| { | |
| 5812 | const match = entry.key_ptr.*; | |
| 5813 | ||
| 5814 | if (self.text_segment_cmd_index) |seg| { | |
| 5815 | if (seg == match.seg) { | |
| 5816 | if (self.eh_frame_section_index) |sect| { | |
| 5817 | if (sect == match.sect) continue; | |
| 5818 | } | |
| 5819 | } | |
| 5820 | } | |
| 5821 | ||
| 5822 | if (self.data_segment_cmd_index) |seg| { | |
| 5823 | if (seg == match.seg) { | |
| 5824 | if (self.rustc_section_index) |sect| { | |
| 5825 | if (sect == match.sect) continue; | |
| 5826 | } | |
| 5827 | } | |
| 5828 | } | |
| 5829 | ||
| 5830 | const seg = &self.load_commands.items[match.seg].segment; | |
| 5831 | const sect = &seg.sections.items[match.sect]; | |
| 5832 | var atom = entry.value_ptr.*; | |
| 5833 | ||
| 5834 | log.warn("GCing atoms in {s},{s}", .{ sect.segName(), sect.sectName() }); | |
| 5835 | ||
| 5836 | while (true) { | |
| 5837 | const orig_prev = atom.prev; | |
| 5838 | ||
| 5839 | if (!retained.contains(atom)) { | |
| 5840 | // Dead atom; remove. | |
| 5841 | log.warn(" DEAD ATOM(%{d})", .{atom.local_sym_index}); | |
| 5842 | ||
| 5843 | const sym = &self.locals.items[atom.local_sym_index]; | |
| 5844 | sym.n_desc = N_DESC_GCED; | |
| 5845 | ||
| 5846 | if (self.symbol_resolver.getPtr(sym.n_strx)) |resolv| { | |
| 5847 | if (resolv.local_sym_index == atom.local_sym_index) { | |
| 5848 | const global = &self.globals.items[resolv.where_index]; | |
| 5849 | global.n_desc = N_DESC_GCED; | |
| 5850 | } | |
| 5851 | } | |
| 5852 | ||
| 5853 | for (self.got_entries.items) |got_entry| { | |
| 5854 | if (got_entry.atom == atom) { | |
| 5855 | _ = self.got_entries_table.swapRemove(got_entry.target); | |
| 5856 | break; | |
| 5857 | } | |
| 5858 | } | |
| 5859 | ||
| 5860 | for (self.stubs.items) |stub, i| { | |
| 5861 | if (stub == atom) { | |
| 5862 | _ = self.stubs_table.swapRemove(@intCast(u32, i)); | |
| 5863 | break; | |
| 5864 | } | |
| 5865 | } | |
| 5866 | ||
| 5867 | for (atom.contained.items) |sym_off| { | |
| 5868 | const inner = &self.locals.items[sym_off.local_sym_index]; | |
| 5869 | inner.n_desc = N_DESC_GCED; | |
| 5870 | ||
| 5871 | if (self.symbol_resolver.getPtr(inner.n_strx)) |resolv| { | |
| 5872 | if (resolv.local_sym_index == atom.local_sym_index) { | |
| 5873 | const global = &self.globals.items[resolv.where_index]; | |
| 5874 | global.n_desc = N_DESC_GCED; | |
| 5875 | } | |
| 5876 | } | |
| 5877 | } | |
| 5878 | ||
| 5879 | log.warn(" BEFORE size = {x}", .{sect.size}); | |
| 5880 | sect.size -= atom.size; | |
| 5881 | log.warn(" AFTER size = {x}", .{sect.size}); | |
| 5882 | if (atom.prev) |prev| { | |
| 5883 | prev.next = atom.next; | |
| 5884 | } | |
| 5885 | if (atom.next) |next| { | |
| 5886 | next.prev = atom.prev; | |
| 5887 | } else { | |
| 5888 | // TODO I think a null would be better here. | |
| 5889 | // The section will be GCed in the next step. | |
| 5890 | entry.value_ptr.* = if (atom.prev) |prev| prev else undefined; | |
| 5891 | } | |
| 5892 | } | |
| 5893 | ||
| 5894 | if (orig_prev) |prev| { | |
| 5895 | atom = prev; | |
| 5896 | } else break; | |
| 5897 | } | |
| 5898 | } | |
| 5899 | } | |
| 5900 | ||
| 5715 | 5901 | fn updateSectionOrdinals(self: *MachO) !void { |
| 5716 | 5902 | if (!self.sections_order_dirty) return; |
| 5717 | 5903 | |
| ... | ... | @@ -5776,8 +5962,11 @@ fn writeDyldInfoData(self: *MachO) !void { |
| 5776 | 5962 | } |
| 5777 | 5963 | |
| 5778 | 5964 | const seg = self.load_commands.items[match.seg].segment; |
| 5965 | const sect = seg.sections.items[match.sect]; | |
| 5966 | log.warn("dyld info for {s},{s}", .{ sect.segName(), sect.sectName() }); | |
| 5779 | 5967 | |
| 5780 | 5968 | while (true) { |
| 5969 | log.warn(" ATOM %{d}", .{atom.local_sym_index}); | |
| 5781 | 5970 | const sym = self.locals.items[atom.local_sym_index]; |
| 5782 | 5971 | const base_offset = sym.n_value - seg.inner.vmaddr; |
| 5783 | 5972 | |
| ... | ... | @@ -6217,10 +6406,19 @@ fn writeSymbolTable(self: *MachO) !void { |
| 6217 | 6406 | |
| 6218 | 6407 | for (self.locals.items) |sym| { |
| 6219 | 6408 | if (sym.n_strx == 0) continue; |
| 6409 | if (sym.n_desc == N_DESC_GCED) continue; | |
| 6220 | 6410 | if (self.symbol_resolver.get(sym.n_strx)) |_| continue; |
| 6221 | 6411 | try locals.append(sym); |
| 6222 | 6412 | } |
| 6223 | 6413 | |
| 6414 | var globals = std.ArrayList(macho.nlist_64).init(self.base.allocator); | |
| 6415 | defer globals.deinit(); | |
| 6416 | ||
| 6417 | for (self.globals.items) |sym| { | |
| 6418 | if (sym.n_desc == N_DESC_GCED) continue; | |
| 6419 | try globals.append(sym); | |
| 6420 | } | |
| 6421 | ||
| 6224 | 6422 | // TODO How do we handle null global symbols in incremental context? |
| 6225 | 6423 | var undefs = std.ArrayList(macho.nlist_64).init(self.base.allocator); |
| 6226 | 6424 | defer undefs.deinit(); |
| ... | ... | @@ -6291,7 +6489,7 @@ fn writeSymbolTable(self: *MachO) !void { |
| 6291 | 6489 | } |
| 6292 | 6490 | |
| 6293 | 6491 | const nlocals = locals.items.len; |
| 6294 | const nexports = self.globals.items.len; | |
| 6492 | const nexports = globals.items.len; | |
| 6295 | 6493 | const nundefs = undefs.items.len; |
| 6296 | 6494 | |
| 6297 | 6495 | const locals_off = symtab.symoff; |
| ... | ... | @@ -6302,7 +6500,7 @@ fn writeSymbolTable(self: *MachO) !void { |
| 6302 | 6500 | const exports_off = locals_off + locals_size; |
| 6303 | 6501 | const exports_size = nexports * @sizeOf(macho.nlist_64); |
| 6304 | 6502 | log.debug("writing exported symbols from 0x{x} to 0x{x}", .{ exports_off, exports_size + exports_off }); |
| 6305 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.globals.items), exports_off); | |
| 6503 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(globals.items), exports_off); | |
| 6306 | 6504 | |
| 6307 | 6505 | const undefs_off = exports_off + exports_size; |
| 6308 | 6506 | const undefs_size = nundefs * @sizeOf(macho.nlist_64); |
| ... | ... | @@ -6898,55 +7096,55 @@ fn snapshotState(self: *MachO) !void { |
| 6898 | 7096 | } |
| 6899 | 7097 | |
| 6900 | 7098 | fn logSymtab(self: MachO) void { |
| 6901 | log.debug("locals:", .{}); | |
| 7099 | log.warn("locals:", .{}); | |
| 6902 | 7100 | for (self.locals.items) |sym, id| { |
| 6903 | log.debug(" {d}: {s}: @{x} in {d}", .{ id, self.getString(sym.n_strx), sym.n_value, sym.n_sect }); | |
| 7101 | log.warn(" {d}: {s}: @{x} in {d}", .{ id, self.getString(sym.n_strx), sym.n_value, sym.n_sect }); | |
| 6904 | 7102 | } |
| 6905 | 7103 | |
| 6906 | log.debug("globals:", .{}); | |
| 7104 | log.warn("globals:", .{}); | |
| 6907 | 7105 | for (self.globals.items) |sym, id| { |
| 6908 | log.debug(" {d}: {s}: @{x} in {d}", .{ id, self.getString(sym.n_strx), sym.n_value, sym.n_sect }); | |
| 7106 | log.warn(" {d}: {s}: @{x} in {d}", .{ id, self.getString(sym.n_strx), sym.n_value, sym.n_sect }); | |
| 6909 | 7107 | } |
| 6910 | 7108 | |
| 6911 | log.debug("undefs:", .{}); | |
| 7109 | log.warn("undefs:", .{}); | |
| 6912 | 7110 | for (self.undefs.items) |sym, id| { |
| 6913 | log.debug(" {d}: {s}: in {d}", .{ id, self.getString(sym.n_strx), sym.n_desc }); | |
| 7111 | log.warn(" {d}: {s}: in {d}", .{ id, self.getString(sym.n_strx), sym.n_desc }); | |
| 6914 | 7112 | } |
| 6915 | 7113 | |
| 6916 | 7114 | { |
| 6917 | log.debug("resolver:", .{}); | |
| 7115 | log.warn("resolver:", .{}); | |
| 6918 | 7116 | var it = self.symbol_resolver.iterator(); |
| 6919 | 7117 | while (it.next()) |entry| { |
| 6920 | log.debug(" {s} => {}", .{ self.getString(entry.key_ptr.*), entry.value_ptr.* }); | |
| 7118 | log.warn(" {s} => {}", .{ self.getString(entry.key_ptr.*), entry.value_ptr.* }); | |
| 6921 | 7119 | } |
| 6922 | 7120 | } |
| 6923 | 7121 | |
| 6924 | log.debug("GOT entries:", .{}); | |
| 7122 | log.warn("GOT entries:", .{}); | |
| 6925 | 7123 | for (self.got_entries_table.values()) |value| { |
| 6926 | 7124 | const key = self.got_entries.items[value].target; |
| 6927 | 7125 | const atom = self.got_entries.items[value].atom; |
| 6928 | 7126 | const n_value = self.locals.items[atom.local_sym_index].n_value; |
| 6929 | 7127 | switch (key) { |
| 6930 | .local => |ndx| log.debug(" {d}: @{x}", .{ ndx, n_value }), | |
| 6931 | .global => |n_strx| log.debug(" {s}: @{x}", .{ self.getString(n_strx), n_value }), | |
| 7128 | .local => |ndx| log.warn(" {d}: @{x}", .{ ndx, n_value }), | |
| 7129 | .global => |n_strx| log.warn(" {s}: @{x}", .{ self.getString(n_strx), n_value }), | |
| 6932 | 7130 | } |
| 6933 | 7131 | } |
| 6934 | 7132 | |
| 6935 | log.debug("__thread_ptrs entries:", .{}); | |
| 7133 | log.warn("__thread_ptrs entries:", .{}); | |
| 6936 | 7134 | for (self.tlv_ptr_entries_table.values()) |value| { |
| 6937 | 7135 | const key = self.tlv_ptr_entries.items[value].target; |
| 6938 | 7136 | const atom = self.tlv_ptr_entries.items[value].atom; |
| 6939 | 7137 | const n_value = self.locals.items[atom.local_sym_index].n_value; |
| 6940 | 7138 | assert(key == .global); |
| 6941 | log.debug(" {s}: @{x}", .{ self.getString(key.global), n_value }); | |
| 7139 | log.warn(" {s}: @{x}", .{ self.getString(key.global), n_value }); | |
| 6942 | 7140 | } |
| 6943 | 7141 | |
| 6944 | log.debug("stubs:", .{}); | |
| 7142 | log.warn("stubs:", .{}); | |
| 6945 | 7143 | for (self.stubs_table.keys()) |key| { |
| 6946 | 7144 | const value = self.stubs_table.get(key).?; |
| 6947 | 7145 | const atom = self.stubs.items[value]; |
| 6948 | 7146 | const sym = self.locals.items[atom.local_sym_index]; |
| 6949 | log.debug(" {s}: @{x}", .{ self.getString(key), sym.n_value }); | |
| 7147 | log.warn(" {s}: @{x}", .{ self.getString(key), sym.n_value }); | |
| 6950 | 7148 | } |
| 6951 | 7149 | } |
| 6952 | 7150 | |
| ... | ... | @@ -6964,6 +7162,45 @@ fn logSectionOrdinals(self: MachO) void { |
| 6964 | 7162 | } |
| 6965 | 7163 | } |
| 6966 | 7164 | |
| 7165 | fn logAtoms(self: MachO) void { | |
| 7166 | log.warn("atoms:", .{}); | |
| 7167 | var it = self.atoms.iterator(); | |
| 7168 | while (it.next()) |entry| { | |
| 7169 | const match = entry.key_ptr.*; | |
| 7170 | var atom = entry.value_ptr.*; | |
| 7171 | ||
| 7172 | while (atom.prev) |prev| { | |
| 7173 | atom = prev; | |
| 7174 | } | |
| 7175 | ||
| 7176 | const seg = self.load_commands.items[match.seg].segment; | |
| 7177 | const sect = seg.sections.items[match.sect]; | |
| 7178 | log.warn("{s},{s}", .{ sect.segName(), sect.sectName() }); | |
| 7179 | ||
| 7180 | while (true) { | |
| 7181 | self.logAtom(atom); | |
| 7182 | ||
| 7183 | if (atom.next) |next| { | |
| 7184 | atom = next; | |
| 7185 | } else break; | |
| 7186 | } | |
| 7187 | } | |
| 7188 | } | |
| 7189 | ||
| 7190 | fn logAtom(self: MachO, atom: *const Atom) void { | |
| 7191 | const sym = self.locals.items[atom.local_sym_index]; | |
| 7192 | log.warn(" ATOM(%{d}) @ {x}", .{ atom.local_sym_index, sym.n_value }); | |
| 7193 | ||
| 7194 | for (atom.contained.items) |sym_off| { | |
| 7195 | const inner_sym = self.locals.items[sym_off.local_sym_index]; | |
| 7196 | log.warn(" %{d} ('{s}') @ {x}", .{ | |
| 7197 | sym_off.local_sym_index, | |
| 7198 | self.getString(inner_sym.n_strx), | |
| 7199 | inner_sym.n_value, | |
| 7200 | }); | |
| 7201 | } | |
| 7202 | } | |
| 7203 | ||
| 6967 | 7204 | /// Since `os.copy_file_range` cannot be used when copying overlapping ranges within the same file, |
| 6968 | 7205 | /// and since `File.copyRangeAll` uses `os.copy_file_range` under-the-hood, we use heap allocated |
| 6969 | 7206 | /// buffers on all hosts except Linux (if `copy_file_range` syscall is available). |
src/link/MachO/Atom.zig+61-3| ... | ... | @@ -236,6 +236,7 @@ pub fn freeListEligible(self: Atom, macho_file: MachO) bool { |
| 236 | 236 | |
| 237 | 237 | const RelocContext = struct { |
| 238 | 238 | base_addr: u64 = 0, |
| 239 | base_offset: i32 = 0, | |
| 239 | 240 | allocator: Allocator, |
| 240 | 241 | object: *Object, |
| 241 | 242 | macho_file: *MachO, |
| ... | ... | @@ -366,7 +367,7 @@ pub fn parseRelocs(self: *Atom, relocs: []const macho.relocation_info, context: |
| 366 | 367 | ) orelse unreachable; |
| 367 | 368 | break :target Relocation.Target{ .global = n_strx }; |
| 368 | 369 | }; |
| 369 | const offset = @intCast(u32, rel.r_address); | |
| 370 | const offset = @intCast(u32, rel.r_address - context.base_offset); | |
| 370 | 371 | |
| 371 | 372 | switch (arch) { |
| 372 | 373 | .aarch64 => { |
| ... | ... | @@ -487,7 +488,7 @@ fn addPtrBindingOrRebase( |
| 487 | 488 | .global => |n_strx| { |
| 488 | 489 | try self.bindings.append(context.allocator, .{ |
| 489 | 490 | .n_strx = n_strx, |
| 490 | .offset = @intCast(u32, rel.r_address), | |
| 491 | .offset = @intCast(u32, rel.r_address - context.base_offset), | |
| 491 | 492 | }); |
| 492 | 493 | }, |
| 493 | 494 | .local => { |
| ... | ... | @@ -529,7 +530,10 @@ fn addPtrBindingOrRebase( |
| 529 | 530 | }; |
| 530 | 531 | |
| 531 | 532 | if (should_rebase) { |
| 532 | try self.rebases.append(context.allocator, @intCast(u32, rel.r_address)); | |
| 533 | try self.rebases.append( | |
| 534 | context.allocator, | |
| 535 | @intCast(u32, rel.r_address - context.base_offset), | |
| 536 | ); | |
| 533 | 537 | } |
| 534 | 538 | }, |
| 535 | 539 | } |
| ... | ... | @@ -650,6 +654,60 @@ fn addStub(target: Relocation.Target, context: RelocContext) !void { |
| 650 | 654 | context.macho_file.stubs.items[stub_index] = atom; |
| 651 | 655 | } |
| 652 | 656 | |
| 657 | pub fn getTargetAtom(rel: Relocation, macho_file: *MachO) !?*Atom { | |
| 658 | const is_via_got = got: { | |
| 659 | switch (macho_file.base.options.target.cpu.arch) { | |
| 660 | .aarch64 => break :got switch (@intToEnum(macho.reloc_type_arm64, rel.@"type")) { | |
| 661 | .ARM64_RELOC_GOT_LOAD_PAGE21, | |
| 662 | .ARM64_RELOC_GOT_LOAD_PAGEOFF12, | |
| 663 | .ARM64_RELOC_POINTER_TO_GOT, | |
| 664 | => true, | |
| 665 | else => false, | |
| 666 | }, | |
| 667 | .x86_64 => break :got switch (@intToEnum(macho.reloc_type_x86_64, rel.@"type")) { | |
| 668 | .X86_64_RELOC_GOT, .X86_64_RELOC_GOT_LOAD => true, | |
| 669 | else => false, | |
| 670 | }, | |
| 671 | else => unreachable, | |
| 672 | } | |
| 673 | }; | |
| 674 | ||
| 675 | if (is_via_got) { | |
| 676 | const got_index = macho_file.got_entries_table.get(rel.target) orelse { | |
| 677 | log.err("expected GOT entry for symbol", .{}); | |
| 678 | switch (rel.target) { | |
| 679 | .local => |sym_index| log.err(" local @{d}", .{sym_index}), | |
| 680 | .global => |n_strx| log.err(" global @'{s}'", .{macho_file.getString(n_strx)}), | |
| 681 | } | |
| 682 | log.err(" this is an internal linker error", .{}); | |
| 683 | return error.FailedToResolveRelocationTarget; | |
| 684 | }; | |
| 685 | return macho_file.got_entries.items[got_index].atom; | |
| 686 | } | |
| 687 | ||
| 688 | switch (rel.target) { | |
| 689 | .local => |sym_index| { | |
| 690 | return macho_file.atom_by_index_table.get(sym_index); | |
| 691 | }, | |
| 692 | .global => |n_strx| { | |
| 693 | const resolv = macho_file.symbol_resolver.get(n_strx).?; | |
| 694 | switch (resolv.where) { | |
| 695 | .global => return macho_file.atom_by_index_table.get(resolv.local_sym_index), | |
| 696 | .undef => { | |
| 697 | if (macho_file.stubs_table.get(n_strx)) |stub_index| { | |
| 698 | return macho_file.stubs.items[stub_index]; | |
| 699 | } else { | |
| 700 | if (macho_file.tlv_ptr_entries_table.get(rel.target)) |tlv_ptr_index| { | |
| 701 | return macho_file.tlv_ptr_entries.items[tlv_ptr_index].atom; | |
| 702 | } | |
| 703 | return null; | |
| 704 | } | |
| 705 | }, | |
| 706 | } | |
| 707 | }, | |
| 708 | } | |
| 709 | } | |
| 710 | ||
| 653 | 711 | pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { |
| 654 | 712 | const tracy = trace(@src()); |
| 655 | 713 | defer tracy.end(); |
src/link/MachO/Object.zig+189-203| ... | ... | @@ -176,6 +176,13 @@ pub fn free(self: *Object, allocator: Allocator, macho_file: *MachO) void { |
| 176 | 176 | .n_desc = 0, |
| 177 | 177 | .n_value = 0, |
| 178 | 178 | }; |
| 179 | _ = macho_file.atom_by_index_table.remove(atom.local_sym_index); | |
| 180 | _ = macho_file.gc_roots.remove(atom); | |
| 181 | ||
| 182 | for (atom.contained.items) |sym_off| { | |
| 183 | _ = macho_file.atom_by_index_table.remove(sym_off.local_sym_index); | |
| 184 | } | |
| 185 | ||
| 179 | 186 | atom.local_sym_index = 0; |
| 180 | 187 | } |
| 181 | 188 | if (atom == last_atom) { |
| ... | ... | @@ -346,7 +353,7 @@ const NlistWithIndex = struct { |
| 346 | 353 | } |
| 347 | 354 | } |
| 348 | 355 | |
| 349 | fn filterInSection(symbols: []NlistWithIndex, sect: macho.section_64) []NlistWithIndex { | |
| 356 | fn filterByAddress(symbols: []NlistWithIndex, start_addr: u64, end_addr: u64) []NlistWithIndex { | |
| 350 | 357 | const Predicate = struct { |
| 351 | 358 | addr: u64, |
| 352 | 359 | |
| ... | ... | @@ -355,13 +362,36 @@ const NlistWithIndex = struct { |
| 355 | 362 | } |
| 356 | 363 | }; |
| 357 | 364 | |
| 358 | const start = MachO.findFirst(NlistWithIndex, symbols, 0, Predicate{ .addr = sect.addr }); | |
| 359 | const end = MachO.findFirst(NlistWithIndex, symbols, start, Predicate{ .addr = sect.addr + sect.size }); | |
| 365 | const start = MachO.findFirst(NlistWithIndex, symbols, 0, Predicate{ | |
| 366 | .addr = start_addr, | |
| 367 | }); | |
| 368 | const end = MachO.findFirst(NlistWithIndex, symbols, start, Predicate{ | |
| 369 | .addr = end_addr, | |
| 370 | }); | |
| 360 | 371 | |
| 361 | 372 | return symbols[start..end]; |
| 362 | 373 | } |
| 363 | 374 | }; |
| 364 | 375 | |
| 376 | fn filterRelocs( | |
| 377 | relocs: []const macho.relocation_info, | |
| 378 | start_addr: u64, | |
| 379 | end_addr: u64, | |
| 380 | ) []const macho.relocation_info { | |
| 381 | const Predicate = struct { | |
| 382 | addr: u64, | |
| 383 | ||
| 384 | pub fn predicate(self: @This(), rel: macho.relocation_info) bool { | |
| 385 | return rel.r_address < self.addr; | |
| 386 | } | |
| 387 | }; | |
| 388 | ||
| 389 | const start = MachO.findFirst(macho.relocation_info, relocs, 0, Predicate{ .addr = end_addr }); | |
| 390 | const end = MachO.findFirst(macho.relocation_info, relocs, start, Predicate{ .addr = start_addr }); | |
| 391 | ||
| 392 | return relocs[start..end]; | |
| 393 | } | |
| 394 | ||
| 365 | 395 | fn filterDice( |
| 366 | 396 | dices: []const macho.data_in_code_entry, |
| 367 | 397 | start_addr: u64, |
| ... | ... | @@ -422,16 +452,13 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) ! |
| 422 | 452 | // We only care about defined symbols, so filter every other out. |
| 423 | 453 | const sorted_nlists = sorted_all_nlists.items[0..iundefsym]; |
| 424 | 454 | |
| 425 | const dead_strip = blk: { | |
| 426 | const dead_strip = macho_file.base.options.gc_sections orelse break :blk false; | |
| 427 | if (dead_strip or macho_file.base.options.optimize_mode != .Debug) | |
| 428 | break :blk self.header.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0; | |
| 429 | break :blk false; | |
| 430 | }; | |
| 455 | const dead_strip = macho_file.base.options.gc_sections orelse false; | |
| 456 | const subsections_via_symbols = self.header.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0 and | |
| 457 | (macho_file.base.options.optimize_mode != .Debug or dead_strip); | |
| 431 | 458 | |
| 432 | 459 | for (seg.sections.items) |sect, id| { |
| 433 | 460 | const sect_id = @intCast(u8, id); |
| 434 | log.debug("putting section '{s},{s}' as an Atom", .{ sect.segName(), sect.sectName() }); | |
| 461 | log.debug("parsing section '{s},{s}' into Atoms", .{ sect.segName(), sect.sectName() }); | |
| 435 | 462 | |
| 436 | 463 | // Get matching segment/section in the final artifact. |
| 437 | 464 | const match = (try macho_file.getMatchingSection(sect)) orelse { |
| ... | ... | @@ -455,7 +482,11 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) ! |
| 455 | 482 | ); |
| 456 | 483 | |
| 457 | 484 | // Symbols within this section only. |
| 458 | const filtered_nlists = NlistWithIndex.filterInSection(sorted_nlists, sect); | |
| 485 | const filtered_nlists = NlistWithIndex.filterByAddress( | |
| 486 | sorted_nlists, | |
| 487 | sect.addr, | |
| 488 | sect.addr + sect.size, | |
| 489 | ); | |
| 459 | 490 | |
| 460 | 491 | macho_file.has_dices = macho_file.has_dices or blk: { |
| 461 | 492 | if (self.text_section_index) |index| { |
| ... | ... | @@ -467,204 +498,123 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) ! |
| 467 | 498 | }; |
| 468 | 499 | macho_file.has_stabs = macho_file.has_stabs or self.debug_info != null; |
| 469 | 500 | |
| 470 | if (dead_strip) blk: { | |
| 471 | if (filtered_nlists.len == 0) break :blk; // nothing to split | |
| 472 | ||
| 501 | if (subsections_via_symbols and filtered_nlists.len > 0) { | |
| 473 | 502 | // If the first nlist does not match the start of the section, |
| 474 | 503 | // then we need to encapsulate the memory range [section start, first symbol) |
| 475 | 504 | // as a temporary symbol and insert the matching Atom. |
| 476 | 505 | const first_nlist = filtered_nlists[0].nlist; |
| 477 | if (first_nlist.n_value > sect.addr) {} | |
| 478 | } | |
| 479 | ||
| 480 | // If there is no symbol to refer to this atom, we create | |
| 481 | // a temp one, unless we already did that when working out the relocations | |
| 482 | // of other atoms. | |
| 483 | const local_sym_index = self.sections_as_symbols.get(sect_id) orelse blk: { | |
| 484 | const local_sym_index = @intCast(u32, macho_file.locals.items.len); | |
| 485 | try macho_file.locals.append(allocator, .{ | |
| 486 | .n_strx = 0, | |
| 487 | .n_type = macho.N_SECT, | |
| 488 | .n_sect = @intCast(u8, macho_file.section_ordinals.getIndex(match).? + 1), | |
| 489 | .n_desc = 0, | |
| 490 | .n_value = sect.addr, | |
| 491 | }); | |
| 492 | try self.sections_as_symbols.putNoClobber(allocator, sect_id, local_sym_index); | |
| 493 | break :blk local_sym_index; | |
| 494 | }; | |
| 495 | const atom = try self.parseIntoAtom( | |
| 496 | allocator, | |
| 497 | local_sym_index, | |
| 498 | sect.size, | |
| 499 | sect.@"align", | |
| 500 | code, | |
| 501 | relocs, | |
| 502 | filtered_nlists, | |
| 503 | match, | |
| 504 | macho_file, | |
| 505 | ); | |
| 506 | ||
| 507 | if (!self.start_atoms.contains(match)) { | |
| 508 | try self.start_atoms.putNoClobber(allocator, match, atom); | |
| 509 | } | |
| 506 | if (first_nlist.n_value > sect.addr) { | |
| 507 | const local_sym_index = self.sections_as_symbols.get(sect_id) orelse blk: { | |
| 508 | const local_sym_index = @intCast(u32, macho_file.locals.items.len); | |
| 509 | try macho_file.locals.append(allocator, .{ | |
| 510 | .n_strx = 0, | |
| 511 | .n_type = macho.N_SECT, | |
| 512 | .n_sect = @intCast(u8, macho_file.section_ordinals.getIndex(match).? + 1), | |
| 513 | .n_desc = 0, | |
| 514 | .n_value = sect.addr, | |
| 515 | }); | |
| 516 | try self.sections_as_symbols.putNoClobber(allocator, sect_id, local_sym_index); | |
| 517 | break :blk local_sym_index; | |
| 518 | }; | |
| 519 | const atom_size = first_nlist.n_value - sect.addr; | |
| 520 | const atom_code: ?[]const u8 = if (code) |cc| | |
| 521 | cc[0..atom_size] | |
| 522 | else | |
| 523 | null; | |
| 524 | try self.parseIntoAtom( | |
| 525 | allocator, | |
| 526 | local_sym_index, | |
| 527 | atom_size, | |
| 528 | sect.@"align", | |
| 529 | atom_code, | |
| 530 | relocs, | |
| 531 | &.{}, | |
| 532 | match, | |
| 533 | sect, | |
| 534 | macho_file, | |
| 535 | ); | |
| 536 | } | |
| 510 | 537 | |
| 511 | if (self.end_atoms.getPtr(match)) |last| { | |
| 512 | last.*.next = atom; | |
| 513 | atom.prev = last.*; | |
| 514 | last.* = atom; | |
| 538 | var next_nlist_count: usize = 0; | |
| 539 | while (next_nlist_count < filtered_nlists.len) { | |
| 540 | const next_nlist = filtered_nlists[next_nlist_count]; | |
| 541 | const addr = next_nlist.nlist.n_value; | |
| 542 | const atom_nlists = NlistWithIndex.filterByAddress( | |
| 543 | filtered_nlists[next_nlist_count..], | |
| 544 | addr, | |
| 545 | addr + 1, | |
| 546 | ); | |
| 547 | next_nlist_count += atom_nlists.len; | |
| 548 | ||
| 549 | const local_sym_index = @intCast(u32, macho_file.locals.items.len); | |
| 550 | try macho_file.locals.append(allocator, .{ | |
| 551 | .n_strx = 0, | |
| 552 | .n_type = macho.N_SECT, | |
| 553 | .n_sect = @intCast(u8, macho_file.section_ordinals.getIndex(match).? + 1), | |
| 554 | .n_desc = 0, | |
| 555 | .n_value = addr, | |
| 556 | }); | |
| 557 | ||
| 558 | const atom_size = blk: { | |
| 559 | const end_addr = if (next_nlist_count < filtered_nlists.len) | |
| 560 | filtered_nlists[next_nlist_count].nlist.n_value | |
| 561 | else | |
| 562 | sect.addr + sect.size; | |
| 563 | break :blk end_addr - addr; | |
| 564 | }; | |
| 565 | const atom_code: ?[]const u8 = if (code) |cc| | |
| 566 | cc[addr - sect.addr ..][0..atom_size] | |
| 567 | else | |
| 568 | null; | |
| 569 | const atom_align = if (addr > 0) | |
| 570 | math.min(@ctz(u64, addr), sect.@"align") | |
| 571 | else | |
| 572 | sect.@"align"; | |
| 573 | try self.parseIntoAtom( | |
| 574 | allocator, | |
| 575 | local_sym_index, | |
| 576 | atom_size, | |
| 577 | atom_align, | |
| 578 | atom_code, | |
| 579 | relocs, | |
| 580 | atom_nlists, | |
| 581 | match, | |
| 582 | sect, | |
| 583 | macho_file, | |
| 584 | ); | |
| 585 | } | |
| 515 | 586 | } else { |
| 516 | try self.end_atoms.putNoClobber(allocator, match, atom); | |
| 587 | // If there is no symbol to refer to this atom, we create | |
| 588 | // a temp one, unless we already did that when working out the relocations | |
| 589 | // of other atoms. | |
| 590 | const local_sym_index = self.sections_as_symbols.get(sect_id) orelse blk: { | |
| 591 | const local_sym_index = @intCast(u32, macho_file.locals.items.len); | |
| 592 | try macho_file.locals.append(allocator, .{ | |
| 593 | .n_strx = 0, | |
| 594 | .n_type = macho.N_SECT, | |
| 595 | .n_sect = @intCast(u8, macho_file.section_ordinals.getIndex(match).? + 1), | |
| 596 | .n_desc = 0, | |
| 597 | .n_value = sect.addr, | |
| 598 | }); | |
| 599 | try self.sections_as_symbols.putNoClobber(allocator, sect_id, local_sym_index); | |
| 600 | break :blk local_sym_index; | |
| 601 | }; | |
| 602 | try self.parseIntoAtom( | |
| 603 | allocator, | |
| 604 | local_sym_index, | |
| 605 | sect.size, | |
| 606 | sect.@"align", | |
| 607 | code, | |
| 608 | relocs, | |
| 609 | filtered_nlists, | |
| 610 | match, | |
| 611 | sect, | |
| 612 | macho_file, | |
| 613 | ); | |
| 517 | 614 | } |
| 518 | try self.contained_atoms.append(allocator, atom); | |
| 519 | 615 | } |
| 520 | 616 | } |
| 521 | 617 | |
| 522 | // const Context = struct { | |
| 523 | // allocator: *Allocator, | |
| 524 | // object: *Object, | |
| 525 | // macho_file: *MachO, | |
| 526 | // match: MachO.MatchingSection, | |
| 527 | // }; | |
| 528 | ||
| 529 | // const AtomParser = struct { | |
| 530 | // section: macho.section_64, | |
| 531 | // code: []u8, | |
| 532 | // relocs: []macho.relocation_info, | |
| 533 | // nlists: []NlistWithIndex, | |
| 534 | // index: u32 = 0, | |
| 535 | ||
| 536 | // fn peek(self: AtomParser) ?NlistWithIndex { | |
| 537 | // return if (self.index + 1 < self.nlists.len) self.nlists[self.index + 1] else null; | |
| 538 | // } | |
| 539 | ||
| 540 | // fn lessThanBySeniority(context: Context, lhs: NlistWithIndex, rhs: NlistWithIndex) bool { | |
| 541 | // if (!MachO.symbolIsExt(rhs.nlist)) { | |
| 542 | // return MachO.symbolIsTemp(lhs.nlist, context.object.getString(lhs.nlist.n_strx)); | |
| 543 | // } else if (MachO.symbolIsPext(rhs.nlist) or MachO.symbolIsWeakDef(rhs.nlist)) { | |
| 544 | // return !MachO.symbolIsExt(lhs.nlist); | |
| 545 | // } else { | |
| 546 | // return false; | |
| 547 | // } | |
| 548 | // } | |
| 549 | ||
| 550 | // pub fn next(self: *AtomParser, context: Context) !?*Atom { | |
| 551 | // if (self.index == self.nlists.len) return null; | |
| 552 | ||
| 553 | // const tracy = trace(@src()); | |
| 554 | // defer tracy.end(); | |
| 555 | ||
| 556 | // var aliases = std.ArrayList(NlistWithIndex).init(context.allocator); | |
| 557 | // defer aliases.deinit(); | |
| 558 | ||
| 559 | // const next_nlist: ?NlistWithIndex = blk: while (true) { | |
| 560 | // const curr_nlist = self.nlists[self.index]; | |
| 561 | // try aliases.append(curr_nlist); | |
| 562 | ||
| 563 | // if (self.peek()) |next_nlist| { | |
| 564 | // if (curr_nlist.nlist.n_value == next_nlist.nlist.n_value) { | |
| 565 | // self.index += 1; | |
| 566 | // continue; | |
| 567 | // } | |
| 568 | // break :blk next_nlist; | |
| 569 | // } | |
| 570 | // break :blk null; | |
| 571 | // } else null; | |
| 572 | ||
| 573 | // for (aliases.items) |*nlist_with_index| { | |
| 574 | // nlist_with_index.index = context.object.symbol_mapping.get(nlist_with_index.index) orelse unreachable; | |
| 575 | // } | |
| 576 | ||
| 577 | // if (aliases.items.len > 1) { | |
| 578 | // // Bubble-up senior symbol as the main link to the atom. | |
| 579 | // sort.sort( | |
| 580 | // NlistWithIndex, | |
| 581 | // aliases.items, | |
| 582 | // context, | |
| 583 | // AtomParser.lessThanBySeniority, | |
| 584 | // ); | |
| 585 | // } | |
| 586 | ||
| 587 | // const senior_nlist = aliases.pop(); | |
| 588 | // const senior_sym = &context.macho_file.locals.items[senior_nlist.index]; | |
| 589 | // senior_sym.n_sect = @intCast(u8, context.macho_file.section_ordinals.getIndex(context.match).? + 1); | |
| 590 | ||
| 591 | // const start_addr = senior_nlist.nlist.n_value - self.section.addr; | |
| 592 | // const end_addr = if (next_nlist) |n| n.nlist.n_value - self.section.addr else self.section.size; | |
| 593 | ||
| 594 | // const code = self.code[start_addr..end_addr]; | |
| 595 | // const size = code.len; | |
| 596 | ||
| 597 | // const max_align = self.section.@"align"; | |
| 598 | // const actual_align = if (senior_nlist.nlist.n_value > 0) | |
| 599 | // math.min(@ctz(u64, senior_nlist.nlist.n_value), max_align) | |
| 600 | // else | |
| 601 | // max_align; | |
| 602 | ||
| 603 | // const stab: ?Atom.Stab = if (context.object.debug_info) |di| blk: { | |
| 604 | // // TODO there has to be a better to handle this. | |
| 605 | // for (di.inner.func_list.items) |func| { | |
| 606 | // if (func.pc_range) |range| { | |
| 607 | // if (senior_nlist.nlist.n_value >= range.start and senior_nlist.nlist.n_value < range.end) { | |
| 608 | // break :blk Atom.Stab{ | |
| 609 | // .function = range.end - range.start, | |
| 610 | // }; | |
| 611 | // } | |
| 612 | // } | |
| 613 | // } | |
| 614 | // // TODO | |
| 615 | // // if (self.macho_file.globals.contains(self.macho_file.getString(senior_sym.strx))) break :blk .global; | |
| 616 | // break :blk .static; | |
| 617 | // } else null; | |
| 618 | ||
| 619 | // const atom = try context.macho_file.createEmptyAtom(senior_nlist.index, size, actual_align); | |
| 620 | // atom.stab = stab; | |
| 621 | ||
| 622 | // const is_zerofill = blk: { | |
| 623 | // const section_type = commands.sectionType(self.section); | |
| 624 | // break :blk section_type == macho.S_ZEROFILL or section_type == macho.S_THREAD_LOCAL_ZEROFILL; | |
| 625 | // }; | |
| 626 | // if (!is_zerofill) { | |
| 627 | // mem.copy(u8, atom.code.items, code); | |
| 628 | // } | |
| 629 | ||
| 630 | // try atom.aliases.ensureTotalCapacity(context.allocator, aliases.items.len); | |
| 631 | // for (aliases.items) |alias| { | |
| 632 | // atom.aliases.appendAssumeCapacity(alias.index); | |
| 633 | // const sym = &context.macho_file.locals.items[alias.index]; | |
| 634 | // sym.n_sect = @intCast(u8, context.macho_file.section_ordinals.getIndex(context.match).? + 1); | |
| 635 | // } | |
| 636 | ||
| 637 | // try atom.parseRelocs(self.relocs, .{ | |
| 638 | // .base_addr = self.section.addr, | |
| 639 | // .base_offset = start_addr, | |
| 640 | // .allocator = context.allocator, | |
| 641 | // .object = context.object, | |
| 642 | // .macho_file = context.macho_file, | |
| 643 | // }); | |
| 644 | ||
| 645 | // if (context.macho_file.has_dices) { | |
| 646 | // const dices = filterDice( | |
| 647 | // context.object.data_in_code_entries.items, | |
| 648 | // senior_nlist.nlist.n_value, | |
| 649 | // senior_nlist.nlist.n_value + size, | |
| 650 | // ); | |
| 651 | // try atom.dices.ensureTotalCapacity(context.allocator, dices.len); | |
| 652 | ||
| 653 | // for (dices) |dice| { | |
| 654 | // atom.dices.appendAssumeCapacity(.{ | |
| 655 | // .offset = dice.offset - try math.cast(u32, senior_nlist.nlist.n_value), | |
| 656 | // .length = dice.length, | |
| 657 | // .kind = dice.kind, | |
| 658 | // }); | |
| 659 | // } | |
| 660 | // } | |
| 661 | ||
| 662 | // self.index += 1; | |
| 663 | ||
| 664 | // return atom; | |
| 665 | // } | |
| 666 | // }; | |
| 667 | ||
| 668 | 618 | fn parseIntoAtom( |
| 669 | 619 | self: *Object, |
| 670 | 620 | allocator: Allocator, |
| ... | ... | @@ -675,8 +625,9 @@ fn parseIntoAtom( |
| 675 | 625 | relocs: []const macho.relocation_info, |
| 676 | 626 | nlists: []const NlistWithIndex, |
| 677 | 627 | match: MatchingSection, |
| 628 | sect: macho.section_64, | |
| 678 | 629 | macho_file: *MachO, |
| 679 | ) !*Atom { | |
| 630 | ) !void { | |
| 680 | 631 | const sym = macho_file.locals.items[local_sym_index]; |
| 681 | 632 | const align_pow_2 = try math.powi(u32, 2, alignment); |
| 682 | 633 | const aligned_size = mem.alignForwardGeneric(u64, size, align_pow_2); |
| ... | ... | @@ -686,8 +637,11 @@ fn parseIntoAtom( |
| 686 | 637 | mem.copy(u8, atom.code.items, cc); |
| 687 | 638 | } |
| 688 | 639 | |
| 689 | try atom.parseRelocs(relocs, .{ | |
| 690 | .base_addr = sym.n_value, | |
| 640 | const base_offset = sym.n_value - sect.addr; | |
| 641 | const filtered_relocs = filterRelocs(relocs, base_offset, base_offset + size); | |
| 642 | try atom.parseRelocs(filtered_relocs, .{ | |
| 643 | .base_addr = sect.addr, | |
| 644 | .base_offset = @intCast(i32, base_offset), | |
| 691 | 645 | .allocator = allocator, |
| 692 | 646 | .object = self, |
| 693 | 647 | .macho_file = macho_file, |
| ... | ... | @@ -740,9 +694,41 @@ fn parseIntoAtom( |
| 740 | 694 | .offset = nlist.n_value - sym.n_value, |
| 741 | 695 | .stab = stab, |
| 742 | 696 | }); |
| 697 | ||
| 698 | try macho_file.atom_by_index_table.putNoClobber(allocator, sym_index, atom); | |
| 743 | 699 | } |
| 744 | 700 | |
| 745 | return atom; | |
| 701 | const is_gc_root = blk: { | |
| 702 | if (sect.isDontDeadStrip()) break :blk true; | |
| 703 | if (sect.isDontDeadStripIfReferencesLive()) { | |
| 704 | // TODO if isDontDeadStripIfReferencesLive we should analyse the edges | |
| 705 | // before making it a GC root | |
| 706 | break :blk true; | |
| 707 | } | |
| 708 | if (mem.eql(u8, "__StaticInit", sect.sectName())) break :blk true; | |
| 709 | switch (sect.type_()) { | |
| 710 | macho.S_MOD_INIT_FUNC_POINTERS, | |
| 711 | macho.S_MOD_TERM_FUNC_POINTERS, | |
| 712 | => break :blk true, | |
| 713 | else => break :blk false, | |
| 714 | } | |
| 715 | }; | |
| 716 | if (is_gc_root) { | |
| 717 | try macho_file.gc_roots.putNoClobber(allocator, atom, {}); | |
| 718 | } | |
| 719 | ||
| 720 | if (!self.start_atoms.contains(match)) { | |
| 721 | try self.start_atoms.putNoClobber(allocator, match, atom); | |
| 722 | } | |
| 723 | ||
| 724 | if (self.end_atoms.getPtr(match)) |last| { | |
| 725 | last.*.next = atom; | |
| 726 | atom.prev = last.*; | |
| 727 | last.* = atom; | |
| 728 | } else { | |
| 729 | try self.end_atoms.putNoClobber(allocator, match, atom); | |
| 730 | } | |
| 731 | try self.contained_atoms.append(allocator, atom); | |
| 746 | 732 | } |
| 747 | 733 | |
| 748 | 734 | fn parseSymtab(self: *Object) void { |
test/link/macho/objcpp/build.zig+1| ... | ... | @@ -16,6 +16,7 @@ pub fn build(b: *Builder) void { |
| 16 | 16 | // TODO when we figure out how to ship framework stubs for cross-compilation, |
| 17 | 17 | // populate paths to the sysroot here. |
| 18 | 18 | exe.linkFramework("Foundation"); |
| 19 | exe.link_gc_sections = true; | |
| 19 | 20 | |
| 20 | 21 | const run_cmd = exe.run(); |
| 21 | 22 | run_cmd.expectStdOutEqual("Hello from C++ and Zig"); |