Commit 96a0479db2
Changed files (5)
src
src/link/MachO/Archive.zig
@@ -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);
}
src/link/MachO/Dylib.zig
@@ -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;
+}
src/link/MachO/Object.zig
@@ -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;
}
src/link/MachO/Zld.zig
@@ -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,28 +398,55 @@ 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);
-fn hasTarget(targets: []const []const u8, target: []const u8) bool {
- for (targets) |t| {
- if (mem.eql(u8, t, target)) return true;
+ 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});
+ }
+ }
+ }
}
- return false;
}
fn parseLibSystem(self: *Zld, lib_system_path: []const u8) !void {
@@ -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
src/link/tapi.zig
@@ -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;
}