mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
zld: parse libSystem tbd stub when linking
This commit is contained in:
parent
fbdc515418
commit
089577a71d
3690
lib/libc/darwin/libSystem.B.tbd
vendored
Normal file
3690
lib/libc/darwin/libSystem.B.tbd
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
@ -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,
|
||||
});
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user