mirror of
https://github.com/ziglang/zig.git
synced 2026-01-17 04:45:20 +00:00
zld: parse lib stubs as tbds on the linker line
This commit is contained in:
parent
089577a71d
commit
96a0479db2
@ -234,8 +234,8 @@ pub fn parseObject(self: Archive, offset: u32) !*Object {
|
||||
return object;
|
||||
}
|
||||
|
||||
pub fn isArchive(file: fs.File) !bool {
|
||||
const magic = try file.reader().readBytesNoEof(Archive.SARMAG);
|
||||
try file.seekTo(0);
|
||||
pub fn isArchive(file: fs.File) bool {
|
||||
const magic = file.reader().readBytesNoEof(Archive.SARMAG) catch return false;
|
||||
file.seekTo(0) catch return false;
|
||||
return mem.eql(u8, &magic, Archive.ARMAG);
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
const Dylib = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const fs = std.fs;
|
||||
const log = std.log.scoped(.dylib);
|
||||
const macho = std.macho;
|
||||
@ -8,6 +9,7 @@ const mem = std.mem;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Symbol = @import("Symbol.zig");
|
||||
const LibStub = @import("../tapi.zig").LibStub;
|
||||
|
||||
usingnamespace @import("commands.zig");
|
||||
|
||||
@ -184,8 +186,88 @@ pub fn parseSymbols(self: *Dylib) !void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn isDylib(file: fs.File) !bool {
|
||||
const header = try file.reader().readStruct(macho.mach_header_64);
|
||||
try file.seekTo(0);
|
||||
pub fn isDylib(file: fs.File) bool {
|
||||
const header = file.reader().readStruct(macho.mach_header_64) catch return false;
|
||||
file.seekTo(0) catch return false;
|
||||
return header.filetype == macho.MH_DYLIB;
|
||||
}
|
||||
|
||||
pub fn parseFromStub(self: *Dylib, lib_stub: LibStub) !void {
|
||||
assert(lib_stub.inner.len > 0);
|
||||
|
||||
log.debug("parsing shared library from stub '{s}'", .{self.name.?});
|
||||
|
||||
const umbrella_lib = lib_stub.inner[0];
|
||||
self.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 (self.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 = self,
|
||||
};
|
||||
|
||||
try self.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 (self.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 = self,
|
||||
};
|
||||
|
||||
try self.symbols.putNoClobber(self.allocator, name, &proxy.base);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn hasTarget(targets: []const []const u8, target: []const u8) bool {
|
||||
for (targets) |t| {
|
||||
if (mem.eql(u8, t, target)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -534,8 +534,8 @@ pub fn parseDataInCode(self: *Object) !void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn isObject(file: fs.File) !bool {
|
||||
const header = try file.reader().readStruct(macho.mach_header_64);
|
||||
try file.seekTo(0);
|
||||
pub fn isObject(file: fs.File) bool {
|
||||
const header = file.reader().readStruct(macho.mach_header_64) catch return false;
|
||||
file.seekTo(0) catch return false;
|
||||
return header.filetype == macho.MH_OBJECT;
|
||||
}
|
||||
|
||||
@ -243,14 +243,16 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
|
||||
object,
|
||||
archive,
|
||||
dylib,
|
||||
stub,
|
||||
},
|
||||
file: fs.File,
|
||||
name: []const u8,
|
||||
stub: ?LibStub = null,
|
||||
};
|
||||
var classified = std.ArrayList(Input).init(self.allocator);
|
||||
defer classified.deinit();
|
||||
|
||||
// First, classify input files: object, archive or dylib.
|
||||
// First, classify input files: object, archive, dylib or stub (tbd).
|
||||
for (files) |file_name| {
|
||||
const file = try fs.cwd().openFile(file_name, .{});
|
||||
const full_path = full_path: {
|
||||
@ -260,7 +262,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
|
||||
};
|
||||
|
||||
try_object: {
|
||||
if (!(try Object.isObject(file))) break :try_object;
|
||||
if (!Object.isObject(file)) break :try_object;
|
||||
try classified.append(.{
|
||||
.kind = .object,
|
||||
.file = file,
|
||||
@ -270,7 +272,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
|
||||
}
|
||||
|
||||
try_archive: {
|
||||
if (!(try Archive.isArchive(file))) break :try_archive;
|
||||
if (!Archive.isArchive(file)) break :try_archive;
|
||||
try classified.append(.{
|
||||
.kind = .archive,
|
||||
.file = file,
|
||||
@ -280,7 +282,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
|
||||
}
|
||||
|
||||
try_dylib: {
|
||||
if (!(try Dylib.isDylib(file))) break :try_dylib;
|
||||
if (!Dylib.isDylib(file)) break :try_dylib;
|
||||
try classified.append(.{
|
||||
.kind = .dylib,
|
||||
.file = file,
|
||||
@ -289,6 +291,19 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
|
||||
continue;
|
||||
}
|
||||
|
||||
try_stub: {
|
||||
var lib_stub = LibStub.loadFromFile(self.allocator, file) catch |_| {
|
||||
break :try_stub;
|
||||
};
|
||||
try classified.append(.{
|
||||
.kind = .stub,
|
||||
.file = file,
|
||||
.name = full_path,
|
||||
.stub = lib_stub,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
file.close();
|
||||
log.warn("unknown filetype for positional input file: '{s}'", .{file_name});
|
||||
}
|
||||
@ -318,7 +333,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
|
||||
try archive.parse();
|
||||
try self.archives.append(self.allocator, archive);
|
||||
},
|
||||
.dylib => {
|
||||
.dylib, .stub => {
|
||||
const dylib = try self.allocator.create(Dylib);
|
||||
errdefer self.allocator.destroy(dylib);
|
||||
|
||||
@ -329,7 +344,11 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
|
||||
dylib.ordinal = @intCast(u16, self.dylibs.items.len) + 1;
|
||||
|
||||
// TODO Defer parsing of the dylibs until they are actually needed
|
||||
try dylib.parse();
|
||||
if (input.stub) |stub| {
|
||||
try dylib.parseFromStub(stub);
|
||||
} else {
|
||||
try dylib.parse();
|
||||
}
|
||||
try self.dylibs.append(self.allocator, dylib);
|
||||
|
||||
// Add LC_LOAD_DYLIB command
|
||||
@ -353,7 +372,7 @@ fn parseLibs(self: *Zld, libs: []const []const u8) !void {
|
||||
for (libs) |lib| {
|
||||
const file = try fs.cwd().openFile(lib, .{});
|
||||
|
||||
if (try Dylib.isDylib(file)) {
|
||||
if (Dylib.isDylib(file)) {
|
||||
const dylib = try self.allocator.create(Dylib);
|
||||
errdefer self.allocator.destroy(dylib);
|
||||
|
||||
@ -379,30 +398,57 @@ fn parseLibs(self: *Zld, libs: []const []const u8) !void {
|
||||
errdefer dylib_cmd.deinit(self.allocator);
|
||||
|
||||
try self.load_commands.append(self.allocator, .{ .Dylib = dylib_cmd });
|
||||
} else if (try Archive.isArchive(file)) {
|
||||
const archive = try self.allocator.create(Archive);
|
||||
errdefer self.allocator.destroy(archive);
|
||||
|
||||
archive.* = Archive.init(self.allocator);
|
||||
archive.arch = self.arch.?;
|
||||
archive.name = try self.allocator.dupe(u8, lib);
|
||||
archive.file = file;
|
||||
try archive.parse();
|
||||
try self.archives.append(self.allocator, archive);
|
||||
} else {
|
||||
file.close();
|
||||
log.warn("unknown filetype for a library: '{s}'", .{lib});
|
||||
// Try tbd stub file next.
|
||||
if (LibStub.loadFromFile(self.allocator, file)) |*lib_stub| {
|
||||
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);
|
||||
dylib.file = file;
|
||||
dylib.ordinal = @intCast(u16, self.dylibs.items.len) + 1;
|
||||
|
||||
try dylib.parseFromStub(lib_stub.*);
|
||||
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 });
|
||||
} else |_| {
|
||||
// TODO this entire logic has to be cleaned up.
|
||||
try file.seekTo(0);
|
||||
if (Archive.isArchive(file)) {
|
||||
const archive = try self.allocator.create(Archive);
|
||||
errdefer self.allocator.destroy(archive);
|
||||
|
||||
archive.* = Archive.init(self.allocator);
|
||||
archive.arch = self.arch.?;
|
||||
archive.name = try self.allocator.dupe(u8, lib);
|
||||
archive.file = file;
|
||||
try archive.parse();
|
||||
try self.archives.append(self.allocator, archive);
|
||||
} else {
|
||||
file.close();
|
||||
log.warn("unknown filetype for a library: '{s}'", .{lib});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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, .{});
|
||||
|
||||
@ -418,73 +464,7 @@ fn parseLibSystem(self: *Zld, lib_system_path: []const u8) !void {
|
||||
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 dylib.parseFromStub(lib_stub);
|
||||
try self.dylibs.append(self.allocator, dylib);
|
||||
|
||||
// Add LC_LOAD_DYLIB command
|
||||
|
||||
@ -58,7 +58,17 @@ pub const LibStub = struct {
|
||||
.inner = undefined,
|
||||
};
|
||||
|
||||
lib_stub.inner = try lib_stub.yaml.parse([]Tbd);
|
||||
lib_stub.inner = lib_stub.yaml.parse([]Tbd) catch |err| blk: {
|
||||
switch (err) {
|
||||
error.TypeMismatch => {
|
||||
// TODO clean this up.
|
||||
var out = try lib_stub.yaml.arena.allocator.alloc(Tbd, 1);
|
||||
out[0] = try lib_stub.yaml.parse(Tbd);
|
||||
break :blk out;
|
||||
},
|
||||
else => |e| return e,
|
||||
}
|
||||
};
|
||||
|
||||
return lib_stub;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user