diff --git a/src/link/MachO/Dylib.zig b/src/link/MachO/Dylib.zig index 8fd4498931..b751249ce4 100644 --- a/src/link/MachO/Dylib.zig +++ b/src/link/MachO/Dylib.zig @@ -506,10 +506,3 @@ pub fn parseDependentLibs(self: *Dylib, out: *std.ArrayList(*Dylib)) !void { } } } - -pub fn createProxy(self: *Dylib, sym_name: []const u8) !?*Symbol { - if (!self.symbols.contains(sym_name)) return null; - return Symbol.Proxy.new(self.allocator, sym_name, .{ - .file = self, - }); -} diff --git a/src/link/MachO/Zld.zig b/src/link/MachO/Zld.zig index 3eeaa3f181..0adac2aeb6 100644 --- a/src/link/MachO/Zld.zig +++ b/src/link/MachO/Zld.zig @@ -104,7 +104,6 @@ objc_data_section_index: ?u16 = null, locals: std.ArrayListUnmanaged(*Symbol) = .{}, globals: std.StringArrayHashMapUnmanaged(*Symbol) = .{}, -imports: std.StringArrayHashMapUnmanaged(*Symbol) = .{}, /// Offset into __DATA,__common section. /// Set if the linker found tentative definitions in any of the objects. @@ -172,12 +171,6 @@ pub fn deinit(self: *Zld) void { } self.dylibs.deinit(self.allocator); - for (self.imports.values()) |sym| { - sym.deinit(self.allocator); - self.allocator.destroy(sym); - } - self.imports.deinit(self.allocator); - for (self.globals.values()) |sym| { sym.deinit(self.allocator); self.allocator.destroy(sym); @@ -1570,6 +1563,95 @@ fn resolveSymbols(self: *Zld) !void { try self.resolveSymbolsInObject(object); } + // Second pass, resolve symbols in static libraries. + var sym_it = self.globals.iterator(); + while (sym_it.next()) |entry| { + const symbol = entry.value_ptr.*; + if (symbol.payload != .undef) continue; + + for (self.archives.items) |archive| { + // Check if the entry exists in a static archive. + const offsets = archive.toc.get(symbol.name) orelse { + // No hit. + continue; + }; + assert(offsets.items.len > 0); + + const object = try archive.parseObject(offsets.items[0]); + try self.objects.append(self.allocator, object); + try self.resolveSymbolsInObject(object); + + sym_it = self.globals.iterator(); + break; + } + } + + // Third pass, resolve symbols in dynamic libraries. + { + // Put dyld_stub_binder as an undefined special symbol. + const symbol = try Symbol.new(self.allocator, "dyld_stub_binder"); + try self.globals.putNoClobber(self.allocator, symbol.name, symbol); + } + + var referenced = std.AutoHashMap(*Dylib, void).init(self.allocator); + defer referenced.deinit(); + + loop: for (self.globals.values()) |symbol| { + if (symbol.payload != .undef) continue; + + for (self.dylibs.items) |dylib| { + if (!dylib.symbols.contains(symbol.name)) continue; + + try referenced.put(dylib, {}); + symbol.payload = .{ + .proxy = .{ + .file = dylib, + }, + }; + continue :loop; + } + } + + // Add LC_LOAD_DYLIB load command for each referenced dylib/stub. + var it = referenced.iterator(); + while (it.next()) |entry| { + const dylib = entry.key_ptr.*; + dylib.ordinal = self.next_dylib_ordinal; + const dylib_id = dylib.id orelse unreachable; + var dylib_cmd = try createLoadDylibCommand( + self.allocator, + dylib_id.name, + dylib_id.timestamp, + dylib_id.current_version, + dylib_id.compatibility_version, + ); + errdefer dylib_cmd.deinit(self.allocator); + try self.load_commands.append(self.allocator, .{ .Dylib = dylib_cmd }); + self.next_dylib_ordinal += 1; + } + + // Fourth pass, handle synthetic symbols and flag any undefined references. + if (self.globals.get("___dso_handle")) |symbol| { + if (symbol.payload == .undef) { + symbol.payload = .{ + .proxy = .{}, + }; + } + } + + var has_undefined = false; + for (self.globals.values()) |symbol| { + if (symbol.payload != .undef) continue; + + log.err("undefined reference to symbol '{s}'", .{symbol.name}); + if (symbol.payload.undef.file) |file| { + log.err(" | referenced in {s}", .{file.name.?}); + } + has_undefined = true; + } + + if (has_undefined) return error.UndefinedSymbolReference; + log.warn("globals", .{}); for (self.globals.values()) |value| { log.warn(" | {s}: {}", .{ value.name, value.payload }); @@ -1581,112 +1663,6 @@ fn resolveSymbols(self: *Zld) !void { log.warn(" | {s}: {}", .{ sym.name, sym.payload }); } } - - // // Second pass, resolve symbols in static libraries. - // var next_sym: usize = 0; - // while (true) { - // if (next_sym == self.unresolved.count()) break; - - // const sym = self.unresolved.values()[next_sym]; - - // var reset: bool = false; - // for (self.archives.items) |archive| { - // // Check if the entry exists in a static archive. - // const offsets = archive.toc.get(sym.name) orelse { - // // No hit. - // continue; - // }; - // assert(offsets.items.len > 0); - - // const object = try archive.parseObject(offsets.items[0]); - // try self.objects.append(self.allocator, object); - // try self.resolveSymbolsInObject(object); - - // reset = true; - // break; - // } - - // if (reset) { - // next_sym = 0; - // } else { - // next_sym += 1; - // } - // } - - // // Third pass, resolve symbols in dynamic libraries. - // var unresolved = std.ArrayList(*Symbol).init(self.allocator); - // defer unresolved.deinit(); - - // try unresolved.ensureCapacity(self.unresolved.count()); - // for (self.unresolved.values()) |value| { - // unresolved.appendAssumeCapacity(value); - // } - // self.unresolved.clearRetainingCapacity(); - - // // Put dyld_stub_binder as an unresolved special symbol. - // { - // const name = try self.allocator.dupe(u8, "dyld_stub_binder"); - // errdefer self.allocator.free(name); - // const undef = try Symbol.Unresolved.new(self.allocator, name, .{}); - // try unresolved.append(undef); - // } - - // var referenced = std.AutoHashMap(*Dylib, void).init(self.allocator); - // defer referenced.deinit(); - - // loop: while (unresolved.popOrNull()) |undef| { - // const proxy = self.imports.get(undef.name) orelse outer: { - // const proxy = inner: { - // for (self.dylibs.items) |dylib| { - // const proxy = (try dylib.createProxy(undef.name)) orelse continue; - // try referenced.put(dylib, {}); - // break :inner proxy; - // } - // if (mem.eql(u8, undef.name, "___dso_handle")) { - // // TODO this is just a temp patch until I work out what to actually - // // do with ___dso_handle and __mh_execute_header symbols which are - // // synthetically created by the linker on macOS. - // break :inner try Symbol.Proxy.new(self.allocator, undef.name, .{}); - // } - - // self.unresolved.putAssumeCapacityNoClobber(undef.name, undef); - // continue :loop; - // }; - - // try self.imports.putNoClobber(self.allocator, proxy.name, proxy); - // break :outer proxy; - // }; - // undef.alias = proxy; - // } - - // // Add LC_LOAD_DYLIB load command for each referenced dylib/stub. - // var it = referenced.iterator(); - // while (it.next()) |entry| { - // const dylib = entry.key_ptr.*; - // dylib.ordinal = self.next_dylib_ordinal; - // const dylib_id = dylib.id orelse unreachable; - // var dylib_cmd = try createLoadDylibCommand( - // self.allocator, - // dylib_id.name, - // dylib_id.timestamp, - // dylib_id.current_version, - // dylib_id.compatibility_version, - // ); - // errdefer dylib_cmd.deinit(self.allocator); - // try self.load_commands.append(self.allocator, .{ .Dylib = dylib_cmd }); - // self.next_dylib_ordinal += 1; - // } - - // if (self.unresolved.count() > 0) { - // for (self.unresolved.values()) |undef| { - // log.err("undefined reference to symbol '{s}'", .{undef.name}); - // if (undef.cast(Symbol.Unresolved).?.file) |file| { - // log.err(" | referenced in {s}", .{file.name.?}); - // } - // } - - // return error.UndefinedSymbolReference; - // } } fn resolveStubsAndGotEntries(self: *Zld) !void {