aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2021-06-19 11:35:15 +0200
committerJakub Konka <kubkon@jakubkonka.com>2021-06-24 14:45:45 +0200
commit089577a71df6e22bf1cc3f83489fd2af548c5b81 (patch)
treec3ebe4195ec16fe35b544930446ade6fa20f6fb6 /src
parentfbdc5154184b0752175dcafc5bfdc4ea6a0cfebf (diff)
downloadzig-089577a71df6e22bf1cc3f83489fd2af548c5b81.tar.gz
zig-089577a71df6e22bf1cc3f83489fd2af548c5b81.zip
zld: parse libSystem tbd stub when linking
Diffstat (limited to 'src')
-rw-r--r--src/link/MachO.zig8
-rw-r--r--src/link/MachO/Symbol.zig2
-rw-r--r--src/link/MachO/Zld.zig199
-rw-r--r--src/link/tapi.zig16
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);