mirror of
https://github.com/ziglang/zig.git
synced 2026-02-06 06:27:05 +00:00
zld: naively parse all dylib deps in stubs
This commit is contained in:
parent
3cb6b6bd90
commit
5ac5cd9de7
@ -789,6 +789,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
|
||||
zld.deinit();
|
||||
}
|
||||
zld.arch = target.cpu.arch;
|
||||
zld.syslibroot = self.base.options.syslibroot;
|
||||
zld.stack_size = stack_size;
|
||||
|
||||
// Positional arguments to the linker such as object files and static archives.
|
||||
|
||||
@ -8,12 +8,13 @@ const macho = std.macho;
|
||||
const mem = std.mem;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Arch = std.Target.Cpu.Arch;
|
||||
const Object = @import("Object.zig");
|
||||
|
||||
usingnamespace @import("commands.zig");
|
||||
|
||||
allocator: *Allocator,
|
||||
arch: ?std.Target.Cpu.Arch = null,
|
||||
arch: ?Arch = null,
|
||||
file: ?fs.File = null,
|
||||
header: ?ar_hdr = null,
|
||||
name: ?[]const u8 = null,
|
||||
@ -85,10 +86,36 @@ const ar_hdr = extern struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub fn init(allocator: *Allocator) Archive {
|
||||
return .{
|
||||
.allocator = allocator,
|
||||
pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u8) !?*Archive {
|
||||
const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {
|
||||
error.FileNotFound => return null,
|
||||
else => |e| return e,
|
||||
};
|
||||
errdefer file.close();
|
||||
|
||||
const archive = try allocator.create(Archive);
|
||||
errdefer allocator.destroy(archive);
|
||||
|
||||
const name = try allocator.dupe(u8, path);
|
||||
errdefer allocator.free(name);
|
||||
|
||||
archive.* = .{
|
||||
.allocator = allocator,
|
||||
.arch = arch,
|
||||
.name = name,
|
||||
.file = file,
|
||||
};
|
||||
|
||||
archive.parse() catch |err| switch (err) {
|
||||
error.EndOfStream, error.NotArchive => {
|
||||
archive.deinit();
|
||||
allocator.destroy(archive);
|
||||
return null;
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
|
||||
return archive;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Archive) void {
|
||||
@ -116,15 +143,15 @@ pub fn parse(self: *Archive) !void {
|
||||
const magic = try reader.readBytesNoEof(SARMAG);
|
||||
|
||||
if (!mem.eql(u8, &magic, ARMAG)) {
|
||||
log.err("invalid magic: expected '{s}', found '{s}'", .{ ARMAG, magic });
|
||||
return error.MalformedArchive;
|
||||
log.debug("invalid magic: expected '{s}', found '{s}'", .{ ARMAG, magic });
|
||||
return error.NotArchive;
|
||||
}
|
||||
|
||||
self.header = try reader.readStruct(ar_hdr);
|
||||
|
||||
if (!mem.eql(u8, &self.header.?.ar_fmag, ARFMAG)) {
|
||||
log.err("invalid header delimiter: expected '{s}', found '{s}'", .{ ARFMAG, self.header.?.ar_fmag });
|
||||
return error.MalformedArchive;
|
||||
log.debug("invalid header delimiter: expected '{s}', found '{s}'", .{ ARFMAG, self.header.?.ar_fmag });
|
||||
return error.NotArchive;
|
||||
}
|
||||
|
||||
var embedded_name = try parseName(self.allocator, self.header.?, reader);
|
||||
@ -222,23 +249,15 @@ pub fn parseObject(self: Archive, offset: u32) !*Object {
|
||||
var object = try self.allocator.create(Object);
|
||||
errdefer self.allocator.destroy(object);
|
||||
|
||||
object.* = Object.init(self.allocator);
|
||||
object.arch = self.arch.?;
|
||||
object.file = try fs.cwd().openFile(self.name.?, .{});
|
||||
object.name = name;
|
||||
object.file_offset = @intCast(u32, try reader.context.getPos());
|
||||
object.* = .{
|
||||
.allocator = self.allocator,
|
||||
.arch = self.arch.?,
|
||||
.file = try fs.cwd().openFile(self.name.?, .{}),
|
||||
.name = name,
|
||||
.file_offset = @intCast(u32, try reader.context.getPos()),
|
||||
};
|
||||
try object.parse();
|
||||
|
||||
try reader.context.seekTo(0);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
pub fn isArchive(file: fs.File) !bool {
|
||||
const magic = file.reader().readBytesNoEof(Archive.SARMAG) catch |err| switch (err) {
|
||||
error.EndOfStream => return false,
|
||||
else => |e| return e,
|
||||
};
|
||||
try file.seekTo(0);
|
||||
return mem.eql(u8, &magic, Archive.ARMAG);
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ const macho = std.macho;
|
||||
const mem = std.mem;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Arch = std.Target.Cpu.Arch;
|
||||
const Symbol = @import("Symbol.zig");
|
||||
const LibStub = @import("../tapi.zig").LibStub;
|
||||
|
||||
@ -15,10 +16,11 @@ usingnamespace @import("commands.zig");
|
||||
|
||||
allocator: *Allocator,
|
||||
|
||||
arch: ?std.Target.Cpu.Arch = null,
|
||||
arch: ?Arch = null,
|
||||
header: ?macho.mach_header_64 = null,
|
||||
file: ?fs.File = null,
|
||||
name: ?[]const u8 = null,
|
||||
syslibroot: ?[]const u8 = null,
|
||||
|
||||
ordinal: ?u16 = null,
|
||||
|
||||
@ -35,6 +37,11 @@ id: ?Id = null,
|
||||
/// a symbol is referenced by an object file.
|
||||
symbols: std.StringArrayHashMapUnmanaged(void) = .{},
|
||||
|
||||
// TODO we should keep track of already parsed dylibs so that
|
||||
// we don't unnecessarily reparse them again.
|
||||
// TODO add dylib dep analysis and extraction for .dylib files.
|
||||
dylibs: std.ArrayListUnmanaged(*Dylib) = .{},
|
||||
|
||||
pub const Id = struct {
|
||||
name: []const u8,
|
||||
timestamp: u32,
|
||||
@ -46,8 +53,57 @@ pub const Id = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub fn init(allocator: *Allocator) Dylib {
|
||||
return .{ .allocator = allocator };
|
||||
pub const Error = error{
|
||||
OutOfMemory,
|
||||
EmptyStubFile,
|
||||
MismatchedCpuArchitecture,
|
||||
UnsupportedCpuArchitecture,
|
||||
} || fs.File.OpenError || std.os.PReadError;
|
||||
|
||||
pub fn createAndParseFromPath(
|
||||
allocator: *Allocator,
|
||||
arch: Arch,
|
||||
path: []const u8,
|
||||
syslibroot: ?[]const u8,
|
||||
recurse_libs: bool,
|
||||
) Error!?*Dylib {
|
||||
const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {
|
||||
error.FileNotFound => return null,
|
||||
else => |e| return e,
|
||||
};
|
||||
errdefer file.close();
|
||||
|
||||
const dylib = try allocator.create(Dylib);
|
||||
errdefer allocator.destroy(dylib);
|
||||
|
||||
const name = try allocator.dupe(u8, path);
|
||||
errdefer allocator.free(name);
|
||||
|
||||
dylib.* = .{
|
||||
.allocator = allocator,
|
||||
.arch = arch,
|
||||
.name = name,
|
||||
.file = file,
|
||||
.syslibroot = syslibroot,
|
||||
};
|
||||
|
||||
dylib.parse(recurse_libs) catch |err| switch (err) {
|
||||
error.EndOfStream, error.NotDylib => {
|
||||
try file.seekTo(0);
|
||||
|
||||
var lib_stub = LibStub.loadFromFile(allocator, file) catch {
|
||||
dylib.deinit();
|
||||
allocator.destroy(dylib);
|
||||
return null;
|
||||
};
|
||||
defer lib_stub.deinit();
|
||||
|
||||
try dylib.parseFromStub(lib_stub, recurse_libs);
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
|
||||
return dylib;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Dylib) void {
|
||||
@ -60,6 +116,7 @@ pub fn deinit(self: *Dylib) void {
|
||||
self.allocator.free(key);
|
||||
}
|
||||
self.symbols.deinit(self.allocator);
|
||||
self.dylibs.deinit(self.allocator);
|
||||
|
||||
if (self.name) |name| {
|
||||
self.allocator.free(name);
|
||||
@ -76,15 +133,15 @@ pub fn closeFile(self: Dylib) void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(self: *Dylib) !void {
|
||||
pub fn parse(self: *Dylib, recurse_libs: bool) !void {
|
||||
log.debug("parsing shared library '{s}'", .{self.name.?});
|
||||
|
||||
var reader = self.file.?.reader();
|
||||
self.header = try reader.readStruct(macho.mach_header_64);
|
||||
|
||||
if (self.header.?.filetype != macho.MH_DYLIB) {
|
||||
log.err("invalid filetype: expected 0x{x}, found 0x{x}", .{ macho.MH_DYLIB, self.header.?.filetype });
|
||||
return error.MalformedDylib;
|
||||
log.debug("invalid filetype: expected 0x{x}, found 0x{x}", .{ macho.MH_DYLIB, self.header.?.filetype });
|
||||
return error.NotDylib;
|
||||
}
|
||||
|
||||
const this_arch: std.Target.Cpu.Arch = switch (self.header.?.cputype) {
|
||||
@ -190,7 +247,7 @@ fn addObjCClassSymbols(self: *Dylib, sym_name: []const u8) !void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parseFromStub(self: *Dylib, lib_stub: LibStub) !void {
|
||||
pub fn parseFromStub(self: *Dylib, lib_stub: LibStub, recurse_libs: bool) !void {
|
||||
if (lib_stub.inner.len == 0) return error.EmptyStubFile;
|
||||
|
||||
log.debug("parsing shared library from stub '{s}'", .{self.name.?});
|
||||
@ -236,9 +293,17 @@ pub fn parseFromStub(self: *Dylib, lib_stub: LibStub) !void {
|
||||
for (reexports) |reexp| {
|
||||
if (!hasTarget(reexp.targets, target_string)) continue;
|
||||
|
||||
for (reexp.symbols) |sym_name| {
|
||||
if (self.symbols.contains(sym_name)) continue;
|
||||
try self.symbols.putNoClobber(self.allocator, try self.allocator.dupe(u8, sym_name), {});
|
||||
if (reexp.symbols) |symbols| {
|
||||
for (symbols) |sym_name| {
|
||||
if (self.symbols.contains(sym_name)) continue;
|
||||
try self.symbols.putNoClobber(self.allocator, try self.allocator.dupe(u8, sym_name), {});
|
||||
}
|
||||
}
|
||||
|
||||
if (reexp.objc_classes) |classes| {
|
||||
for (classes) |sym_name| {
|
||||
try self.addObjCClassSymbols(sym_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -249,6 +314,60 @@ pub fn parseFromStub(self: *Dylib, lib_stub: LibStub) !void {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (lib_stub.inner) |stub| {
|
||||
if (!hasTarget(stub.targets, target_string)) continue;
|
||||
|
||||
if (stub.reexported_libraries) |reexports| reexports: {
|
||||
if (!recurse_libs) break :reexports;
|
||||
|
||||
for (reexports) |reexp| {
|
||||
if (!hasTarget(reexp.targets, target_string)) continue;
|
||||
|
||||
outer: for (reexp.libraries) |lib| {
|
||||
const dirname = fs.path.dirname(lib) orelse {
|
||||
log.warn("unable to resolve dependency {s}", .{lib});
|
||||
continue;
|
||||
};
|
||||
const filename = fs.path.basename(lib);
|
||||
const without_ext = if (mem.lastIndexOfScalar(u8, filename, '.')) |index|
|
||||
filename[0..index]
|
||||
else
|
||||
filename;
|
||||
|
||||
for (&[_][]const u8{ "dylib", "tbd" }) |ext| {
|
||||
const with_ext = try std.fmt.allocPrint(self.allocator, "{s}.{s}", .{
|
||||
without_ext,
|
||||
ext,
|
||||
});
|
||||
defer self.allocator.free(with_ext);
|
||||
|
||||
const lib_path = if (self.syslibroot) |syslibroot|
|
||||
try fs.path.join(self.allocator, &.{ syslibroot, dirname, with_ext })
|
||||
else
|
||||
try fs.path.join(self.allocator, &.{ dirname, with_ext });
|
||||
|
||||
log.debug("trying dependency at fully resolved path {s}", .{lib_path});
|
||||
|
||||
const dylib = (try createAndParseFromPath(
|
||||
self.allocator,
|
||||
self.arch.?,
|
||||
lib_path,
|
||||
self.syslibroot,
|
||||
true,
|
||||
)) orelse {
|
||||
continue;
|
||||
};
|
||||
|
||||
try self.dylibs.append(self.allocator, dylib);
|
||||
continue :outer;
|
||||
} else {
|
||||
log.warn("unable to resolve dependency {s}", .{lib});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn hasTarget(targets: []const []const u8, target: []const u8) bool {
|
||||
@ -258,15 +377,6 @@ fn hasTarget(targets: []const []const u8, target: []const u8) bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn isDylib(file: fs.File) !bool {
|
||||
const header = file.reader().readStruct(macho.mach_header_64) catch |err| switch (err) {
|
||||
error.EndOfStream => return false,
|
||||
else => |e| return e,
|
||||
};
|
||||
try file.seekTo(0);
|
||||
return header.filetype == macho.MH_DYLIB;
|
||||
}
|
||||
|
||||
pub fn createProxy(self: *Dylib, sym_name: []const u8) !?*Symbol {
|
||||
if (!self.symbols.contains(sym_name)) return null;
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@ const mem = std.mem;
|
||||
const reloc = @import("reloc.zig");
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Arch = std.Target.Cpu.Arch;
|
||||
const Relocation = reloc.Relocation;
|
||||
const Symbol = @import("Symbol.zig");
|
||||
const parseName = @import("Zld.zig").parseName;
|
||||
@ -18,7 +19,7 @@ const parseName = @import("Zld.zig").parseName;
|
||||
usingnamespace @import("commands.zig");
|
||||
|
||||
allocator: *Allocator,
|
||||
arch: ?std.Target.Cpu.Arch = null,
|
||||
arch: ?Arch = null,
|
||||
header: ?macho.mach_header_64 = null,
|
||||
file: ?fs.File = null,
|
||||
file_offset: ?u32 = null,
|
||||
@ -173,10 +174,36 @@ const DebugInfo = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub fn init(allocator: *Allocator) Object {
|
||||
return .{
|
||||
.allocator = allocator,
|
||||
pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u8) !?*Object {
|
||||
const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {
|
||||
error.FileNotFound => return null,
|
||||
else => |e| return e,
|
||||
};
|
||||
errdefer file.close();
|
||||
|
||||
const object = try allocator.create(Object);
|
||||
errdefer allocator.destroy(object);
|
||||
|
||||
const name = try allocator.dupe(u8, path);
|
||||
errdefer allocator.free(name);
|
||||
|
||||
object.* = .{
|
||||
.allocator = allocator,
|
||||
.arch = arch,
|
||||
.name = name,
|
||||
.file = file,
|
||||
};
|
||||
|
||||
object.parse() catch |err| switch (err) {
|
||||
error.EndOfStream, error.NotObject => {
|
||||
object.deinit();
|
||||
allocator.destroy(object);
|
||||
return null;
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Object) void {
|
||||
@ -223,11 +250,15 @@ pub fn parse(self: *Object) !void {
|
||||
self.header = try reader.readStruct(macho.mach_header_64);
|
||||
|
||||
if (self.header.?.filetype != macho.MH_OBJECT) {
|
||||
log.err("invalid filetype: expected 0x{x}, found 0x{x}", .{ macho.MH_OBJECT, self.header.?.filetype });
|
||||
return error.MalformedObject;
|
||||
log.debug("invalid filetype: expected 0x{x}, found 0x{x}", .{
|
||||
macho.MH_OBJECT,
|
||||
self.header.?.filetype,
|
||||
});
|
||||
|
||||
return error.NotObject;
|
||||
}
|
||||
|
||||
const this_arch: std.Target.Cpu.Arch = switch (self.header.?.cputype) {
|
||||
const this_arch: Arch = switch (self.header.?.cputype) {
|
||||
macho.CPU_TYPE_ARM64 => .aarch64,
|
||||
macho.CPU_TYPE_X86_64 => .x86_64,
|
||||
else => |value| {
|
||||
@ -533,12 +564,3 @@ pub fn parseDataInCode(self: *Object) !void {
|
||||
try self.data_in_code_entries.append(self.allocator, dice);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn isObject(file: fs.File) !bool {
|
||||
const header = file.reader().readStruct(macho.mach_header_64) catch |err| switch (err) {
|
||||
error.EndOfStream => return false,
|
||||
else => |e| return e,
|
||||
};
|
||||
try file.seekTo(0);
|
||||
return header.filetype == macho.MH_OBJECT;
|
||||
}
|
||||
|
||||
@ -16,7 +16,6 @@ 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");
|
||||
@ -33,6 +32,7 @@ out_path: ?[]const u8 = null,
|
||||
|
||||
// TODO these args will become obselete once Zld is coalesced with incremental
|
||||
// linker.
|
||||
syslibroot: ?[]const u8 = null,
|
||||
stack_size: u64 = 0,
|
||||
|
||||
objects: std.ArrayListUnmanaged(*Object) = .{},
|
||||
@ -257,214 +257,90 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L
|
||||
}
|
||||
|
||||
fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
|
||||
const Input = struct {
|
||||
kind: union(enum) {
|
||||
object: fs.File,
|
||||
archive: fs.File,
|
||||
dylib: fs.File,
|
||||
stub: LibStub,
|
||||
},
|
||||
name: []const u8,
|
||||
|
||||
fn deinit(input: *@This()) void {
|
||||
switch (input.kind) {
|
||||
.stub => |*stub| {
|
||||
stub.deinit();
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
};
|
||||
var classified = std.ArrayList(Input).init(self.allocator);
|
||||
defer {
|
||||
for (classified.items) |*input| {
|
||||
input.deinit();
|
||||
}
|
||||
classified.deinit();
|
||||
}
|
||||
|
||||
// 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: {
|
||||
var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
|
||||
const path = try std.fs.realpath(file_name, &buffer);
|
||||
break :full_path try self.allocator.dupe(u8, path);
|
||||
};
|
||||
|
||||
try_object: {
|
||||
if (!(try Object.isObject(file))) break :try_object;
|
||||
try classified.append(.{
|
||||
.kind = .{ .object = file },
|
||||
.name = full_path,
|
||||
});
|
||||
if (try Object.createAndParseFromPath(self.allocator, self.arch.?, full_path)) |object| {
|
||||
try self.objects.append(self.allocator, object);
|
||||
continue;
|
||||
}
|
||||
|
||||
try_archive: {
|
||||
if (!(try Archive.isArchive(file))) break :try_archive;
|
||||
try classified.append(.{
|
||||
.kind = .{ .archive = file },
|
||||
.name = full_path,
|
||||
});
|
||||
if (try Archive.createAndParseFromPath(self.allocator, self.arch.?, full_path)) |archive| {
|
||||
try self.archives.append(self.allocator, archive);
|
||||
continue;
|
||||
}
|
||||
|
||||
try_dylib: {
|
||||
if (!(try Dylib.isDylib(file))) break :try_dylib;
|
||||
try classified.append(.{
|
||||
.kind = .{ .dylib = file },
|
||||
.name = full_path,
|
||||
});
|
||||
if (try Dylib.createAndParseFromPath(
|
||||
self.allocator,
|
||||
self.arch.?,
|
||||
full_path,
|
||||
self.syslibroot,
|
||||
true,
|
||||
)) |dylib| {
|
||||
try self.dylibs.append(self.allocator, dylib);
|
||||
continue;
|
||||
}
|
||||
|
||||
try_stub: {
|
||||
var lib_stub = LibStub.loadFromFile(self.allocator, file) catch {
|
||||
break :try_stub;
|
||||
};
|
||||
try classified.append(.{
|
||||
.kind = .{ .stub = lib_stub },
|
||||
.name = full_path,
|
||||
});
|
||||
file.close();
|
||||
continue;
|
||||
}
|
||||
|
||||
file.close();
|
||||
log.warn("unknown filetype for positional input file: '{s}'", .{file_name});
|
||||
}
|
||||
|
||||
// Based on our classification, proceed with parsing.
|
||||
for (classified.items) |input| {
|
||||
switch (input.kind) {
|
||||
.object => |file| {
|
||||
const object = try self.allocator.create(Object);
|
||||
errdefer self.allocator.destroy(object);
|
||||
|
||||
object.* = Object.init(self.allocator);
|
||||
object.arch = self.arch.?;
|
||||
object.name = input.name;
|
||||
object.file = file;
|
||||
|
||||
try object.parse();
|
||||
try self.objects.append(self.allocator, object);
|
||||
},
|
||||
.archive => |file| {
|
||||
const archive = try self.allocator.create(Archive);
|
||||
errdefer self.allocator.destroy(archive);
|
||||
|
||||
archive.* = Archive.init(self.allocator);
|
||||
archive.arch = self.arch.?;
|
||||
archive.name = input.name;
|
||||
archive.file = file;
|
||||
|
||||
try archive.parse();
|
||||
try self.archives.append(self.allocator, archive);
|
||||
},
|
||||
.dylib, .stub => {
|
||||
const dylib = try self.allocator.create(Dylib);
|
||||
errdefer self.allocator.destroy(dylib);
|
||||
|
||||
dylib.* = Dylib.init(self.allocator);
|
||||
dylib.arch = self.arch.?;
|
||||
dylib.name = input.name;
|
||||
|
||||
if (input.kind == .dylib) {
|
||||
dylib.file = input.kind.dylib;
|
||||
try dylib.parse();
|
||||
} else {
|
||||
try dylib.parseFromStub(input.kind.stub);
|
||||
}
|
||||
|
||||
try self.dylibs.append(self.allocator, dylib);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parseLibs(self: *Zld, libs: []const []const u8) !void {
|
||||
for (libs) |lib| {
|
||||
const file = try fs.cwd().openFile(lib, .{});
|
||||
|
||||
var kind: ?union(enum) {
|
||||
archive,
|
||||
dylib,
|
||||
stub: LibStub,
|
||||
} = kind: {
|
||||
if (try Archive.isArchive(file)) break :kind .archive;
|
||||
if (try Dylib.isDylib(file)) break :kind .dylib;
|
||||
var lib_stub = LibStub.loadFromFile(self.allocator, file) catch {
|
||||
break :kind null;
|
||||
};
|
||||
break :kind .{ .stub = lib_stub };
|
||||
};
|
||||
defer {
|
||||
if (kind) |*kk| {
|
||||
switch (kk.*) {
|
||||
.stub => |*stub| {
|
||||
stub.deinit();
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
const DylibDeps = struct {
|
||||
fn bubbleUp(out: *std.ArrayList(*Dylib), next: *Dylib) error{OutOfMemory}!void {
|
||||
try out.ensureUnusedCapacity(next.dylibs.items.len);
|
||||
for (next.dylibs.items) |dylib| {
|
||||
out.appendAssumeCapacity(dylib);
|
||||
}
|
||||
for (next.dylibs.items) |dylib| {
|
||||
try bubbleUp(out, dylib);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const unwrapped = kind orelse {
|
||||
file.close();
|
||||
log.warn("unknown filetype for a library: '{s}'", .{lib});
|
||||
for (libs) |lib| {
|
||||
if (try Dylib.createAndParseFromPath(
|
||||
self.allocator,
|
||||
self.arch.?,
|
||||
lib,
|
||||
self.syslibroot,
|
||||
true,
|
||||
)) |dylib| {
|
||||
try self.dylibs.append(self.allocator, dylib);
|
||||
continue;
|
||||
};
|
||||
switch (unwrapped) {
|
||||
.archive => {
|
||||
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);
|
||||
},
|
||||
.dylib, .stub => {
|
||||
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);
|
||||
|
||||
if (unwrapped == .dylib) {
|
||||
dylib.file = file;
|
||||
try dylib.parse();
|
||||
} else {
|
||||
try dylib.parseFromStub(unwrapped.stub);
|
||||
}
|
||||
|
||||
try self.dylibs.append(self.allocator, dylib);
|
||||
},
|
||||
}
|
||||
|
||||
if (try Archive.createAndParseFromPath(self.allocator, self.arch.?, lib)) |archive| {
|
||||
try self.archives.append(self.allocator, archive);
|
||||
continue;
|
||||
}
|
||||
|
||||
log.warn("unknown filetype for a library: '{s}'", .{lib});
|
||||
}
|
||||
|
||||
// Flatten out any parsed dependencies.
|
||||
var deps = std.ArrayList(*Dylib).init(self.allocator);
|
||||
defer deps.deinit();
|
||||
|
||||
for (self.dylibs.items) |dylib| {
|
||||
try DylibDeps.bubbleUp(&deps, dylib);
|
||||
}
|
||||
|
||||
try self.dylibs.appendSlice(self.allocator, deps.toOwnedSlice());
|
||||
}
|
||||
|
||||
fn parseLibSystem(self: *Zld, libc_stub_path: []const u8) !void {
|
||||
const file = try fs.cwd().openFile(libc_stub_path, .{});
|
||||
defer file.close();
|
||||
|
||||
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, libc_stub_path);
|
||||
|
||||
try dylib.parseFromStub(lib_stub);
|
||||
|
||||
const dylib = (try Dylib.createAndParseFromPath(
|
||||
self.allocator,
|
||||
self.arch.?,
|
||||
libc_stub_path,
|
||||
self.syslibroot,
|
||||
false,
|
||||
)) orelse return error.FailedToParseLibSystem;
|
||||
self.libsystem_dylib_index = @intCast(u16, self.dylibs.items.len);
|
||||
try self.dylibs.append(self.allocator, dylib);
|
||||
|
||||
|
||||
@ -41,7 +41,8 @@ pub const LibStub = struct {
|
||||
},
|
||||
reexports: ?[]const struct {
|
||||
targets: []const []const u8,
|
||||
symbols: []const []const u8,
|
||||
symbols: ?[]const []const u8,
|
||||
objc_classes: ?[]const []const u8,
|
||||
},
|
||||
allowable_clients: ?[]const struct {
|
||||
targets: []const []const u8,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user