diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 9b3911d54a..08e2805ee8 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -243,8 +243,6 @@ unnamed_const_atoms: UnnamedConstTable = .{}, /// TODO consolidate this. decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, ?MatchingSection) = .{}, -gc_roots: std.AutoHashMapUnmanaged(*Atom, void) = .{}, - const Entry = struct { target: SymbolWithLoc, atom: *Atom, @@ -631,7 +629,8 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) const tracy = trace(@src()); defer tracy.end(); - var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator); + const gpa = self.base.allocator; + var arena_allocator = std.heap.ArenaAllocator.init(gpa); defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); @@ -676,6 +675,7 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib; const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe; const stack_size = self.base.options.stack_size_override orelse 0; + const dead_strip = self.base.options.gc_sections orelse false; const id_symlink_basename = "zld.id"; @@ -707,7 +707,7 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) man.hash.addOptional(self.base.options.search_strategy); man.hash.addOptional(self.base.options.headerpad_size); man.hash.add(self.base.options.headerpad_max_install_names); - man.hash.add(self.base.options.gc_sections orelse false); + man.hash.add(dead_strip); man.hash.add(self.base.options.dead_strip_dylibs); man.hash.addListOfBytes(self.base.options.lib_dirs); man.hash.addListOfBytes(self.base.options.framework_dirs); @@ -790,14 +790,14 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) .mode = link.determineMode(self.base.options), }); // Index 0 is always a null symbol. - try self.locals.append(self.base.allocator, .{ + try self.locals.append(gpa, .{ .n_strx = 0, .n_type = 0, .n_sect = 0, .n_desc = 0, .n_value = 0, }); - try self.strtab.buffer.append(self.base.allocator, 0); + try self.strtab.buffer.append(gpa, 0); try self.populateMissingMetadata(); var lib_not_found = false; @@ -964,10 +964,10 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) .cmdsize = cmdsize, .path = @sizeOf(macho.rpath_command), }); - rpath_cmd.data = try self.base.allocator.alloc(u8, cmdsize - rpath_cmd.inner.path); + rpath_cmd.data = try gpa.alloc(u8, cmdsize - rpath_cmd.inner.path); mem.set(u8, rpath_cmd.data, 0); mem.copy(u8, rpath_cmd.data, rpath); - try self.load_commands.append(self.base.allocator, .{ .rpath = rpath_cmd }); + try self.load_commands.append(gpa, .{ .rpath = rpath_cmd }); try rpath_table.putNoClobber(rpath, {}); self.load_commands_dirty = true; } @@ -975,11 +975,11 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) // code signature and entitlements if (self.base.options.entitlements) |path| { if (self.code_signature) |*csig| { - try csig.addEntitlements(self.base.allocator, path); + try csig.addEntitlements(gpa, path); csig.code_directory.ident = self.base.options.emit.?.sub_path; } else { var csig = CodeSignature.init(self.page_size); - try csig.addEntitlements(self.base.allocator, path); + try csig.addEntitlements(gpa, path); csig.code_directory.ident = self.base.options.emit.?.sub_path; self.code_signature = csig; } @@ -1033,10 +1033,8 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) try argv.append("-headerpad_max_install_names"); } - if (self.base.options.gc_sections) |is_set| { - if (is_set) { - try argv.append("-dead_strip"); - } + if (dead_strip) { + try argv.append("-dead_strip"); } if (self.base.options.dead_strip_dylibs) { @@ -1120,7 +1118,7 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) var dependent_libs = std.fifo.LinearFifo(struct { id: Dylib.Id, parent: u16, - }, .Dynamic).init(self.base.allocator); + }, .Dynamic).init(gpa); defer dependent_libs.deinit(); try self.parseInputFiles(positionals.items, self.base.options.sysroot, &dependent_libs); try self.parseAndForceLoadStaticArchives(must_link_archives.keys()); @@ -1153,11 +1151,21 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) try self.createTentativeDefAtoms(); - for (self.objects.items) |*object, object_id| { - try object.splitIntoAtomsOneShot(self, @intCast(u32, object_id)); + if (dead_strip) { + var gc_roots = std.AutoHashMap(*Atom, void).init(gpa); + defer gc_roots.deinit(); + + for (self.objects.items) |*object, object_id| { + try object.splitIntoAtomsOneShot(self, @intCast(u32, object_id), &gc_roots); + } + + try self.gcAtoms(&gc_roots); + } else { + for (self.objects.items) |*object, object_id| { + try object.splitIntoAtomsOneShot(self, @intCast(u32, object_id), null); + } } - try self.gcAtoms(); try self.pruneAndSortSections(); try self.allocateSegments(); try self.allocateSymbols(); @@ -1184,7 +1192,7 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) try self.writeLinkeditSegment(); if (self.code_signature) |*csig| { - csig.clear(self.base.allocator); + csig.clear(gpa); csig.code_directory.ident = self.base.options.emit.?.sub_path; // Preallocate space for the code signature. // We need to do this at this stage so that we have the load commands with proper values @@ -3294,7 +3302,6 @@ pub fn deinit(self: *MachO) void { self.locals.deinit(self.base.allocator); self.locals_free_list.deinit(self.base.allocator); self.unresolved.deinit(self.base.allocator); - self.gc_roots.deinit(self.base.allocator); for (self.objects.items) |*object| { object.deinit(self.base.allocator); @@ -5447,9 +5454,8 @@ fn pruneAndSortSections(self: *MachO) !void { self.sections_order_dirty = false; } -fn gcAtoms(self: *MachO) !void { - const dead_strip = self.base.options.gc_sections orelse return; - if (!dead_strip) return; +fn gcAtoms(self: *MachO, gc_roots: *std.AutoHashMap(*Atom, void)) !void { + assert(self.base.options.gc_sections.?); const gpa = self.base.allocator; @@ -5461,7 +5467,7 @@ fn gcAtoms(self: *MachO) !void { log.debug("skipping {s}", .{self.getSymbolName(global)}); continue; }; - _ = try self.gc_roots.getOrPut(gpa, gc_root); + _ = try gc_roots.getOrPut(gc_root); } // Add any atom targeting an import as GC root @@ -5474,7 +5480,7 @@ fn gcAtoms(self: *MachO) !void { if ((try rel.getTargetAtom(self)) == null) { const target_sym = self.getSymbol(rel.target); if (target_sym.undf()) { - _ = try self.gc_roots.getOrPut(gpa, atom); + _ = try gc_roots.getOrPut(atom); break; } } @@ -5488,14 +5494,14 @@ fn gcAtoms(self: *MachO) !void { var stack = std.ArrayList(*Atom).init(gpa); defer stack.deinit(); - try stack.ensureUnusedCapacity(self.gc_roots.count()); + try stack.ensureUnusedCapacity(gc_roots.count()); var retained = std.AutoHashMap(*Atom, void).init(gpa); defer retained.deinit(); - try retained.ensureUnusedCapacity(self.gc_roots.count()); + try retained.ensureUnusedCapacity(gc_roots.count()); log.debug("GC roots:", .{}); - var gc_roots_it = self.gc_roots.keyIterator(); + var gc_roots_it = gc_roots.keyIterator(); while (gc_roots_it.next()) |gc_root| { self.logAtom(gc_root.*); diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig index 2737b5e164..82d872f68c 100644 --- a/src/link/MachO/Object.zig +++ b/src/link/MachO/Object.zig @@ -360,7 +360,12 @@ fn filterDice( } /// Splits object into atoms assuming one-shot linking mode. -pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32) !void { +pub fn splitIntoAtomsOneShot( + self: *Object, + macho_file: *MachO, + object_id: u32, + gc_roots: ?*std.AutoHashMap(*Atom, void), +) !void { assert(macho_file.mode == .one_shot); const tracy = trace(@src()); @@ -493,6 +498,7 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32) &.{}, match, sect, + gc_roots, ); try macho_file.addAtomToSection(atom, match); } @@ -538,6 +544,7 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32) atom_syms[1..], match, sect, + gc_roots, ); if (arch == .x86_64 and addr == sect.addr) { @@ -593,6 +600,7 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32) filtered_syms, match, sect, + gc_roots, ); try macho_file.addAtomToSection(atom, match); } @@ -611,6 +619,7 @@ fn createAtomFromSubsection( indexes: []const SymbolAtIndex, match: MatchingSection, sect: macho.section_64, + gc_roots: ?*std.AutoHashMap(*Atom, void), ) !*Atom { const gpa = macho_file.base.allocator; const sym = self.symtab.items[sym_index]; @@ -715,23 +724,25 @@ fn createAtomFromSubsection( try self.atom_by_index_table.putNoClobber(gpa, inner_sym_index.index, atom); } - const is_gc_root = blk: { - if (sect.isDontDeadStrip()) break :blk true; - if (sect.isDontDeadStripIfReferencesLive()) { - // TODO if isDontDeadStripIfReferencesLive we should analyse the edges - // before making it a GC root - break :blk true; + if (gc_roots) |gcr| { + const is_gc_root = blk: { + if (sect.isDontDeadStrip()) break :blk true; + if (sect.isDontDeadStripIfReferencesLive()) { + // TODO if isDontDeadStripIfReferencesLive we should analyse the edges + // before making it a GC root + break :blk true; + } + if (mem.eql(u8, "__StaticInit", sect.sectName())) break :blk true; + switch (sect.type_()) { + macho.S_MOD_INIT_FUNC_POINTERS, + macho.S_MOD_TERM_FUNC_POINTERS, + => break :blk true, + else => break :blk false, + } + }; + if (is_gc_root) { + try gcr.putNoClobber(atom, {}); } - if (mem.eql(u8, "__StaticInit", sect.sectName())) break :blk true; - switch (sect.type_()) { - macho.S_MOD_INIT_FUNC_POINTERS, - macho.S_MOD_TERM_FUNC_POINTERS, - => break :blk true, - else => break :blk false, - } - }; - if (is_gc_root) { - try macho_file.gc_roots.putNoClobber(gpa, atom, {}); } return atom;