macho: track unresolved externs globally

this way we share state between incremental and traditional paths.
This commit is contained in:
Jakub Konka 2021-08-20 09:12:26 +02:00
parent 30247fbb6a
commit 153e231774

View File

@ -138,6 +138,7 @@ locals: std.ArrayListUnmanaged(macho.nlist_64) = .{},
globals: std.ArrayListUnmanaged(macho.nlist_64) = .{},
undefs: std.ArrayListUnmanaged(macho.nlist_64) = .{},
symbol_resolver: std.AutoHashMapUnmanaged(u32, SymbolWithLoc) = .{},
unresolved: std.AutoArrayHashMapUnmanaged(u32, void) = .{},
locals_free_list: std.ArrayListUnmanaged(u32) = .{},
globals_free_list: std.ArrayListUnmanaged(u32) = .{},
@ -2082,7 +2083,6 @@ fn resolveSymbolsInObject(
self: *MachO,
object_id: u16,
tentatives: *std.AutoArrayHashMap(u32, void),
unresolved: *std.AutoArrayHashMap(u32, void),
) !void {
const object = &self.objects.items[object_id];
@ -2181,7 +2181,7 @@ fn resolveSymbolsInObject(
.n_desc = 0,
.n_value = 0,
};
_ = unresolved.fetchSwapRemove(resolv.where_index);
_ = self.unresolved.fetchSwapRemove(resolv.where_index);
},
}
@ -2252,7 +2252,7 @@ fn resolveSymbolsInObject(
.n_desc = 0,
.n_value = 0,
};
_ = unresolved.fetchSwapRemove(resolv.where_index);
_ = self.unresolved.fetchSwapRemove(resolv.where_index);
},
}
} else {
@ -2272,7 +2272,7 @@ fn resolveSymbolsInObject(
.where_index = undef_sym_index,
.file = object_id,
});
_ = try unresolved.getOrPut(undef_sym_index);
_ = try self.unresolved.getOrPut(self.base.allocator, undef_sym_index);
}
}
}
@ -2281,18 +2281,15 @@ fn resolveSymbols(self: *MachO) !void {
var tentatives = std.AutoArrayHashMap(u32, void).init(self.base.allocator);
defer tentatives.deinit();
var unresolved = std.AutoArrayHashMap(u32, void).init(self.base.allocator);
defer unresolved.deinit();
// First pass, resolve symbols in provided objects.
for (self.objects.items) |_, object_id| {
try self.resolveSymbolsInObject(@intCast(u16, object_id), &tentatives, &unresolved);
try self.resolveSymbolsInObject(@intCast(u16, object_id), &tentatives);
}
// Second pass, resolve symbols in static libraries.
var next_sym: usize = 0;
loop: while (next_sym < unresolved.count()) {
const sym = self.undefs.items[unresolved.keys()[next_sym]];
loop: while (next_sym < self.unresolved.count()) {
const sym = self.undefs.items[self.unresolved.keys()[next_sym]];
const sym_name = self.getString(sym.n_strx);
for (self.archives.items) |archive| {
@ -2306,7 +2303,7 @@ fn resolveSymbols(self: *MachO) !void {
const object_id = @intCast(u16, self.objects.items.len);
const object = try self.objects.addOne(self.base.allocator);
object.* = try archive.parseObject(self.base.allocator, self.base.options.target, offsets.items[0]);
try self.resolveSymbolsInObject(object_id, &tentatives, &unresolved);
try self.resolveSymbolsInObject(object_id, &tentatives);
continue :loop;
}
@ -2382,8 +2379,8 @@ fn resolveSymbols(self: *MachO) !void {
// Third pass, resolve symbols in dynamic libraries.
next_sym = 0;
loop: while (next_sym < unresolved.count()) {
const sym = self.undefs.items[unresolved.keys()[next_sym]];
loop: while (next_sym < self.unresolved.count()) {
const sym = self.undefs.items[self.unresolved.keys()[next_sym]];
const sym_name = self.getString(sym.n_strx);
for (self.dylibs.items) |dylib, id| {
@ -2400,7 +2397,7 @@ fn resolveSymbols(self: *MachO) !void {
undef.n_type |= macho.N_EXT;
undef.n_desc = @intCast(u16, ordinal + 1) * macho.N_SYMBOL_RESOLVER;
_ = unresolved.fetchSwapRemove(resolv.where_index);
_ = self.unresolved.fetchSwapRemove(resolv.where_index);
continue :loop;
}
@ -2434,7 +2431,7 @@ fn resolveSymbols(self: *MachO) !void {
nlist.n_desc = macho.N_WEAK_DEF;
try self.globals.append(self.base.allocator, nlist);
_ = unresolved.fetchSwapRemove(resolv.where_index);
_ = self.unresolved.fetchSwapRemove(resolv.where_index);
undef.* = .{
.n_strx = 0,
@ -2468,7 +2465,7 @@ fn resolveSymbols(self: *MachO) !void {
}
}
for (unresolved.keys()) |index| {
for (self.unresolved.keys()) |index| {
const sym = self.undefs.items[index];
const sym_name = self.getString(sym.n_strx);
const resolv = self.symbol_resolver.get(sym.n_strx) orelse unreachable;
@ -2477,7 +2474,7 @@ fn resolveSymbols(self: *MachO) !void {
log.err(" first referenced in '{s}'", .{self.objects.items[resolv.file].name});
}
if (unresolved.count() > 0)
if (self.unresolved.count() > 0)
return error.UndefinedSymbolReference;
}
@ -3122,6 +3119,7 @@ pub fn deinit(self: *MachO) void {
self.locals.deinit(self.base.allocator);
self.locals_free_list.deinit(self.base.allocator);
self.symbol_resolver.deinit(self.base.allocator);
self.unresolved.deinit(self.base.allocator);
for (self.objects.items) |*object| {
object.deinit(self.base.allocator);
@ -4332,6 +4330,7 @@ pub fn addExternFn(self: *MachO, name: []const u8) !u32 {
.where = .undef,
.where_index = sym_index,
});
_ = try self.unresolved.getOrPut(self.base.allocator, sym_index);
const stubs_index = @intCast(u32, self.stubs.items.len);
try self.stubs.append(self.base.allocator, sym_index);
@ -4340,8 +4339,7 @@ pub fn addExternFn(self: *MachO, name: []const u8) !u32 {
// TODO discuss this. The caller context expects codegen.InnerError{ OutOfMemory, CodegenFail },
// which obviously doesn't include file writing op errors. So instead of trying to write the stub
// entry right here and now, queue it up and dispose of when updating decl.
try self.pending_updates.ensureUnusedCapacity(self.base.allocator, 2);
self.pending_updates.appendAssumeCapacity(.{ .resolve_undef = sym_index });
try self.pending_updates.ensureUnusedCapacity(self.base.allocator, 1);
self.pending_updates.appendAssumeCapacity(.{ .add_stub_entry = stubs_index });
return sym_index;