authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-08-18 00:17:03+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-08-18 00:17:03+02:00
log8167456c58270fe9586ac93dbd6a6ee1a8ae7915
tree86dff19da5aa325743843ddd377c5d4408bf087e
parent790633a2a09164db5985d1c8302a60d3809e5002

macho: resolve undefs in incremental properly

Instead of assuming that every undef extern symbol comes from libSystem, actually perform the check!

1 files changed, 68 insertions(+), 33 deletions(-)

src/link/MachO.zig+68-33
...@@ -174,13 +174,7 @@ has_stabs: bool = false,...@@ -174,13 +174,7 @@ has_stabs: bool = false,
174174
175section_ordinals: std.AutoArrayHashMapUnmanaged(MatchingSection, void) = .{},175section_ordinals: std.AutoArrayHashMapUnmanaged(MatchingSection, void) = .{},
176176
177pending_updates: std.ArrayListUnmanaged(struct {177pending_updates: std.ArrayListUnmanaged(PendingUpdate) = .{},
178 kind: enum {
179 got,
180 stub,
181 },
182 index: u32,
183}) = .{},
184178
185/// A list of text blocks that have surplus capacity. This list can have false179/// A list of text blocks that have surplus capacity. This list can have false
186/// positives, as functions grow and shrink over time, only sometimes being added180/// positives, as functions grow and shrink over time, only sometimes being added
...@@ -223,6 +217,12 @@ decls: std.AutoArrayHashMapUnmanaged(*Module.Decl, void) = .{},...@@ -223,6 +217,12 @@ decls: std.AutoArrayHashMapUnmanaged(*Module.Decl, void) = .{},
223/// somewhere else in the codegen.217/// somewhere else in the codegen.
224active_decl: ?*Module.Decl = null,218active_decl: ?*Module.Decl = null,
225219
220const PendingUpdate = union(enum) {
221 resolve_undef: u32,
222 add_stub_entry: u32,
223 add_got_entry: u32,
224};
225
226const StringIndexContext = struct {226const StringIndexContext = struct {
227 strtab: *std.ArrayListUnmanaged(u8),227 strtab: *std.ArrayListUnmanaged(u8),
228228
...@@ -761,6 +761,56 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {...@@ -761,6 +761,56 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {
761 try self.parseLibs(libs.items, self.base.options.sysroot);761 try self.parseLibs(libs.items, self.base.options.sysroot);
762 try self.resolveSymbols();762 try self.resolveSymbols();
763 try self.resolveDyldStubBinder();763 try self.resolveDyldStubBinder();
764
765 // Apply pending updates
766 var still_pending = std.ArrayList(PendingUpdate).init(self.base.allocator);
767 defer still_pending.deinit();
768
769 for (self.pending_updates.items) |update| {
770 switch (update) {
771 .resolve_undef => |sym_index| {
772 const sym = &self.undefs.items[sym_index];
773 const sym_name = self.getString(sym.n_strx);
774 const resolv = self.symbol_resolver.getPtr(sym.n_strx) orelse unreachable;
775
776 for (self.dylibs.items) |dylib, id| {
777 if (!dylib.symbols.contains(sym_name)) continue;
778
779 const dylib_id = @intCast(u16, id);
780 if (!self.referenced_dylibs.contains(dylib_id)) {
781 try self.referenced_dylibs.putNoClobber(self.base.allocator, dylib_id, {});
782 }
783
784 const ordinal = self.referenced_dylibs.getIndex(dylib_id) orelse unreachable;
785 sym.n_type |= macho.N_EXT;
786 sym.n_desc = @intCast(u16, ordinal + 1) * macho.N_SYMBOL_RESOLVER;
787
788 break;
789 } else {
790 try still_pending.append(update);
791 log.warn("undefined reference to symbol '{s}'", .{sym_name});
792 // TODO self-reference for incremental means resolv.file == 0!
793 if (self.objects.items.len > 0) {
794 log.warn(" first referenced in '{s}'", .{self.objects.items[resolv.file].name});
795 }
796 }
797 },
798 .add_got_entry => return error.TODOAddGotEntryUpdate,
799 .add_stub_entry => |stub_index| {
800 try self.writeStub(stub_index);
801 try self.writeStubInStubHelper(stub_index);
802 try self.writeLazySymbolPointer(stub_index);
803 self.rebase_info_dirty = true;
804 self.lazy_binding_info_dirty = true;
805 },
806 }
807 }
808
809 self.pending_updates.clearRetainingCapacity();
810 for (still_pending.items) |update| {
811 self.pending_updates.appendAssumeCapacity(update);
812 }
813
764 try self.parseTextBlocks();814 try self.parseTextBlocks();
765 try self.addRpathLCs(rpath_table.keys());815 try self.addRpathLCs(rpath_table.keys());
766 try self.addLoadDylibLCs();816 try self.addLoadDylibLCs();
...@@ -3488,20 +3538,6 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64...@@ -3488,20 +3538,6 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64
3488 // so that we can reapply them when moving/growing sections?3538 // so that we can reapply them when moving/growing sections?
3489 decl.link.macho.relocs.clearAndFree(self.base.allocator);3539 decl.link.macho.relocs.clearAndFree(self.base.allocator);
34903540
3491 // Apply pending updates
3492 while (self.pending_updates.popOrNull()) |update| {
3493 switch (update.kind) {
3494 .got => unreachable,
3495 .stub => {
3496 try self.writeStub(update.index);
3497 try self.writeStubInStubHelper(update.index);
3498 try self.writeLazySymbolPointer(update.index);
3499 self.rebase_info_dirty = true;
3500 self.lazy_binding_info_dirty = true;
3501 },
3502 }
3503 }
3504
3505 return symbol;3541 return symbol;
3506}3542}
35073543
...@@ -4281,34 +4317,33 @@ pub fn addExternFn(self: *MachO, name: []const u8) !u32 {...@@ -4281,34 +4317,33 @@ pub fn addExternFn(self: *MachO, name: []const u8) !u32 {
4281 return resolv.where_index;4317 return resolv.where_index;
4282 }4318 }
42834319
4284 log.debug("adding new extern function '{s}' with dylib ordinal 1", .{sym_name});4320 log.debug("adding new extern function '{s}'", .{sym_name});
4285 const import_sym_index = @intCast(u32, self.undefs.items.len);4321 const sym_index = @intCast(u32, self.undefs.items.len);
4286 const n_strx = try self.makeString(sym_name);4322 const n_strx = try self.makeString(sym_name);
4287 try self.undefs.append(self.base.allocator, .{4323 try self.undefs.append(self.base.allocator, .{
4288 .n_strx = n_strx,4324 .n_strx = n_strx,
4289 .n_type = macho.N_UNDF | macho.N_EXT,4325 .n_type = macho.N_UNDF,
4290 .n_sect = 0,4326 .n_sect = 0,
4291 .n_desc = @intCast(u8, 1) * macho.N_SYMBOL_RESOLVER,4327 .n_desc = 0,
4292 .n_value = 0,4328 .n_value = 0,
4293 });4329 });
4294 try self.symbol_resolver.putNoClobber(self.base.allocator, n_strx, .{4330 try self.symbol_resolver.putNoClobber(self.base.allocator, n_strx, .{
4295 .where = .undef,4331 .where = .undef,
4296 .where_index = import_sym_index,4332 .where_index = sym_index,
4297 });4333 });
42984334
4299 const stubs_index = @intCast(u32, self.stubs.items.len);4335 const stubs_index = @intCast(u32, self.stubs.items.len);
4300 try self.stubs.append(self.base.allocator, import_sym_index);4336 try self.stubs.append(self.base.allocator, sym_index);
4301 try self.stubs_map.putNoClobber(self.base.allocator, import_sym_index, stubs_index);4337 try self.stubs_map.putNoClobber(self.base.allocator, sym_index, stubs_index);
43024338
4303 // TODO discuss this. The caller context expects codegen.InnerError{ OutOfMemory, CodegenFail },4339 // TODO discuss this. The caller context expects codegen.InnerError{ OutOfMemory, CodegenFail },
4304 // which obviously doesn't include file writing op errors. So instead of trying to write the stub4340 // which obviously doesn't include file writing op errors. So instead of trying to write the stub
4305 // entry right here and now, queue it up and dispose of when updating decl.4341 // entry right here and now, queue it up and dispose of when updating decl.
4306 try self.pending_updates.append(self.base.allocator, .{4342 try self.pending_updates.ensureUnusedCapacity(self.base.allocator, 2);
4307 .kind = .stub,4343 self.pending_updates.appendAssumeCapacity(.{ .resolve_undef = sym_index });
4308 .index = stubs_index,4344 self.pending_updates.appendAssumeCapacity(.{ .add_stub_entry = stubs_index });
4309 });
43104345
4311 return import_sym_index;4346 return sym_index;
4312}4347}
43134348
4314const NextSegmentAddressAndOffset = struct {4349const NextSegmentAddressAndOffset = struct {