| ... | ... | @@ -174,13 +174,7 @@ has_stabs: bool = false, |
| 174 | 174 | |
| 175 | 175 | section_ordinals: std.AutoArrayHashMapUnmanaged(MatchingSection, void) = .{}, |
| 176 | 176 | |
| 177 | | pending_updates: std.ArrayListUnmanaged(struct { |
| 178 | | kind: enum { |
| 179 | | got, |
| 180 | | stub, |
| 181 | | }, |
| 182 | | index: u32, |
| 183 | | }) = .{}, |
| 177 | pending_updates: std.ArrayListUnmanaged(PendingUpdate) = .{}, |
| 184 | 178 | |
| 185 | 179 | /// A list of text blocks that have surplus capacity. This list can have false |
| 186 | 180 | /// positives, as functions grow and shrink over time, only sometimes being added |
| ... | ... | @@ -223,6 +217,12 @@ decls: std.AutoArrayHashMapUnmanaged(*Module.Decl, void) = .{}, |
| 223 | 217 | /// somewhere else in the codegen. |
| 224 | 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 | 226 | const StringIndexContext = struct { |
| 227 | 227 | strtab: *std.ArrayListUnmanaged(u8), |
| 228 | 228 | |
| ... | ... | @@ -761,6 +761,56 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 761 | 761 | try self.parseLibs(libs.items, self.base.options.sysroot); |
| 762 | 762 | try self.resolveSymbols(); |
| 763 | 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 | 814 | try self.parseTextBlocks(); |
| 765 | 815 | try self.addRpathLCs(rpath_table.keys()); |
| 766 | 816 | try self.addLoadDylibLCs(); |
| ... | ... | @@ -3488,20 +3538,6 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64 |
| 3488 | 3538 | // so that we can reapply them when moving/growing sections? |
| 3489 | 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 | 3541 | return symbol; |
| 3506 | 3542 | } |
| 3507 | 3543 | |
| ... | ... | @@ -4281,34 +4317,33 @@ pub fn addExternFn(self: *MachO, name: []const u8) !u32 { |
| 4281 | 4317 | return resolv.where_index; |
| 4282 | 4318 | } |
| 4283 | 4319 | |
| 4284 | | log.debug("adding new extern function '{s}' with dylib ordinal 1", .{sym_name}); |
| 4285 | | const import_sym_index = @intCast(u32, self.undefs.items.len); |
| 4320 | log.debug("adding new extern function '{s}'", .{sym_name}); |
| 4321 | const sym_index = @intCast(u32, self.undefs.items.len); |
| 4286 | 4322 | const n_strx = try self.makeString(sym_name); |
| 4287 | 4323 | try self.undefs.append(self.base.allocator, .{ |
| 4288 | 4324 | .n_strx = n_strx, |
| 4289 | | .n_type = macho.N_UNDF | macho.N_EXT, |
| 4325 | .n_type = macho.N_UNDF, |
| 4290 | 4326 | .n_sect = 0, |
| 4291 | | .n_desc = @intCast(u8, 1) * macho.N_SYMBOL_RESOLVER, |
| 4327 | .n_desc = 0, |
| 4292 | 4328 | .n_value = 0, |
| 4293 | 4329 | }); |
| 4294 | 4330 | try self.symbol_resolver.putNoClobber(self.base.allocator, n_strx, .{ |
| 4295 | 4331 | .where = .undef, |
| 4296 | | .where_index = import_sym_index, |
| 4332 | .where_index = sym_index, |
| 4297 | 4333 | }); |
| 4298 | 4334 | |
| 4299 | 4335 | const stubs_index = @intCast(u32, self.stubs.items.len); |
| 4300 | | try self.stubs.append(self.base.allocator, import_sym_index); |
| 4301 | | try self.stubs_map.putNoClobber(self.base.allocator, import_sym_index, stubs_index); |
| 4336 | try self.stubs.append(self.base.allocator, sym_index); |
| 4337 | try self.stubs_map.putNoClobber(self.base.allocator, sym_index, stubs_index); |
| 4302 | 4338 | |
| 4303 | 4339 | // TODO discuss this. The caller context expects codegen.InnerError{ OutOfMemory, CodegenFail }, |
| 4304 | 4340 | // which obviously doesn't include file writing op errors. So instead of trying to write the stub |
| 4305 | 4341 | // entry right here and now, queue it up and dispose of when updating decl. |
| 4306 | | try self.pending_updates.append(self.base.allocator, .{ |
| 4307 | | .kind = .stub, |
| 4308 | | .index = stubs_index, |
| 4309 | | }); |
| 4342 | try self.pending_updates.ensureUnusedCapacity(self.base.allocator, 2); |
| 4343 | self.pending_updates.appendAssumeCapacity(.{ .resolve_undef = sym_index }); |
| 4344 | self.pending_updates.appendAssumeCapacity(.{ .add_stub_entry = stubs_index }); |
| 4310 | 4345 | |
| 4311 | | return import_sym_index; |
| 4346 | return sym_index; |
| 4312 | 4347 | } |
| 4313 | 4348 | |
| 4314 | 4349 | const NextSegmentAddressAndOffset = struct { |