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:
Jakub Konka
2022-07-15 17:54:09 +02:00
parent 61b4119a7d
commit 817939d20a
2 changed files with 62 additions and 45 deletions

View File

@@ -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.*);

View File

@@ -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;