mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 21:08:36 +00:00
zld: merge Stub with Dylib struct
After giving it more thought, it doesn't make sense to separate the two structurally. Instead, there should be two constructors for a Dylib struct: one from binary file, and the other from a stub file. This cleans up a lot of code and opens the way for recursive parsing of re-exports from a dylib which are a hard requirement for native feel when linking frameworks.
This commit is contained in:
parent
3f57468c8b
commit
3cb6b6bd90
@ -579,7 +579,6 @@ set(ZIG_STAGE2_SOURCES
|
||||
"${CMAKE_SOURCE_DIR}/src/link/MachO/DebugSymbols.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/MachO/Dylib.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/MachO/Object.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/MachO/Stub.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/MachO/Symbol.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/MachO/Trie.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/MachO/Zld.zig"
|
||||
|
||||
@ -9,10 +9,12 @@ const mem = std.mem;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Symbol = @import("Symbol.zig");
|
||||
const LibStub = @import("../tapi.zig").LibStub;
|
||||
|
||||
usingnamespace @import("commands.zig");
|
||||
|
||||
allocator: *Allocator,
|
||||
|
||||
arch: ?std.Target.Cpu.Arch = null,
|
||||
header: ?macho.mach_header_64 = null,
|
||||
file: ?fs.File = null,
|
||||
@ -103,7 +105,7 @@ pub fn parse(self: *Dylib) !void {
|
||||
try self.parseSymbols();
|
||||
}
|
||||
|
||||
pub fn readLoadCommands(self: *Dylib, reader: anytype) !void {
|
||||
fn readLoadCommands(self: *Dylib, reader: anytype) !void {
|
||||
try self.load_commands.ensureCapacity(self.allocator, self.header.?.ncmds);
|
||||
|
||||
var i: u16 = 0;
|
||||
@ -127,7 +129,7 @@ pub fn readLoadCommands(self: *Dylib, reader: anytype) !void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parseId(self: *Dylib) !void {
|
||||
fn parseId(self: *Dylib) !void {
|
||||
const index = self.id_cmd_index orelse {
|
||||
log.debug("no LC_ID_DYLIB load command found; using hard-coded defaults...", .{});
|
||||
self.id = .{
|
||||
@ -153,7 +155,7 @@ pub fn parseId(self: *Dylib) !void {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn parseSymbols(self: *Dylib) !void {
|
||||
fn parseSymbols(self: *Dylib) !void {
|
||||
const index = self.symtab_cmd_index orelse return;
|
||||
const symtab_cmd = self.load_commands.items[index].Symtab;
|
||||
|
||||
@ -176,6 +178,86 @@ pub fn parseSymbols(self: *Dylib) !void {
|
||||
}
|
||||
}
|
||||
|
||||
fn addObjCClassSymbols(self: *Dylib, sym_name: []const u8) !void {
|
||||
const expanded = &[_][]const u8{
|
||||
try std.fmt.allocPrint(self.allocator, "_OBJC_CLASS_$_{s}", .{sym_name}),
|
||||
try std.fmt.allocPrint(self.allocator, "_OBJC_METACLASS_$_{s}", .{sym_name}),
|
||||
};
|
||||
|
||||
for (expanded) |sym| {
|
||||
if (self.symbols.contains(sym)) continue;
|
||||
try self.symbols.putNoClobber(self.allocator, sym, .{});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parseFromStub(self: *Dylib, lib_stub: LibStub) !void {
|
||||
if (lib_stub.inner.len == 0) return error.EmptyStubFile;
|
||||
|
||||
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;
|
||||
|
||||
if (exp.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 (exp.objc_classes) |classes| {
|
||||
for (classes) |sym_name| {
|
||||
try self.addObjCClassSymbols(sym_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
try self.symbols.putNoClobber(self.allocator, try self.allocator.dupe(u8, sym_name), {});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stub.objc_classes) |classes| {
|
||||
for (classes) |sym_name| {
|
||||
try self.addObjCClassSymbols(sym_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn hasTarget(targets: []const []const u8, target: []const u8) bool {
|
||||
for (targets) |t| {
|
||||
if (mem.eql(u8, t, target)) return true;
|
||||
}
|
||||
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,
|
||||
@ -197,7 +279,7 @@ pub fn createProxy(self: *Dylib, sym_name: []const u8) !?*Symbol {
|
||||
.@"type" = .proxy,
|
||||
.name = name,
|
||||
},
|
||||
.file = .{ .dylib = self },
|
||||
.file = self,
|
||||
};
|
||||
|
||||
return &proxy.base;
|
||||
|
||||
@ -1,159 +0,0 @@
|
||||
const Stub = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const fs = std.fs;
|
||||
const log = std.log.scoped(.stub);
|
||||
const macho = std.macho;
|
||||
const mem = std.mem;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Symbol = @import("Symbol.zig");
|
||||
pub const LibStub = @import("../tapi.zig").LibStub;
|
||||
|
||||
allocator: *Allocator,
|
||||
arch: ?std.Target.Cpu.Arch = null,
|
||||
lib_stub: ?LibStub = null,
|
||||
name: ?[]const u8 = null,
|
||||
|
||||
ordinal: ?u16 = null,
|
||||
|
||||
id: ?Id = null,
|
||||
|
||||
/// Parsed symbol table represented as hash map of symbols'
|
||||
/// names. We can and should defer creating *Symbols until
|
||||
/// a symbol is referenced by an object file.
|
||||
symbols: std.StringArrayHashMapUnmanaged(void) = .{},
|
||||
|
||||
pub const Id = struct {
|
||||
name: []const u8,
|
||||
timestamp: u32,
|
||||
current_version: u32,
|
||||
compatibility_version: u32,
|
||||
|
||||
pub fn deinit(id: *Id, allocator: *Allocator) void {
|
||||
allocator.free(id.name);
|
||||
}
|
||||
};
|
||||
|
||||
pub fn init(allocator: *Allocator) Stub {
|
||||
return .{ .allocator = allocator };
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Stub) void {
|
||||
for (self.symbols.keys()) |key| {
|
||||
self.allocator.free(key);
|
||||
}
|
||||
self.symbols.deinit(self.allocator);
|
||||
|
||||
if (self.lib_stub) |*lib_stub| {
|
||||
lib_stub.deinit();
|
||||
}
|
||||
|
||||
if (self.name) |name| {
|
||||
self.allocator.free(name);
|
||||
}
|
||||
|
||||
if (self.id) |*id| {
|
||||
id.deinit(self.allocator);
|
||||
}
|
||||
}
|
||||
|
||||
fn addObjCClassSymbols(self: *Stub, sym_name: []const u8) !void {
|
||||
const expanded = &[_][]const u8{
|
||||
try std.fmt.allocPrint(self.allocator, "_OBJC_CLASS_$_{s}", .{sym_name}),
|
||||
try std.fmt.allocPrint(self.allocator, "_OBJC_METACLASS_$_{s}", .{sym_name}),
|
||||
};
|
||||
|
||||
for (expanded) |sym| {
|
||||
if (self.symbols.contains(sym)) continue;
|
||||
try self.symbols.putNoClobber(self.allocator, sym, .{});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(self: *Stub) !void {
|
||||
const lib_stub = self.lib_stub orelse return error.EmptyStubFile;
|
||||
if (lib_stub.inner.len == 0) return error.EmptyStubFile;
|
||||
|
||||
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;
|
||||
|
||||
if (exp.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 (exp.objc_classes) |classes| {
|
||||
for (classes) |sym_name| {
|
||||
try self.addObjCClassSymbols(sym_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
try self.symbols.putNoClobber(self.allocator, try self.allocator.dupe(u8, sym_name), {});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stub.objc_classes) |classes| {
|
||||
for (classes) |sym_name| {
|
||||
try self.addObjCClassSymbols(sym_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn hasTarget(targets: []const []const u8, target: []const u8) bool {
|
||||
for (targets) |t| {
|
||||
if (mem.eql(u8, t, target)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn createProxy(self: *Stub, sym_name: []const u8) !?*Symbol {
|
||||
if (!self.symbols.contains(sym_name)) return null;
|
||||
|
||||
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,
|
||||
},
|
||||
.file = .{ .stub = self },
|
||||
};
|
||||
|
||||
return &proxy.base;
|
||||
}
|
||||
@ -7,7 +7,6 @@ const mem = std.mem;
|
||||
const Allocator = mem.Allocator;
|
||||
const Dylib = @import("Dylib.zig");
|
||||
const Object = @import("Object.zig");
|
||||
const Stub = @import("Stub.zig");
|
||||
|
||||
pub const Type = enum {
|
||||
regular,
|
||||
@ -94,12 +93,9 @@ pub const Proxy = struct {
|
||||
address: u64,
|
||||
}) = .{},
|
||||
|
||||
/// Dylib or stub where to locate this symbol.
|
||||
/// Dylib where to locate this symbol.
|
||||
/// null means self-reference.
|
||||
file: ?union(enum) {
|
||||
dylib: *Dylib,
|
||||
stub: *Stub,
|
||||
} = null,
|
||||
file: ?*Dylib = null,
|
||||
|
||||
pub const base_type: Symbol.Type = .proxy;
|
||||
|
||||
@ -108,11 +104,8 @@ pub const Proxy = struct {
|
||||
}
|
||||
|
||||
pub fn dylibOrdinal(proxy: *Proxy) u16 {
|
||||
const file = proxy.file orelse return 0;
|
||||
return switch (file) {
|
||||
.dylib => |dylib| dylib.ordinal.?,
|
||||
.stub => |stub| stub.ordinal.?,
|
||||
};
|
||||
const dylib = proxy.file orelse return 0;
|
||||
return dylib.ordinal.?;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -16,8 +16,8 @@ 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 Stub = @import("Stub.zig");
|
||||
const Symbol = @import("Symbol.zig");
|
||||
const Trie = @import("Trie.zig");
|
||||
|
||||
@ -38,9 +38,8 @@ stack_size: u64 = 0,
|
||||
objects: std.ArrayListUnmanaged(*Object) = .{},
|
||||
archives: std.ArrayListUnmanaged(*Archive) = .{},
|
||||
dylibs: std.ArrayListUnmanaged(*Dylib) = .{},
|
||||
lib_stubs: std.ArrayListUnmanaged(*Stub) = .{},
|
||||
|
||||
libsystem_stub_index: ?u16 = null,
|
||||
libsystem_dylib_index: ?u16 = null,
|
||||
next_dylib_ordinal: u16 = 1,
|
||||
|
||||
load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},
|
||||
@ -134,10 +133,6 @@ const TlvOffset = struct {
|
||||
/// Default path to dyld
|
||||
const DEFAULT_DYLD_PATH: [*:0]const u8 = "/usr/lib/dyld";
|
||||
|
||||
const LIB_SYSTEM_NAME: [*:0]const u8 = "System";
|
||||
/// TODO this should be inferred from included libSystem.tbd or similar.
|
||||
const LIB_SYSTEM_PATH: [*:0]const u8 = "/usr/lib/libSystem.B.dylib";
|
||||
|
||||
pub fn init(allocator: *Allocator) Zld {
|
||||
return .{ .allocator = allocator };
|
||||
}
|
||||
@ -171,12 +166,6 @@ pub fn deinit(self: *Zld) void {
|
||||
}
|
||||
self.dylibs.deinit(self.allocator);
|
||||
|
||||
for (self.lib_stubs.items) |stub| {
|
||||
stub.deinit();
|
||||
self.allocator.destroy(stub);
|
||||
}
|
||||
self.lib_stubs.deinit(self.allocator);
|
||||
|
||||
for (self.imports.values()) |proxy| {
|
||||
proxy.deinit(self.allocator);
|
||||
self.allocator.destroy(proxy);
|
||||
@ -269,20 +258,30 @@ 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: enum {
|
||||
object,
|
||||
archive,
|
||||
dylib,
|
||||
stub,
|
||||
},
|
||||
origin: union {
|
||||
file: fs.File,
|
||||
stub: Stub.LibStub,
|
||||
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 classified.deinit();
|
||||
defer {
|
||||
for (classified.items) |*input| {
|
||||
input.deinit();
|
||||
}
|
||||
classified.deinit();
|
||||
}
|
||||
|
||||
// First, classify input files: object, archive, dylib or stub (tbd).
|
||||
for (files) |file_name| {
|
||||
@ -296,8 +295,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
|
||||
try_object: {
|
||||
if (!(try Object.isObject(file))) break :try_object;
|
||||
try classified.append(.{
|
||||
.kind = .object,
|
||||
.origin = .{ .file = file },
|
||||
.kind = .{ .object = file },
|
||||
.name = full_path,
|
||||
});
|
||||
continue;
|
||||
@ -306,8 +304,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
|
||||
try_archive: {
|
||||
if (!(try Archive.isArchive(file))) break :try_archive;
|
||||
try classified.append(.{
|
||||
.kind = .archive,
|
||||
.origin = .{ .file = file },
|
||||
.kind = .{ .archive = file },
|
||||
.name = full_path,
|
||||
});
|
||||
continue;
|
||||
@ -316,20 +313,18 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
|
||||
try_dylib: {
|
||||
if (!(try Dylib.isDylib(file))) break :try_dylib;
|
||||
try classified.append(.{
|
||||
.kind = .dylib,
|
||||
.origin = .{ .file = file },
|
||||
.kind = .{ .dylib = file },
|
||||
.name = full_path,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
try_stub: {
|
||||
var lib_stub = Stub.LibStub.loadFromFile(self.allocator, file) catch {
|
||||
var lib_stub = LibStub.loadFromFile(self.allocator, file) catch {
|
||||
break :try_stub;
|
||||
};
|
||||
try classified.append(.{
|
||||
.kind = .stub,
|
||||
.origin = .{ .stub = lib_stub },
|
||||
.kind = .{ .stub = lib_stub },
|
||||
.name = full_path,
|
||||
});
|
||||
file.close();
|
||||
@ -343,54 +338,47 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
|
||||
// Based on our classification, proceed with parsing.
|
||||
for (classified.items) |input| {
|
||||
switch (input.kind) {
|
||||
.object => {
|
||||
.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 = input.origin.file;
|
||||
object.file = file;
|
||||
|
||||
try object.parse();
|
||||
try self.objects.append(self.allocator, object);
|
||||
},
|
||||
.archive => {
|
||||
.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 = input.origin.file;
|
||||
archive.file = file;
|
||||
|
||||
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);
|
||||
|
||||
dylib.* = Dylib.init(self.allocator);
|
||||
dylib.arch = self.arch.?;
|
||||
dylib.name = input.name;
|
||||
dylib.file = input.origin.file;
|
||||
|
||||
try dylib.parse();
|
||||
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);
|
||||
},
|
||||
.stub => {
|
||||
const stub = try self.allocator.create(Stub);
|
||||
errdefer self.allocator.destroy(stub);
|
||||
|
||||
stub.* = Stub.init(self.allocator);
|
||||
stub.arch = self.arch.?;
|
||||
stub.name = input.name;
|
||||
stub.lib_stub = input.origin.stub;
|
||||
|
||||
try stub.parse();
|
||||
try self.lib_stubs.append(self.allocator, stub);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -399,51 +387,65 @@ fn parseLibs(self: *Zld, libs: []const []const u8) !void {
|
||||
for (libs) |lib| {
|
||||
const file = try fs.cwd().openFile(lib, .{});
|
||||
|
||||
if (try Dylib.isDylib(file)) {
|
||||
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;
|
||||
|
||||
try dylib.parse();
|
||||
try self.dylibs.append(self.allocator, dylib);
|
||||
} else {
|
||||
// Try tbd stub file next.
|
||||
if (Stub.LibStub.loadFromFile(self.allocator, file)) |lib_stub| {
|
||||
const stub = try self.allocator.create(Stub);
|
||||
errdefer self.allocator.destroy(stub);
|
||||
|
||||
stub.* = Stub.init(self.allocator);
|
||||
stub.arch = self.arch.?;
|
||||
stub.name = try self.allocator.dupe(u8, lib);
|
||||
stub.lib_stub = lib_stub;
|
||||
|
||||
try stub.parse();
|
||||
try self.lib_stubs.append(self.allocator, stub);
|
||||
} else |_| {
|
||||
// TODO this entire logic has to be cleaned up.
|
||||
try file.seekTo(0);
|
||||
|
||||
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});
|
||||
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 unwrapped = kind orelse {
|
||||
file.close();
|
||||
log.warn("unknown filetype for a library: '{s}'", .{lib});
|
||||
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);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -451,24 +453,24 @@ 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 Stub.LibStub.loadFromFile(self.allocator, file);
|
||||
var lib_stub = try LibStub.loadFromFile(self.allocator, file);
|
||||
defer lib_stub.deinit();
|
||||
|
||||
const stub = try self.allocator.create(Stub);
|
||||
errdefer self.allocator.destroy(stub);
|
||||
const dylib = try self.allocator.create(Dylib);
|
||||
errdefer self.allocator.destroy(dylib);
|
||||
|
||||
stub.* = Stub.init(self.allocator);
|
||||
stub.arch = self.arch.?;
|
||||
stub.name = try self.allocator.dupe(u8, libc_stub_path);
|
||||
stub.lib_stub = lib_stub;
|
||||
dylib.* = Dylib.init(self.allocator);
|
||||
dylib.arch = self.arch.?;
|
||||
dylib.name = try self.allocator.dupe(u8, libc_stub_path);
|
||||
|
||||
try stub.parse();
|
||||
try dylib.parseFromStub(lib_stub);
|
||||
|
||||
self.libsystem_stub_index = @intCast(u16, self.lib_stubs.items.len);
|
||||
try self.lib_stubs.append(self.allocator, stub);
|
||||
self.libsystem_dylib_index = @intCast(u16, self.dylibs.items.len);
|
||||
try self.dylibs.append(self.allocator, dylib);
|
||||
|
||||
// Add LC_LOAD_DYLIB load command.
|
||||
stub.ordinal = self.next_dylib_ordinal;
|
||||
const dylib_id = stub.id orelse unreachable;
|
||||
dylib.ordinal = self.next_dylib_ordinal;
|
||||
const dylib_id = dylib.id orelse unreachable;
|
||||
var dylib_cmd = try createLoadDylibCommand(
|
||||
self.allocator,
|
||||
dylib_id.name,
|
||||
@ -1778,25 +1780,16 @@ fn resolveSymbols(self: *Zld) !void {
|
||||
}
|
||||
self.unresolved.clearRetainingCapacity();
|
||||
|
||||
var referenced = std.AutoHashMap(union(enum) {
|
||||
dylib: *Dylib,
|
||||
stub: *Stub,
|
||||
}, void).init(self.allocator);
|
||||
var referenced = std.AutoHashMap(*Dylib, void).init(self.allocator);
|
||||
defer referenced.deinit();
|
||||
|
||||
loop: while (unresolved.popOrNull()) |undef| {
|
||||
const proxy = self.imports.get(undef.name) orelse outer: {
|
||||
const proxy = inner: {
|
||||
for (self.dylibs.items) |dylib| {
|
||||
for (self.dylibs.items) |dylib, i| {
|
||||
const proxy = (try dylib.createProxy(undef.name)) orelse continue;
|
||||
try referenced.put(.{ .dylib = dylib }, {});
|
||||
break :inner proxy;
|
||||
}
|
||||
for (self.lib_stubs.items) |stub, i| {
|
||||
const proxy = (try stub.createProxy(undef.name)) orelse continue;
|
||||
if (self.libsystem_stub_index.? != @intCast(u16, i)) {
|
||||
// LibSystem gets its load command separately.
|
||||
try referenced.put(.{ .stub = stub }, {});
|
||||
if (self.libsystem_dylib_index.? != @intCast(u16, i)) { // LibSystem gets load command seperately.
|
||||
try referenced.put(dylib, {});
|
||||
}
|
||||
break :inner proxy;
|
||||
}
|
||||
@ -1829,33 +1822,17 @@ fn resolveSymbols(self: *Zld) !void {
|
||||
|
||||
// Add LC_LOAD_DYLIB load command for each referenced dylib/stub.
|
||||
var it = referenced.iterator();
|
||||
while (it.next()) |key| {
|
||||
var dylib_cmd = blk: {
|
||||
switch (key.key_ptr.*) {
|
||||
.dylib => |dylib| {
|
||||
dylib.ordinal = self.next_dylib_ordinal;
|
||||
const dylib_id = dylib.id orelse unreachable;
|
||||
break :blk try createLoadDylibCommand(
|
||||
self.allocator,
|
||||
dylib_id.name,
|
||||
dylib_id.timestamp,
|
||||
dylib_id.current_version,
|
||||
dylib_id.compatibility_version,
|
||||
);
|
||||
},
|
||||
.stub => |stub| {
|
||||
stub.ordinal = self.next_dylib_ordinal;
|
||||
const dylib_id = stub.id orelse unreachable;
|
||||
break :blk try createLoadDylibCommand(
|
||||
self.allocator,
|
||||
dylib_id.name,
|
||||
dylib_id.timestamp,
|
||||
dylib_id.current_version,
|
||||
dylib_id.compatibility_version,
|
||||
);
|
||||
},
|
||||
}
|
||||
};
|
||||
while (it.next()) |entry| {
|
||||
const dylib = entry.key_ptr.*;
|
||||
dylib.ordinal = self.next_dylib_ordinal;
|
||||
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 });
|
||||
self.next_dylib_ordinal += 1;
|
||||
@ -1873,8 +1850,8 @@ fn resolveSymbols(self: *Zld) !void {
|
||||
}
|
||||
|
||||
// Finally put dyld_stub_binder as an Import
|
||||
const libsystem_stub = self.lib_stubs.items[self.libsystem_stub_index.?];
|
||||
const proxy = (try libsystem_stub.createProxy("dyld_stub_binder")) orelse {
|
||||
const libsystem_dylib = self.dylibs.items[self.libsystem_dylib_index.?];
|
||||
const proxy = (try libsystem_dylib.createProxy("dyld_stub_binder")) orelse {
|
||||
log.err("undefined reference to symbol 'dyld_stub_binder'", .{});
|
||||
return error.UndefinedSymbolReference;
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user