| ... | ... | @@ -171,17 +171,19 @@ stub_helper_preamble_atom: ?*Atom = null, |
| 171 | 171 | |
| 172 | 172 | strtab: StringTable(.strtab) = .{}, |
| 173 | 173 | |
| 174 | // TODO I think synthetic tables are a perfect match for some generic refactoring, |
| 175 | // and probably reusable between linker backends too. |
| 174 | 176 | tlv_ptr_entries: std.ArrayListUnmanaged(Entry) = .{}, |
| 175 | 177 | tlv_ptr_entries_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 176 | | tlv_ptr_entries_table: std.AutoArrayHashMapUnmanaged(SymbolWithLoc, u32) = .{}, |
| 178 | tlv_ptr_entries_table: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{}, |
| 177 | 179 | |
| 178 | 180 | got_entries: std.ArrayListUnmanaged(Entry) = .{}, |
| 179 | 181 | got_entries_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 180 | | got_entries_table: std.AutoArrayHashMapUnmanaged(SymbolWithLoc, u32) = .{}, |
| 182 | got_entries_table: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{}, |
| 181 | 183 | |
| 182 | 184 | stubs: std.ArrayListUnmanaged(Entry) = .{}, |
| 183 | 185 | stubs_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 184 | | stubs_table: std.AutoArrayHashMapUnmanaged(SymbolWithLoc, u32) = .{}, |
| 186 | stubs_table: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{}, |
| 185 | 187 | |
| 186 | 188 | error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 187 | 189 | |
| ... | ... | @@ -251,7 +253,24 @@ decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, ?MatchingSection) = .{}, |
| 251 | 253 | |
| 252 | 254 | const Entry = struct { |
| 253 | 255 | target: SymbolWithLoc, |
| 254 | | atom: *Atom, |
| 256 | // Index into the synthetic symbol table (i.e., file == null). |
| 257 | sym_index: u32, |
| 258 | |
| 259 | pub fn getSymbol(entry: Entry, macho_file: *MachO) macho.nlist_64 { |
| 260 | return macho_file.getSymbol(.{ .sym_index = entry.sym_index, .file = null }); |
| 261 | } |
| 262 | |
| 263 | pub fn getSymbolPtr(entry: Entry, macho_file: *MachO) *macho.nlist_64 { |
| 264 | return macho_file.getSymbolPtr(.{ .sym_index = entry.sym_index, .file = null }); |
| 265 | } |
| 266 | |
| 267 | pub fn getAtom(entry: Entry, macho_file: *MachO) *Atom { |
| 268 | return macho_file.getAtomForSymbol(.{ .sym_index = entry.sym_index, .file = null }).?; |
| 269 | } |
| 270 | |
| 271 | pub fn getName(entry: Entry, macho_file: *MachO) []const u8 { |
| 272 | return macho_file.getSymbolName(.{ .sym_index = entry.sym_index, .file = null }); |
| 273 | } |
| 255 | 274 | }; |
| 256 | 275 | |
| 257 | 276 | const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(*Atom)); |
| ... | ... | @@ -1652,6 +1671,15 @@ fn parseDependentLibs(self: *MachO, syslibroot: ?[]const u8, dependent_libs: any |
| 1652 | 1671 | pub const MatchingSection = struct { |
| 1653 | 1672 | seg: u16, |
| 1654 | 1673 | sect: u16, |
| 1674 | |
| 1675 | pub fn eql(this: MatchingSection, other: struct { |
| 1676 | seg: ?u16, |
| 1677 | sect: ?u16, |
| 1678 | }) bool { |
| 1679 | const seg = other.seg orelse return false; |
| 1680 | const sect = other.sect orelse return false; |
| 1681 | return this.seg == seg and this.sect == sect; |
| 1682 | } |
| 1655 | 1683 | }; |
| 1656 | 1684 | |
| 1657 | 1685 | pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSection { |
| ... | ... | @@ -3153,8 +3181,7 @@ fn resolveSymbolsInDylibs(self: *MachO) !void { |
| 3153 | 3181 | const stub_helper_atom = try self.createStubHelperAtom(); |
| 3154 | 3182 | const laptr_atom = try self.createLazyPointerAtom(stub_helper_atom.sym_index, global); |
| 3155 | 3183 | const stub_atom = try self.createStubAtom(laptr_atom.sym_index); |
| 3156 | | |
| 3157 | | self.stubs.items[stub_index].atom = stub_atom; |
| 3184 | self.stubs.items[stub_index].sym_index = stub_atom.sym_index; |
| 3158 | 3185 | } |
| 3159 | 3186 | |
| 3160 | 3187 | continue :loop; |
| ... | ... | @@ -3251,7 +3278,7 @@ fn resolveDyldStubBinder(self: *MachO) !void { |
| 3251 | 3278 | // Add dyld_stub_binder as the final GOT entry. |
| 3252 | 3279 | const got_index = try self.allocateGotEntry(global); |
| 3253 | 3280 | const got_atom = try self.createGotAtom(global); |
| 3254 | | self.got_entries.items[got_index].atom = got_atom; |
| 3281 | self.got_entries.items[got_index].sym_index = got_atom.sym_index; |
| 3255 | 3282 | } |
| 3256 | 3283 | |
| 3257 | 3284 | fn addLoadDylibLC(self: *MachO, id: u16) !void { |
| ... | ... | @@ -3288,11 +3315,7 @@ fn setEntryPoint(self: *MachO) !void { |
| 3288 | 3315 | if (self.base.options.output_mode != .Exe) return; |
| 3289 | 3316 | |
| 3290 | 3317 | const seg = self.load_commands.items[self.text_segment_cmd_index.?].segment; |
| 3291 | | const global = self.getEntryPoint() orelse { |
| 3292 | | const name = self.base.options.entry orelse "_main"; |
| 3293 | | log.err("entrypoint '{s}' not found", .{name}); |
| 3294 | | return error.MissingMainEntrypoint; |
| 3295 | | }; |
| 3318 | const global = try self.getEntryPoint(); |
| 3296 | 3319 | const sym = self.getSymbol(global); |
| 3297 | 3320 | const ec = &self.load_commands.items[self.main_cmd_index.?].main; |
| 3298 | 3321 | ec.entryoff = @intCast(u32, sym.n_value - seg.inner.vmaddr); |
| ... | ... | @@ -3508,7 +3531,8 @@ fn allocateSymbol(self: *MachO) !u32 { |
| 3508 | 3531 | } |
| 3509 | 3532 | |
| 3510 | 3533 | pub fn allocateGotEntry(self: *MachO, target: SymbolWithLoc) !u32 { |
| 3511 | | try self.got_entries.ensureUnusedCapacity(self.base.allocator, 1); |
| 3534 | const gpa = self.base.allocator; |
| 3535 | try self.got_entries.ensureUnusedCapacity(gpa, 1); |
| 3512 | 3536 | |
| 3513 | 3537 | const index = blk: { |
| 3514 | 3538 | if (self.got_entries_free_list.popOrNull()) |index| { |
| ... | ... | @@ -3522,8 +3546,8 @@ pub fn allocateGotEntry(self: *MachO, target: SymbolWithLoc) !u32 { |
| 3522 | 3546 | } |
| 3523 | 3547 | }; |
| 3524 | 3548 | |
| 3525 | | self.got_entries.items[index] = .{ .target = target, .atom = undefined }; |
| 3526 | | try self.got_entries_table.putNoClobber(self.base.allocator, target, index); |
| 3549 | self.got_entries.items[index] = .{ .target = target, .sym_index = 0 }; |
| 3550 | try self.got_entries_table.putNoClobber(gpa, target, index); |
| 3527 | 3551 | |
| 3528 | 3552 | return index; |
| 3529 | 3553 | } |
| ... | ... | @@ -3543,7 +3567,7 @@ pub fn allocateStubEntry(self: *MachO, target: SymbolWithLoc) !u32 { |
| 3543 | 3567 | } |
| 3544 | 3568 | }; |
| 3545 | 3569 | |
| 3546 | | self.stubs.items[index] = .{ .target = target, .atom = undefined }; |
| 3570 | self.stubs.items[index] = .{ .target = target, .sym_index = 0 }; |
| 3547 | 3571 | try self.stubs_table.putNoClobber(self.base.allocator, target, index); |
| 3548 | 3572 | |
| 3549 | 3573 | return index; |
| ... | ... | @@ -3564,7 +3588,7 @@ pub fn allocateTlvPtrEntry(self: *MachO, target: SymbolWithLoc) !u32 { |
| 3564 | 3588 | } |
| 3565 | 3589 | }; |
| 3566 | 3590 | |
| 3567 | | self.tlv_ptr_entries.items[index] = .{ .target = target, .atom = undefined }; |
| 3591 | self.tlv_ptr_entries.items[index] = .{ .target = target, .sym_index = 0 }; |
| 3568 | 3592 | try self.tlv_ptr_entries_table.putNoClobber(self.base.allocator, target, index); |
| 3569 | 3593 | |
| 3570 | 3594 | return index; |
| ... | ... | @@ -4029,7 +4053,7 @@ fn placeDecl(self: *MachO, decl_index: Module.Decl.Index, code_len: usize) !*mac |
| 4029 | 4053 | const got_target = SymbolWithLoc{ .sym_index = decl.link.macho.sym_index, .file = null }; |
| 4030 | 4054 | const got_index = try self.allocateGotEntry(got_target); |
| 4031 | 4055 | const got_atom = try self.createGotAtom(got_target); |
| 4032 | | self.got_entries.items[got_index].atom = got_atom; |
| 4056 | self.got_entries.items[got_index].sym_index = got_atom.sym_index; |
| 4033 | 4057 | } |
| 4034 | 4058 | |
| 4035 | 4059 | return symbol; |
| ... | ... | @@ -4219,9 +4243,9 @@ pub fn freeDecl(self: *MachO, decl_index: Module.Decl.Index) void { |
| 4219 | 4243 | self.got_entries_free_list.append(self.base.allocator, @intCast(u32, got_index)) catch {}; |
| 4220 | 4244 | self.got_entries.items[got_index] = .{ |
| 4221 | 4245 | .target = .{ .sym_index = 0, .file = null }, |
| 4222 | | .atom = undefined, |
| 4246 | .sym_index = 0, |
| 4223 | 4247 | }; |
| 4224 | | _ = self.got_entries_table.swapRemove(got_target); |
| 4248 | _ = self.got_entries_table.remove(got_target); |
| 4225 | 4249 | |
| 4226 | 4250 | if (self.d_sym) |*d_sym| { |
| 4227 | 4251 | d_sym.swapRemoveRelocs(decl.link.macho.sym_index); |
| ... | ... | @@ -5493,46 +5517,26 @@ fn gcAtoms(self: *MachO, gc_roots: *std.AutoHashMap(*Atom, void)) !void { |
| 5493 | 5517 | |
| 5494 | 5518 | if (self.base.options.output_mode == .Exe) { |
| 5495 | 5519 | // Add entrypoint as GC root |
| 5496 | | if (self.getEntryPoint()) |global| { |
| 5497 | | if (self.getAtomForSymbol(global)) |gc_root| { |
| 5498 | | _ = try gc_roots.getOrPut(gc_root); |
| 5499 | | } else { |
| 5500 | | log.debug("skipping {s}", .{self.getSymbolName(global)}); |
| 5501 | | } |
| 5502 | | } |
| 5520 | const global = try self.getEntryPoint(); |
| 5521 | const atom = self.getAtomForSymbol(global).?; // panic here means fatal error |
| 5522 | _ = try gc_roots.getOrPut(atom); |
| 5503 | 5523 | } else { |
| 5504 | 5524 | assert(self.base.options.output_mode == .Lib); |
| 5505 | 5525 | // Add exports as GC roots |
| 5506 | 5526 | for (self.globals.values()) |global| { |
| 5507 | 5527 | const sym = self.getSymbol(global); |
| 5508 | 5528 | if (!sym.sect()) continue; |
| 5509 | | const gc_root = self.getAtomForSymbol(global) orelse { |
| 5529 | const atom = self.getAtomForSymbol(global) orelse { |
| 5510 | 5530 | log.debug("skipping {s}", .{self.getSymbolName(global)}); |
| 5511 | 5531 | continue; |
| 5512 | 5532 | }; |
| 5513 | | _ = try gc_roots.getOrPut(gc_root); |
| 5533 | _ = try gc_roots.getOrPut(atom); |
| 5514 | 5534 | } |
| 5515 | 5535 | } |
| 5516 | | |
| 5517 | | // Add any atom targeting an import as GC root |
| 5518 | | var atoms_it = self.atoms.iterator(); |
| 5519 | | while (atoms_it.next()) |entry| { |
| 5520 | | var atom = entry.value_ptr.*; |
| 5521 | | |
| 5522 | | while (true) { |
| 5523 | | for (atom.relocs.items) |rel| { |
| 5524 | | if ((try rel.getTargetAtom(self)) == null) { |
| 5525 | | const target_sym = self.getSymbol(rel.target); |
| 5526 | | if (target_sym.undf()) { |
| 5527 | | _ = try gc_roots.getOrPut(atom); |
| 5528 | | break; |
| 5529 | | } |
| 5530 | | } |
| 5531 | | } |
| 5532 | | |
| 5533 | | if (atom.prev) |prev| { |
| 5534 | | atom = prev; |
| 5535 | | } else break; |
| 5536 | // TODO just a temp until we learn how to parse unwind records |
| 5537 | if (self.globals.get("___gxx_personality_v0")) |global| { |
| 5538 | if (self.getAtomForSymbol(global)) |atom| { |
| 5539 | _ = try gc_roots.getOrPut(atom); |
| 5536 | 5540 | } |
| 5537 | 5541 | } |
| 5538 | 5542 | |
| ... | ... | @@ -5540,80 +5544,80 @@ fn gcAtoms(self: *MachO, gc_roots: *std.AutoHashMap(*Atom, void)) !void { |
| 5540 | 5544 | defer stack.deinit(); |
| 5541 | 5545 | try stack.ensureUnusedCapacity(gc_roots.count()); |
| 5542 | 5546 | |
| 5543 | | var retained = std.AutoHashMap(*Atom, void).init(gpa); |
| 5544 | | defer retained.deinit(); |
| 5545 | | try retained.ensureUnusedCapacity(gc_roots.count()); |
| 5547 | var alive = std.AutoHashMap(*Atom, void).init(gpa); |
| 5548 | defer alive.deinit(); |
| 5549 | try alive.ensureUnusedCapacity(gc_roots.count()); |
| 5546 | 5550 | |
| 5547 | 5551 | log.debug("GC roots:", .{}); |
| 5548 | 5552 | var gc_roots_it = gc_roots.keyIterator(); |
| 5549 | 5553 | while (gc_roots_it.next()) |gc_root| { |
| 5550 | 5554 | self.logAtom(gc_root.*); |
| 5551 | | |
| 5552 | 5555 | stack.appendAssumeCapacity(gc_root.*); |
| 5553 | | retained.putAssumeCapacityNoClobber(gc_root.*, {}); |
| 5556 | alive.putAssumeCapacity(gc_root.*, {}); |
| 5554 | 5557 | } |
| 5555 | 5558 | |
| 5556 | | log.debug("walking tree...", .{}); |
| 5557 | 5559 | while (stack.popOrNull()) |source_atom| { |
| 5558 | 5560 | for (source_atom.relocs.items) |rel| { |
| 5559 | | if (try rel.getTargetAtom(self)) |target_atom| { |
| 5560 | | const gop = try retained.getOrPut(target_atom); |
| 5561 | if (rel.getTargetAtom(self)) |target_atom| { |
| 5562 | const gop = try alive.getOrPut(target_atom); |
| 5561 | 5563 | if (!gop.found_existing) { |
| 5562 | | log.debug(" RETAINED ATOM(%{d}) -> ATOM(%{d})", .{ |
| 5563 | | source_atom.sym_index, |
| 5564 | log.debug(" retained ATOM(%{d}, '{s}') in object({d})", .{ |
| 5564 | 5565 | target_atom.sym_index, |
| 5566 | target_atom.getName(self), |
| 5567 | target_atom.file, |
| 5568 | }); |
| 5569 | log.debug(" referenced by ATOM(%{d}, '{s}') in object({d})", .{ |
| 5570 | source_atom.sym_index, |
| 5571 | source_atom.getName(self), |
| 5572 | source_atom.file, |
| 5565 | 5573 | }); |
| 5566 | 5574 | try stack.append(target_atom); |
| 5567 | 5575 | } |
| 5568 | 5576 | } |
| 5569 | 5577 | } |
| 5570 | 5578 | } |
| 5579 | // TODO live support |
| 5571 | 5580 | |
| 5572 | 5581 | // Any section that ends up here will be updated, that is, |
| 5573 | 5582 | // its size and alignment recalculated. |
| 5574 | 5583 | var gc_sections = std.AutoHashMap(MatchingSection, void).init(gpa); |
| 5575 | 5584 | defer gc_sections.deinit(); |
| 5576 | 5585 | |
| 5577 | | atoms_it = self.atoms.iterator(); |
| 5578 | | while (atoms_it.next()) |entry| { |
| 5579 | | const match = entry.key_ptr.*; |
| 5580 | | |
| 5581 | | if (self.text_segment_cmd_index) |seg| { |
| 5582 | | if (seg == match.seg) { |
| 5583 | | if (self.eh_frame_section_index) |sect| { |
| 5584 | | if (sect == match.sect) continue; |
| 5585 | | } |
| 5586 | | } |
| 5587 | | } |
| 5586 | var loop: bool = true; |
| 5587 | while (loop) { |
| 5588 | loop = false; |
| 5588 | 5589 | |
| 5589 | | if (self.data_segment_cmd_index) |seg| { |
| 5590 | | if (seg == match.seg) { |
| 5591 | | if (self.rustc_section_index) |sect| { |
| 5592 | | if (sect == match.sect) continue; |
| 5593 | | } |
| 5594 | | } |
| 5595 | | } |
| 5590 | for (self.objects.items) |object| { |
| 5591 | for (object.getSourceSymtab()) |_, source_index| { |
| 5592 | const atom = object.getAtomForSymbol(@intCast(u32, source_index)) orelse continue; |
| 5593 | if (alive.contains(atom)) continue; |
| 5596 | 5594 | |
| 5597 | | const sect = self.getSectionPtr(match); |
| 5598 | | var atom = entry.value_ptr.*; |
| 5595 | const global = atom.getSymbolWithLoc(); |
| 5596 | const sym = atom.getSymbolPtr(self); |
| 5599 | 5597 | |
| 5600 | | log.debug("GCing atoms in {s},{s}", .{ sect.segName(), sect.sectName() }); |
| 5598 | if (sym.n_desc == N_DESC_GCED) continue; |
| 5599 | if (!sym.ext()) { |
| 5600 | for (atom.relocs.items) |rel| { |
| 5601 | if (rel.getTargetAtom(self)) |target_atom| { |
| 5602 | const target_sym = target_atom.getSymbol(self); |
| 5603 | if (target_sym.n_desc == N_DESC_GCED) break; |
| 5604 | } |
| 5605 | } else continue; |
| 5606 | } |
| 5601 | 5607 | |
| 5602 | | while (true) { |
| 5603 | | const orig_prev = atom.prev; |
| 5608 | loop = true; |
| 5609 | const match = self.getMatchingSectionFromOrdinal(sym.n_sect); |
| 5604 | 5610 | |
| 5605 | | if (!retained.contains(atom)) { |
| 5606 | | // Dead atom; remove. |
| 5607 | | log.debug(" DEAD ATOM(%{d})", .{atom.sym_index}); |
| 5611 | // TODO don't dedup eh_frame info yet until we actually implement parsing unwind records |
| 5612 | if (match.eql(.{ |
| 5613 | .seg = self.text_segment_cmd_index, |
| 5614 | .sect = self.eh_frame_section_index, |
| 5615 | })) continue; |
| 5608 | 5616 | |
| 5609 | | const sym = atom.getSymbolPtr(self); |
| 5617 | self.logAtom(atom); |
| 5610 | 5618 | sym.n_desc = N_DESC_GCED; |
| 5611 | | |
| 5612 | | // TODO add full bookkeeping here |
| 5613 | | const global = SymbolWithLoc{ .sym_index = atom.sym_index, .file = atom.file }; |
| 5614 | | _ = self.got_entries_table.swapRemove(global); |
| 5615 | | _ = self.stubs_table.swapRemove(global); |
| 5616 | | _ = self.tlv_ptr_entries_table.swapRemove(global); |
| 5619 | self.removeAtomFromSection(atom, match); |
| 5620 | _ = try gc_sections.put(match, {}); |
| 5617 | 5621 | |
| 5618 | 5622 | for (atom.contained.items) |sym_off| { |
| 5619 | 5623 | const inner = self.getSymbolPtr(.{ |
| ... | ... | @@ -5622,34 +5626,64 @@ fn gcAtoms(self: *MachO, gc_roots: *std.AutoHashMap(*Atom, void)) !void { |
| 5622 | 5626 | }); |
| 5623 | 5627 | inner.n_desc = N_DESC_GCED; |
| 5624 | 5628 | } |
| 5625 | | // If we want to enable GC for incremental codepath, we need to take into |
| 5626 | | // account any padding that might have been left here. |
| 5627 | | sect.size -= atom.size; |
| 5628 | 5629 | |
| 5629 | | _ = try gc_sections.put(match, {}); |
| 5630 | if (self.got_entries_table.contains(global)) { |
| 5631 | const got_atom = self.getGotAtomForSymbol(global).?; |
| 5632 | const got_sym = got_atom.getSymbolPtr(self); |
| 5633 | got_sym.n_desc = N_DESC_GCED; |
| 5634 | } |
| 5630 | 5635 | |
| 5631 | | if (atom.prev) |prev| { |
| 5632 | | prev.next = atom.next; |
| 5636 | if (self.stubs_table.contains(global)) { |
| 5637 | const stubs_atom = self.getStubsAtomForSymbol(global).?; |
| 5638 | const stubs_sym = stubs_atom.getSymbolPtr(self); |
| 5639 | stubs_sym.n_desc = N_DESC_GCED; |
| 5633 | 5640 | } |
| 5634 | | if (atom.next) |next| { |
| 5635 | | next.prev = atom.prev; |
| 5636 | | } else { |
| 5637 | | if (atom.prev) |prev| { |
| 5638 | | entry.value_ptr.* = prev; |
| 5639 | | } else { |
| 5640 | | // The section will be GCed in the next step. |
| 5641 | | entry.value_ptr.* = undefined; |
| 5642 | | sect.size = 0; |
| 5643 | | } |
| 5641 | |
| 5642 | if (self.tlv_ptr_entries_table.contains(global)) { |
| 5643 | const tlv_ptr_atom = self.getTlvPtrAtomForSymbol(global).?; |
| 5644 | const tlv_ptr_sym = tlv_ptr_atom.getSymbolPtr(self); |
| 5645 | tlv_ptr_sym.n_desc = N_DESC_GCED; |
| 5644 | 5646 | } |
| 5645 | 5647 | } |
| 5646 | | |
| 5647 | | if (orig_prev) |prev| { |
| 5648 | | atom = prev; |
| 5649 | | } else break; |
| 5650 | 5648 | } |
| 5651 | 5649 | } |
| 5652 | 5650 | |
| 5651 | for (self.got_entries.items) |entry| { |
| 5652 | const sym = entry.getSymbol(self); |
| 5653 | if (sym.n_desc != N_DESC_GCED) continue; |
| 5654 | |
| 5655 | // TODO tombstone |
| 5656 | const atom = entry.getAtom(self); |
| 5657 | const match = self.getMatchingSectionFromOrdinal(sym.n_sect); |
| 5658 | self.removeAtomFromSection(atom, match); |
| 5659 | _ = try gc_sections.put(match, {}); |
| 5660 | _ = self.got_entries_table.remove(entry.target); |
| 5661 | } |
| 5662 | |
| 5663 | for (self.stubs.items) |entry| { |
| 5664 | const sym = entry.getSymbol(self); |
| 5665 | if (sym.n_desc != N_DESC_GCED) continue; |
| 5666 | |
| 5667 | // TODO tombstone |
| 5668 | const atom = entry.getAtom(self); |
| 5669 | const match = self.getMatchingSectionFromOrdinal(sym.n_sect); |
| 5670 | self.removeAtomFromSection(atom, match); |
| 5671 | _ = try gc_sections.put(match, {}); |
| 5672 | _ = self.stubs_table.remove(entry.target); |
| 5673 | } |
| 5674 | |
| 5675 | for (self.tlv_ptr_entries.items) |entry| { |
| 5676 | const sym = entry.getSymbol(self); |
| 5677 | if (sym.n_desc != N_DESC_GCED) continue; |
| 5678 | |
| 5679 | // TODO tombstone |
| 5680 | const atom = entry.getAtom(self); |
| 5681 | const match = self.getMatchingSectionFromOrdinal(sym.n_sect); |
| 5682 | self.removeAtomFromSection(atom, match); |
| 5683 | _ = try gc_sections.put(match, {}); |
| 5684 | _ = self.tlv_ptr_entries_table.remove(entry.target); |
| 5685 | } |
| 5686 | |
| 5653 | 5687 | var gc_sections_it = gc_sections.iterator(); |
| 5654 | 5688 | while (gc_sections_it.next()) |entry| { |
| 5655 | 5689 | const match = entry.key_ptr.*; |
| ... | ... | @@ -5679,6 +5713,30 @@ fn gcAtoms(self: *MachO, gc_roots: *std.AutoHashMap(*Atom, void)) !void { |
| 5679 | 5713 | } |
| 5680 | 5714 | } |
| 5681 | 5715 | |
| 5716 | fn removeAtomFromSection(self: *MachO, atom: *Atom, match: MatchingSection) void { |
| 5717 | const sect = self.getSectionPtr(match); |
| 5718 | |
| 5719 | // If we want to enable GC for incremental codepath, we need to take into |
| 5720 | // account any padding that might have been left here. |
| 5721 | sect.size -= atom.size; |
| 5722 | |
| 5723 | if (atom.prev) |prev| { |
| 5724 | prev.next = atom.next; |
| 5725 | } |
| 5726 | if (atom.next) |next| { |
| 5727 | next.prev = atom.prev; |
| 5728 | } else { |
| 5729 | const last = self.atoms.getPtr(match).?; |
| 5730 | if (atom.prev) |prev| { |
| 5731 | last.* = prev; |
| 5732 | } else { |
| 5733 | // The section will be GCed in the next step. |
| 5734 | last.* = undefined; |
| 5735 | sect.size = 0; |
| 5736 | } |
| 5737 | } |
| 5738 | } |
| 5739 | |
| 5682 | 5740 | fn updateSectionOrdinals(self: *MachO) !void { |
| 5683 | 5741 | if (!self.sections_order_dirty) return; |
| 5684 | 5742 | |
| ... | ... | @@ -5849,7 +5907,7 @@ fn writeDyldInfoData(self: *MachO) !void { |
| 5849 | 5907 | |
| 5850 | 5908 | if (self.base.options.output_mode == .Exe) { |
| 5851 | 5909 | for (&[_]SymbolWithLoc{ |
| 5852 | | self.getEntryPoint().?, // We would already errored out if no entrypoint was found. |
| 5910 | try self.getEntryPoint(), |
| 5853 | 5911 | self.globals.get("__mh_execute_header").?, |
| 5854 | 5912 | }) |global| { |
| 5855 | 5913 | const sym = self.getSymbol(global); |
| ... | ... | @@ -6337,10 +6395,13 @@ fn writeSymtab(self: *MachO) !void { |
| 6337 | 6395 | .sect = stubs_section_index, |
| 6338 | 6396 | }); |
| 6339 | 6397 | stubs.reserved1 = 0; |
| 6340 | | for (self.stubs_table.keys()) |target| { |
| 6341 | | const sym = self.getSymbol(target); |
| 6342 | | assert(sym.undf()); |
| 6343 | | try writer.writeIntLittle(u32, dysymtab.iundefsym + imports_table.get(target).?); |
| 6398 | for (self.stubs.items) |entry| { |
| 6399 | if (entry.sym_index == 0) continue; |
| 6400 | const atom_sym = entry.getSymbol(self); |
| 6401 | if (atom_sym.n_desc == N_DESC_GCED) continue; |
| 6402 | const target_sym = self.getSymbol(entry.target); |
| 6403 | assert(target_sym.undf()); |
| 6404 | try writer.writeIntLittle(u32, dysymtab.iundefsym + imports_table.get(entry.target).?); |
| 6344 | 6405 | } |
| 6345 | 6406 | } |
| 6346 | 6407 | |
| ... | ... | @@ -6351,10 +6412,13 @@ fn writeSymtab(self: *MachO) !void { |
| 6351 | 6412 | .sect = got_section_index, |
| 6352 | 6413 | }); |
| 6353 | 6414 | got.reserved1 = nstubs; |
| 6354 | | for (self.got_entries_table.keys()) |target| { |
| 6355 | | const sym = self.getSymbol(target); |
| 6356 | | if (sym.undf()) { |
| 6357 | | try writer.writeIntLittle(u32, dysymtab.iundefsym + imports_table.get(target).?); |
| 6415 | for (self.got_entries.items) |entry| { |
| 6416 | if (entry.sym_index == 0) continue; |
| 6417 | const atom_sym = entry.getSymbol(self); |
| 6418 | if (atom_sym.n_desc == N_DESC_GCED) continue; |
| 6419 | const target_sym = self.getSymbol(entry.target); |
| 6420 | if (target_sym.undf()) { |
| 6421 | try writer.writeIntLittle(u32, dysymtab.iundefsym + imports_table.get(entry.target).?); |
| 6358 | 6422 | } else { |
| 6359 | 6423 | try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL); |
| 6360 | 6424 | } |
| ... | ... | @@ -6368,10 +6432,13 @@ fn writeSymtab(self: *MachO) !void { |
| 6368 | 6432 | .sect = la_symbol_ptr_section_index, |
| 6369 | 6433 | }); |
| 6370 | 6434 | la_symbol_ptr.reserved1 = nstubs + ngot_entries; |
| 6371 | | for (self.stubs_table.keys()) |target| { |
| 6372 | | const sym = self.getSymbol(target); |
| 6373 | | assert(sym.undf()); |
| 6374 | | try writer.writeIntLittle(u32, dysymtab.iundefsym + imports_table.get(target).?); |
| 6435 | for (self.stubs.items) |entry| { |
| 6436 | if (entry.sym_index == 0) continue; |
| 6437 | const atom_sym = entry.getSymbol(self); |
| 6438 | if (atom_sym.n_desc == N_DESC_GCED) continue; |
| 6439 | const target_sym = self.getSymbol(entry.target); |
| 6440 | assert(target_sym.undf()); |
| 6441 | try writer.writeIntLittle(u32, dysymtab.iundefsym + imports_table.get(entry.target).?); |
| 6375 | 6442 | } |
| 6376 | 6443 | } |
| 6377 | 6444 | |
| ... | ... | @@ -6623,7 +6690,7 @@ pub fn getSymbolName(self: *MachO, sym_with_loc: SymbolWithLoc) []const u8 { |
| 6623 | 6690 | pub fn getAtomForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?*Atom { |
| 6624 | 6691 | if (sym_with_loc.file) |file| { |
| 6625 | 6692 | const object = self.objects.items[file]; |
| 6626 | | return object.atom_by_index_table.get(sym_with_loc.sym_index); |
| 6693 | return object.getAtomForSymbol(sym_with_loc.sym_index); |
| 6627 | 6694 | } else { |
| 6628 | 6695 | return self.atom_by_index_table.get(sym_with_loc.sym_index); |
| 6629 | 6696 | } |
| ... | ... | @@ -6633,28 +6700,32 @@ pub fn getAtomForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?*Atom { |
| 6633 | 6700 | /// Returns null otherwise. |
| 6634 | 6701 | pub fn getGotAtomForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?*Atom { |
| 6635 | 6702 | const got_index = self.got_entries_table.get(sym_with_loc) orelse return null; |
| 6636 | | return self.got_entries.items[got_index].atom; |
| 6703 | return self.got_entries.items[got_index].getAtom(self); |
| 6637 | 6704 | } |
| 6638 | 6705 | |
| 6639 | 6706 | /// Returns stubs atom that references `sym_with_loc` if one exists. |
| 6640 | 6707 | /// Returns null otherwise. |
| 6641 | 6708 | pub fn getStubsAtomForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?*Atom { |
| 6642 | 6709 | const stubs_index = self.stubs_table.get(sym_with_loc) orelse return null; |
| 6643 | | return self.stubs.items[stubs_index].atom; |
| 6710 | return self.stubs.items[stubs_index].getAtom(self); |
| 6644 | 6711 | } |
| 6645 | 6712 | |
| 6646 | 6713 | /// Returns TLV pointer atom that references `sym_with_loc` if one exists. |
| 6647 | 6714 | /// Returns null otherwise. |
| 6648 | 6715 | pub fn getTlvPtrAtomForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?*Atom { |
| 6649 | 6716 | const tlv_ptr_index = self.tlv_ptr_entries_table.get(sym_with_loc) orelse return null; |
| 6650 | | return self.tlv_ptr_entries.items[tlv_ptr_index].atom; |
| 6717 | return self.tlv_ptr_entries.items[tlv_ptr_index].getAtom(self); |
| 6651 | 6718 | } |
| 6652 | 6719 | |
| 6653 | 6720 | /// Returns symbol location corresponding to the set entrypoint. |
| 6654 | 6721 | /// Asserts output mode is executable. |
| 6655 | | pub fn getEntryPoint(self: MachO) ?SymbolWithLoc { |
| 6722 | pub fn getEntryPoint(self: MachO) error{MissingMainEntrypoint}!SymbolWithLoc { |
| 6656 | 6723 | const entry_name = self.base.options.entry orelse "_main"; |
| 6657 | | return self.globals.get(entry_name); |
| 6724 | const global = self.globals.get(entry_name) orelse { |
| 6725 | log.err("entrypoint '{s}' not found", .{entry_name}); |
| 6726 | return error.MissingMainEntrypoint; |
| 6727 | }; |
| 6728 | return global; |
| 6658 | 6729 | } |
| 6659 | 6730 | |
| 6660 | 6731 | pub fn findFirst(comptime T: type, haystack: []const T, start: usize, predicate: anytype) usize { |
| ... | ... | @@ -6986,7 +7057,7 @@ fn snapshotState(self: *MachO) !void { |
| 6986 | 7057 | break :blk source_sym.n_value + rel.offset; |
| 6987 | 7058 | }; |
| 6988 | 7059 | const target_addr = blk: { |
| 6989 | | const target_atom = (try rel.getTargetAtom(self)) orelse { |
| 7060 | const target_atom = rel.getTargetAtom(self) orelse { |
| 6990 | 7061 | // If there is no atom for target, we still need to check for special, atom-less |
| 6991 | 7062 | // symbols such as `___dso_handle`. |
| 6992 | 7063 | const target_name = self.getSymbolName(rel.target); |
| ... | ... | @@ -7119,8 +7190,9 @@ fn snapshotState(self: *MachO) !void { |
| 7119 | 7190 | try writer.writeByte(']'); |
| 7120 | 7191 | } |
| 7121 | 7192 | |
| 7122 | | pub fn logSymAttributes(sym: macho.nlist_64, buf: *[4]u8) []const u8 { |
| 7123 | | mem.set(u8, buf, '_'); |
| 7193 | fn logSymAttributes(sym: macho.nlist_64, buf: *[9]u8) []const u8 { |
| 7194 | mem.set(u8, buf[0..4], '_'); |
| 7195 | mem.set(u8, buf[4..], ' '); |
| 7124 | 7196 | if (sym.sect()) { |
| 7125 | 7197 | buf[0] = 's'; |
| 7126 | 7198 | } |
| ... | ... | @@ -7137,11 +7209,14 @@ pub fn logSymAttributes(sym: macho.nlist_64, buf: *[4]u8) []const u8 { |
| 7137 | 7209 | if (sym.undf()) { |
| 7138 | 7210 | buf[3] = 'u'; |
| 7139 | 7211 | } |
| 7212 | if (sym.n_desc == N_DESC_GCED) { |
| 7213 | mem.copy(u8, buf[5..], "DEAD"); |
| 7214 | } |
| 7140 | 7215 | return buf[0..]; |
| 7141 | 7216 | } |
| 7142 | 7217 | |
| 7143 | 7218 | fn logSymtab(self: *MachO) void { |
| 7144 | | var buf: [4]u8 = undefined; |
| 7219 | var buf: [9]u8 = undefined; |
| 7145 | 7220 | |
| 7146 | 7221 | log.debug("symtab:", .{}); |
| 7147 | 7222 | for (self.objects.items) |object, id| { |
| ... | ... | @@ -7186,42 +7261,50 @@ fn logSymtab(self: *MachO) void { |
| 7186 | 7261 | } |
| 7187 | 7262 | |
| 7188 | 7263 | log.debug("GOT entries:", .{}); |
| 7189 | | for (self.got_entries_table.values()) |value| { |
| 7190 | | const target = self.got_entries.items[value].target; |
| 7191 | | const target_sym = self.getSymbol(target); |
| 7192 | | const atom = self.got_entries.items[value].atom; |
| 7193 | | const atom_sym = atom.getSymbol(self); |
| 7194 | | |
| 7264 | for (self.got_entries.items) |entry, i| { |
| 7265 | const atom_sym = entry.getSymbol(self); |
| 7266 | if (atom_sym.n_desc == N_DESC_GCED) continue; |
| 7267 | const target_sym = self.getSymbol(entry.target); |
| 7195 | 7268 | if (target_sym.undf()) { |
| 7196 | | log.debug(" {d}@{x} => import('{s}')", .{ value, atom_sym.n_value, self.getSymbolName(target) }); |
| 7269 | log.debug(" {d}@{x} => import('{s}')", .{ |
| 7270 | i, |
| 7271 | atom_sym.n_value, |
| 7272 | self.getSymbolName(entry.target), |
| 7273 | }); |
| 7197 | 7274 | } else { |
| 7198 | | log.debug(" {d}@{x} => local(%{d}) in object({d})", .{ |
| 7199 | | value, |
| 7275 | log.debug(" {d}@{x} => local(%{d}) in object({d}) {s}", .{ |
| 7276 | i, |
| 7200 | 7277 | atom_sym.n_value, |
| 7201 | | target.sym_index, |
| 7202 | | target.file, |
| 7278 | entry.target.sym_index, |
| 7279 | entry.target.file, |
| 7280 | logSymAttributes(target_sym, &buf), |
| 7203 | 7281 | }); |
| 7204 | 7282 | } |
| 7205 | 7283 | } |
| 7206 | 7284 | |
| 7207 | 7285 | log.debug("__thread_ptrs entries:", .{}); |
| 7208 | | for (self.tlv_ptr_entries_table.values()) |value| { |
| 7209 | | const target = self.tlv_ptr_entries.items[value].target; |
| 7210 | | const target_sym = self.getSymbol(target); |
| 7211 | | const atom = self.tlv_ptr_entries.items[value].atom; |
| 7212 | | const atom_sym = atom.getSymbol(self); |
| 7286 | for (self.tlv_ptr_entries.items) |entry, i| { |
| 7287 | const atom_sym = entry.getSymbol(self); |
| 7288 | if (atom_sym.n_desc == N_DESC_GCED) continue; |
| 7289 | const target_sym = self.getSymbol(entry.target); |
| 7213 | 7290 | assert(target_sym.undf()); |
| 7214 | | log.debug(" {d}@{x} => import('{s}')", .{ value, atom_sym.n_value, self.getSymbolName(target) }); |
| 7291 | log.debug(" {d}@{x} => import('{s}')", .{ |
| 7292 | i, |
| 7293 | atom_sym.n_value, |
| 7294 | self.getSymbolName(entry.target), |
| 7295 | }); |
| 7215 | 7296 | } |
| 7216 | 7297 | |
| 7217 | 7298 | log.debug("stubs entries:", .{}); |
| 7218 | | for (self.stubs_table.values()) |value| { |
| 7219 | | const target = self.stubs.items[value].target; |
| 7220 | | const target_sym = self.getSymbol(target); |
| 7221 | | const atom = self.stubs.items[value].atom; |
| 7222 | | const atom_sym = atom.getSymbol(self); |
| 7299 | for (self.stubs.items) |entry, i| { |
| 7300 | const target_sym = self.getSymbol(entry.target); |
| 7301 | const atom_sym = entry.getSymbol(self); |
| 7223 | 7302 | assert(target_sym.undf()); |
| 7224 | | log.debug(" {d}@{x} => import('{s}')", .{ value, atom_sym.n_value, self.getSymbolName(target) }); |
| 7303 | log.debug(" {d}@{x} => import('{s}')", .{ |
| 7304 | i, |
| 7305 | atom_sym.n_value, |
| 7306 | self.getSymbolName(entry.target), |
| 7307 | }); |
| 7225 | 7308 | } |
| 7226 | 7309 | } |
| 7227 | 7310 | |
| ... | ... | @@ -7248,7 +7331,6 @@ fn logAtoms(self: *MachO) void { |
| 7248 | 7331 | |
| 7249 | 7332 | while (true) { |
| 7250 | 7333 | self.logAtom(atom); |
| 7251 | | |
| 7252 | 7334 | if (atom.next) |next| { |
| 7253 | 7335 | atom = next; |
| 7254 | 7336 | } else break; |
| ... | ... | @@ -7256,14 +7338,17 @@ fn logAtoms(self: *MachO) void { |
| 7256 | 7338 | } |
| 7257 | 7339 | } |
| 7258 | 7340 | |
| 7259 | | pub fn logAtom(self: *MachO, atom: *const Atom) void { |
| 7341 | fn logAtom(self: *MachO, atom: *const Atom) void { |
| 7260 | 7342 | const sym = atom.getSymbol(self); |
| 7261 | 7343 | const sym_name = atom.getName(self); |
| 7262 | | log.debug(" ATOM(%{d}, '{s}') @ {x} in object({d})", .{ |
| 7344 | log.debug(" ATOM(%{d}, '{s}') @ {x} (sizeof({x}), alignof({x})) in object({d}) in sect({d})", .{ |
| 7263 | 7345 | atom.sym_index, |
| 7264 | 7346 | sym_name, |
| 7265 | 7347 | sym.n_value, |
| 7348 | atom.size, |
| 7349 | atom.alignment, |
| 7266 | 7350 | atom.file, |
| 7351 | sym.n_sect, |
| 7267 | 7352 | }); |
| 7268 | 7353 | |
| 7269 | 7354 | for (atom.contained.items) |sym_off| { |
| ... | ... | @@ -7271,13 +7356,15 @@ pub fn logAtom(self: *MachO, atom: *const Atom) void { |
| 7271 | 7356 | .sym_index = sym_off.sym_index, |
| 7272 | 7357 | .file = atom.file, |
| 7273 | 7358 | }); |
| 7274 | | const inner_sym_name = self.getSymbolName(.{ .sym_index = sym_off.sym_index, .file = atom.file }); |
| 7275 | | log.debug(" (%{d}, '{s}') @ {x} ({x}) in object({d})", .{ |
| 7359 | const inner_sym_name = self.getSymbolName(.{ |
| 7360 | .sym_index = sym_off.sym_index, |
| 7361 | .file = atom.file, |
| 7362 | }); |
| 7363 | log.debug(" (%{d}, '{s}') @ {x} ({x})", .{ |
| 7276 | 7364 | sym_off.sym_index, |
| 7277 | 7365 | inner_sym_name, |
| 7278 | 7366 | inner_sym.n_value, |
| 7279 | 7367 | sym_off.offset, |
| 7280 | | atom.file, |
| 7281 | 7368 | }); |
| 7282 | 7369 | } |
| 7283 | 7370 | } |