macho: don't store GC roots globally
Instead, if dead-strip was requested, create a temp container and pass it around.
This commit is contained in:
@@ -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.*);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user