| ... | @@ -174,13 +174,7 @@ has_stabs: bool = false, | ... | @@ -174,13 +174,7 @@ has_stabs: bool = false, |
| 174 | | 174 | |
| 175 | section_ordinals: std.AutoArrayHashMapUnmanaged(MatchingSection, void) = .{}, | 175 | section_ordinals: std.AutoArrayHashMapUnmanaged(MatchingSection, void) = .{}, |
| 176 | | 176 | |
| 177 | pending_updates: std.ArrayListUnmanaged(struct { | 177 | pending_updates: std.ArrayListUnmanaged(PendingUpdate) = .{}, |
| 178 | kind: enum { | | |
| 179 | got, | | |
| 180 | stub, | | |
| 181 | }, | | |
| 182 | index: u32, | | |
| 183 | }) = .{}, | | |
| 184 | | 178 | |
| 185 | /// A list of text blocks that have surplus capacity. This list can have false | 179 | /// 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 added | 180 | /// 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. |
| 224 | active_decl: ?*Module.Decl = null, | 218 | active_decl: ?*Module.Decl = null, |
| 225 | | 219 | |
| | 220 | const PendingUpdate = union(enum) { |
| | 221 | resolve_undef: u32, |
| | 222 | add_stub_entry: u32, |
| | 223 | add_got_entry: u32, |
| | 224 | }; |
| | 225 | |
| 226 | const StringIndexContext = struct { | 226 | const StringIndexContext = struct { |
| 227 | strtab: *std.ArrayListUnmanaged(u8), | 227 | strtab: *std.ArrayListUnmanaged(u8), |
| 228 | | 228 | |
| ... | @@ -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); |
| 3490 | | 3540 | |
| 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 | } |
| 3507 | | 3543 | |
| ... | @@ -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 | } |
| 4283 | | 4319 | |
| 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 | }); |
| 4298 | | 4334 | |
| 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); |
| 4302 | | 4338 | |
| 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 stub | 4340 | // 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 | }); | | |
| 4310 | | 4345 | |
| 4311 | return import_sym_index; | 4346 | return sym_index; |
| 4312 | } | 4347 | } |
| 4313 | | 4348 | |
| 4314 | const NextSegmentAddressAndOffset = struct { | 4349 | const NextSegmentAddressAndOffset = struct { |