diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2021-06-19 11:35:15 +0200 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2021-06-24 14:45:45 +0200 |
| commit | 089577a71df6e22bf1cc3f83489fd2af548c5b81 (patch) | |
| tree | c3ebe4195ec16fe35b544930446ade6fa20f6fb6 /src | |
| parent | fbdc5154184b0752175dcafc5bfdc4ea6a0cfebf (diff) | |
| download | zig-089577a71df6e22bf1cc3f83489fd2af548c5b81.tar.gz zig-089577a71df6e22bf1cc3f83489fd2af548c5b81.zip | |
zld: parse libSystem tbd stub when linking
Diffstat (limited to 'src')
| -rw-r--r-- | src/link/MachO.zig | 8 | ||||
| -rw-r--r-- | src/link/MachO/Symbol.zig | 2 | ||||
| -rw-r--r-- | src/link/MachO/Zld.zig | 199 | ||||
| -rw-r--r-- | src/link/tapi.zig | 16 |
4 files changed, 140 insertions, 85 deletions
diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 6e1996f9ff..76b59e896b 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -760,10 +760,9 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { } // Assume ld64 default: -search_paths_first - // Look in each directory for a dylib (tbd), and then for archive + // Look in each directory for a dylib (next, tbd), and then for archive // TODO implement alternative: -search_dylibs_first - // TODO text-based API, or .tbd files. - const exts = &[_][]const u8{ "dylib", "a" }; + const exts = &[_][]const u8{ "dylib", "tbd", "a" }; for (search_lib_names.items) |l_name| { var found = false; @@ -849,6 +848,9 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { try zld.link(positionals.items, full_out_path, .{ .libs = libs.items, .rpaths = rpaths.items, + .lib_system_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ + "libc", "darwin", "libSystem.B.tbd", + }), }); break :outer; diff --git a/src/link/MachO/Symbol.zig b/src/link/MachO/Symbol.zig index bb97acdf9f..3fc64febe0 100644 --- a/src/link/MachO/Symbol.zig +++ b/src/link/MachO/Symbol.zig @@ -85,7 +85,7 @@ pub const Proxy = struct { base: Symbol, /// Dylib where to locate this symbol. - dylib: ?*Dylib = null, + dylib: *Dylib, pub const base_type: Symbol.Type = .proxy; }; diff --git a/src/link/MachO/Zld.zig b/src/link/MachO/Zld.zig index 9d9a1315bb..58cf51663c 100644 --- a/src/link/MachO/Zld.zig +++ b/src/link/MachO/Zld.zig @@ -16,6 +16,7 @@ const Allocator = mem.Allocator; const Archive = @import("Archive.zig"); const CodeSignature = @import("CodeSignature.zig"); const Dylib = @import("Dylib.zig"); +const LibStub = @import("../tapi.zig").LibStub; const Object = @import("Object.zig"); const Symbol = @import("Symbol.zig"); const Trie = @import("Trie.zig"); @@ -49,7 +50,6 @@ dyld_info_cmd_index: ?u16 = null, symtab_cmd_index: ?u16 = null, dysymtab_cmd_index: ?u16 = null, dylinker_cmd_index: ?u16 = null, -libsystem_cmd_index: ?u16 = null, data_in_code_cmd_index: ?u16 = null, function_starts_cmd_index: ?u16 = null, main_cmd_index: ?u16 = null, @@ -181,6 +181,7 @@ pub fn closeFiles(self: Zld) void { const LinkArgs = struct { libs: []const []const u8, rpaths: []const []const u8, + lib_system_path: []const u8, }; pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: LinkArgs) !void { @@ -222,6 +223,7 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L try self.addRpaths(args.rpaths); try self.parseInputFiles(files); try self.parseLibs(args.libs); + try self.parseLibSystem(args.lib_system_path); try self.resolveSymbols(); try self.resolveStubsAndGotEntries(); try self.updateMetadata(); @@ -324,9 +326,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { dylib.arch = self.arch.?; dylib.name = input.name; dylib.file = input.file; - - const ordinal = @intCast(u16, self.dylibs.items.len); - dylib.ordinal = ordinal + 2; // TODO +2 since 1 is reserved for libSystem + dylib.ordinal = @intCast(u16, self.dylibs.items.len) + 1; // TODO Defer parsing of the dylibs until they are actually needed try dylib.parse(); @@ -361,9 +361,7 @@ fn parseLibs(self: *Zld, libs: []const []const u8) !void { dylib.arch = self.arch.?; dylib.name = try self.allocator.dupe(u8, lib); dylib.file = file; - - const ordinal = @intCast(u16, self.dylibs.items.len); - dylib.ordinal = ordinal + 2; // TODO +2 since 1 is reserved for libSystem + dylib.ordinal = @intCast(u16, self.dylibs.items.len) + 1; // TODO Defer parsing of the dylibs until they are actually needed try dylib.parse(); @@ -398,6 +396,111 @@ fn parseLibs(self: *Zld, libs: []const []const u8) !void { } } +fn hasTarget(targets: []const []const u8, target: []const u8) bool { + for (targets) |t| { + if (mem.eql(u8, t, target)) return true; + } + return false; +} + +fn parseLibSystem(self: *Zld, lib_system_path: []const u8) !void { + const file = try fs.cwd().openFile(lib_system_path, .{}); + + var lib_stub = try LibStub.loadFromFile(self.allocator, file); + defer lib_stub.deinit(); + + const dylib = try self.allocator.create(Dylib); + errdefer self.allocator.destroy(dylib); + + dylib.* = Dylib.init(self.allocator); + dylib.arch = self.arch.?; + dylib.name = try self.allocator.dupe(u8, lib_system_path); + dylib.file = file; + dylib.ordinal = @intCast(u16, self.dylibs.items.len) + 1; + + const umbrella_lib = lib_stub.inner[0]; + dylib.id = .{ + .name = try self.allocator.dupe(u8, umbrella_lib.install_name), + // TODO parse from the stub + .timestamp = 2, + .current_version = 0, + .compatibility_version = 0, + }; + + const target_string: []const u8 = switch (self.arch.?) { + .aarch64 => "arm64-macos", + .x86_64 => "x86_64-macos", + else => unreachable, + }; + + for (lib_stub.inner) |stub| { + if (!hasTarget(stub.targets, target_string)) continue; + + if (stub.exports) |exports| { + for (exports) |exp| { + if (!hasTarget(exp.targets, target_string)) continue; + + for (exp.symbols) |sym_name| { + if (dylib.symbols.contains(sym_name)) continue; + + const name = try self.allocator.dupe(u8, sym_name); + const proxy = try self.allocator.create(Symbol.Proxy); + errdefer self.allocator.destroy(proxy); + + proxy.* = .{ + .base = .{ + .@"type" = .proxy, + .name = name, + }, + .dylib = dylib, + }; + + try dylib.symbols.putNoClobber(self.allocator, name, &proxy.base); + } + } + } + + if (stub.reexports) |reexports| { + for (reexports) |reexp| { + if (!hasTarget(reexp.targets, target_string)) continue; + + for (reexp.symbols) |sym_name| { + if (dylib.symbols.contains(sym_name)) continue; + + const name = try self.allocator.dupe(u8, sym_name); + const proxy = try self.allocator.create(Symbol.Proxy); + errdefer self.allocator.destroy(proxy); + + proxy.* = .{ + .base = .{ + .@"type" = .proxy, + .name = name, + }, + .dylib = dylib, + }; + + try dylib.symbols.putNoClobber(self.allocator, name, &proxy.base); + } + } + } + } + + try self.dylibs.append(self.allocator, dylib); + + // Add LC_LOAD_DYLIB command + 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 }); +} + fn mapAndUpdateSections( self: *Zld, object: *Object, @@ -1814,9 +1917,8 @@ fn resolveSymbols(self: *Zld) !void { next_sym += 1; } } + // Third pass, resolve symbols in dynamic libraries. - // TODO Implement libSystem as a hard-coded library, or ship with - // a libSystem.B.tbd definition file? var unresolved = std.ArrayList(*Symbol).init(self.allocator); defer unresolved.deinit(); @@ -1837,48 +1939,22 @@ fn resolveSymbols(self: *Zld) !void { } if (!found) { - // TODO we currently hardcode all unresolved symbols to libSystem - const proxy = try self.allocator.create(Symbol.Proxy); - errdefer self.allocator.destroy(proxy); - - proxy.* = .{ - .base = .{ - .@"type" = .proxy, - .name = try self.allocator.dupe(u8, undef.name), - }, - .dylib = null, // TODO null means libSystem - }; - - try self.imports.putNoClobber(self.allocator, proxy.base.name, &proxy.base); - undef.alias = &proxy.base; - - // log.err("undefined reference to symbol '{s}'", .{undef.name}); - // log.err(" | referenced in {s}", .{ - // undef.cast(Symbol.Unresolved).?.file.name.?, - // }); - // has_undefined = true; + log.err("undefined reference to symbol '{s}'", .{undef.name}); + log.err(" | referenced in {s}", .{ + undef.cast(Symbol.Unresolved).?.file.name.?, + }); + has_undefined = true; } } if (has_undefined) return error.UndefinedSymbolReference; // Finally put dyld_stub_binder as an Import - const dyld_stub_binder = try self.allocator.create(Symbol.Proxy); - errdefer self.allocator.destroy(dyld_stub_binder); - - dyld_stub_binder.* = .{ - .base = .{ - .@"type" = .proxy, - .name = try self.allocator.dupe(u8, "dyld_stub_binder"), - }, - .dylib = null, // TODO null means libSystem + const proxy = self.dylibs.items[self.dylibs.items.len - 1].symbols.get("dyld_stub_binder") orelse { + log.err("undefined reference to symbol 'dyld_stub_binder'", .{}); + return error.UndefinedSymbolReference; }; - - try self.imports.putNoClobber( - self.allocator, - dyld_stub_binder.base.name, - &dyld_stub_binder.base, - ); + try self.imports.putNoClobber(self.allocator, proxy.name, proxy); } fn resolveStubsAndGotEntries(self: *Zld) !void { @@ -2437,15 +2513,6 @@ fn populateMetadata(self: *Zld) !void { try self.load_commands.append(self.allocator, .{ .Dylinker = dylinker_cmd }); } - if (self.libsystem_cmd_index == null) { - self.libsystem_cmd_index = @intCast(u16, self.load_commands.items.len); - - var dylib_cmd = try createLoadDylibCommand(self.allocator, mem.spanZ(LIB_SYSTEM_PATH), 2, 0, 0); - errdefer dylib_cmd.deinit(self.allocator); - - try self.load_commands.append(self.allocator, .{ .Dylib = dylib_cmd }); - } - if (self.main_cmd_index == null) { self.main_cmd_index = @intCast(u16, self.load_commands.items.len); try self.load_commands.append(self.allocator, .{ @@ -2746,14 +2813,10 @@ fn writeBindInfoTable(self: *Zld) !void { for (self.got_entries.items) |sym| { if (sym.cast(Symbol.Proxy)) |proxy| { - const dylib_ordinal = ordinal: { - const dylib = proxy.dylib orelse break :ordinal 1; // TODO embedded libSystem - break :ordinal dylib.ordinal.?; - }; try pointers.append(.{ .offset = base_offset + proxy.base.got_index.? * @sizeOf(u64), .segment_id = segment_id, - .dylib_ordinal = dylib_ordinal, + .dylib_ordinal = proxy.dylib.ordinal.?, .name = proxy.base.name, }); } @@ -2768,15 +2831,11 @@ fn writeBindInfoTable(self: *Zld) !void { const sym = self.imports.get("__tlv_bootstrap") orelse unreachable; const proxy = sym.cast(Symbol.Proxy) orelse unreachable; - const dylib_ordinal = ordinal: { - const dylib = proxy.dylib orelse break :ordinal 1; // TODO embedded libSystem - break :ordinal dylib.ordinal.?; - }; try pointers.append(.{ .offset = base_offset, .segment_id = segment_id, - .dylib_ordinal = dylib_ordinal, + .dylib_ordinal = proxy.dylib.ordinal.?, .name = proxy.base.name, }); } @@ -2813,15 +2872,10 @@ fn writeLazyBindInfoTable(self: *Zld) !void { for (self.stubs.items) |sym| { const proxy = sym.cast(Symbol.Proxy) orelse unreachable; - const dylib_ordinal = ordinal: { - const dylib = proxy.dylib orelse break :ordinal 1; // TODO embedded libSystem - break :ordinal dylib.ordinal.?; - }; - pointers.appendAssumeCapacity(.{ .offset = base_offset + sym.stubs_index.? * @sizeOf(u64), .segment_id = segment_id, - .dylib_ordinal = dylib_ordinal, + .dylib_ordinal = proxy.dylib.ordinal.?, .name = sym.name, }); } @@ -3128,15 +3182,12 @@ fn writeSymbolTable(self: *Zld) !void { defer undefs.deinit(); for (self.imports.values()) |sym| { - const ordinal = ordinal: { - const dylib = sym.cast(Symbol.Proxy).?.dylib orelse break :ordinal 1; // TODO handle libSystem - break :ordinal dylib.ordinal.?; - }; + const proxy = sym.cast(Symbol.Proxy) orelse unreachable; try undefs.append(.{ .n_strx = try self.makeString(sym.name), .n_type = macho.N_UNDF | macho.N_EXT, .n_sect = 0, - .n_desc = (ordinal * macho.N_SYMBOL_RESOLVER) | macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY, + .n_desc = (proxy.dylib.ordinal.? * macho.N_SYMBOL_RESOLVER) | macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY, .n_value = 0, }); } diff --git a/src/link/tapi.zig b/src/link/tapi.zig index 447485950e..05a23a3aff 100644 --- a/src/link/tapi.zig +++ b/src/link/tapi.zig @@ -21,9 +21,10 @@ pub const LibStub = struct { value: []const u8, }, install_name: []const u8, - current_version: union(enum) { + current_version: ?union(enum) { string: []const u8, - int: u32, + float: f64, + int: u64, }, reexported_libraries: ?[]const struct { targets: []const []const u8, @@ -33,7 +34,11 @@ pub const LibStub = struct { targets: []const []const u8, umbrella: []const u8, }, - exports: []const struct { + exports: ?[]const struct { + targets: []const []const u8, + symbols: []const []const u8, + }, + reexports: ?[]const struct { targets: []const []const u8, symbols: []const []const u8, }, @@ -44,10 +49,7 @@ pub const LibStub = struct { objc_classes: ?[]const []const u8, }; - pub fn loadFromFile(allocator: *Allocator, file_path: []const u8) !LibStub { - const file = try fs.cwd().openFile(file_path, .{}); - defer file.close(); - + pub fn loadFromFile(allocator: *Allocator, file: fs.File) !LibStub { const source = try file.readToEndAlloc(allocator, std.math.maxInt(u32)); defer allocator.free(source); |
