authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-06-23 11:09:45+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-06-24 18:57:04+02:00
log3cb6b6bd90c3b304bf771b37e974dd943c060e2b
treeaedd44c189f439fa852b16ad264bf1e6f86b2580
parent3f57468c8bd16f33b5ac21cf8eaea2fdb948b999

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.

5 files changed, 212 insertions(+), 320 deletions(-)

CMakeLists.txt-1
...@@ -579,7 +579,6 @@ set(ZIG_STAGE2_SOURCES...@@ -579,7 +579,6 @@ set(ZIG_STAGE2_SOURCES
579 "${CMAKE_SOURCE_DIR}/src/link/MachO/DebugSymbols.zig"579 "${CMAKE_SOURCE_DIR}/src/link/MachO/DebugSymbols.zig"
580 "${CMAKE_SOURCE_DIR}/src/link/MachO/Dylib.zig"580 "${CMAKE_SOURCE_DIR}/src/link/MachO/Dylib.zig"
581 "${CMAKE_SOURCE_DIR}/src/link/MachO/Object.zig"581 "${CMAKE_SOURCE_DIR}/src/link/MachO/Object.zig"
582 "${CMAKE_SOURCE_DIR}/src/link/MachO/Stub.zig"
583 "${CMAKE_SOURCE_DIR}/src/link/MachO/Symbol.zig"582 "${CMAKE_SOURCE_DIR}/src/link/MachO/Symbol.zig"
584 "${CMAKE_SOURCE_DIR}/src/link/MachO/Trie.zig"583 "${CMAKE_SOURCE_DIR}/src/link/MachO/Trie.zig"
585 "${CMAKE_SOURCE_DIR}/src/link/MachO/Zld.zig"584 "${CMAKE_SOURCE_DIR}/src/link/MachO/Zld.zig"
src/link/MachO/Dylib.zig+86-4
...@@ -9,10 +9,12 @@ const mem = std.mem;...@@ -9,10 +9,12 @@ const mem = std.mem;
99
10const Allocator = mem.Allocator;10const Allocator = mem.Allocator;
11const Symbol = @import("Symbol.zig");11const Symbol = @import("Symbol.zig");
12const LibStub = @import("../tapi.zig").LibStub;
1213
13usingnamespace @import("commands.zig");14usingnamespace @import("commands.zig");
1415
15allocator: *Allocator,16allocator: *Allocator,
17
16arch: ?std.Target.Cpu.Arch = null,18arch: ?std.Target.Cpu.Arch = null,
17header: ?macho.mach_header_64 = null,19header: ?macho.mach_header_64 = null,
18file: ?fs.File = null,20file: ?fs.File = null,
...@@ -103,7 +105,7 @@ pub fn parse(self: *Dylib) !void {...@@ -103,7 +105,7 @@ pub fn parse(self: *Dylib) !void {
103 try self.parseSymbols();105 try self.parseSymbols();
104}106}
105107
106pub fn readLoadCommands(self: *Dylib, reader: anytype) !void {108fn readLoadCommands(self: *Dylib, reader: anytype) !void {
107 try self.load_commands.ensureCapacity(self.allocator, self.header.?.ncmds);109 try self.load_commands.ensureCapacity(self.allocator, self.header.?.ncmds);
108110
109 var i: u16 = 0;111 var i: u16 = 0;
...@@ -127,7 +129,7 @@ pub fn readLoadCommands(self: *Dylib, reader: anytype) !void {...@@ -127,7 +129,7 @@ pub fn readLoadCommands(self: *Dylib, reader: anytype) !void {
127 }129 }
128}130}
129131
130pub fn parseId(self: *Dylib) !void {132fn parseId(self: *Dylib) !void {
131 const index = self.id_cmd_index orelse {133 const index = self.id_cmd_index orelse {
132 log.debug("no LC_ID_DYLIB load command found; using hard-coded defaults...", .{});134 log.debug("no LC_ID_DYLIB load command found; using hard-coded defaults...", .{});
133 self.id = .{135 self.id = .{
...@@ -153,7 +155,7 @@ pub fn parseId(self: *Dylib) !void {...@@ -153,7 +155,7 @@ pub fn parseId(self: *Dylib) !void {
153 };155 };
154}156}
155157
156pub fn parseSymbols(self: *Dylib) !void {158fn parseSymbols(self: *Dylib) !void {
157 const index = self.symtab_cmd_index orelse return;159 const index = self.symtab_cmd_index orelse return;
158 const symtab_cmd = self.load_commands.items[index].Symtab;160 const symtab_cmd = self.load_commands.items[index].Symtab;
159161
...@@ -176,6 +178,86 @@ pub fn parseSymbols(self: *Dylib) !void {...@@ -176,6 +178,86 @@ pub fn parseSymbols(self: *Dylib) !void {
176 }178 }
177}179}
178180
181fn addObjCClassSymbols(self: *Dylib, sym_name: []const u8) !void {
182 const expanded = &[_][]const u8{
183 try std.fmt.allocPrint(self.allocator, "_OBJC_CLASS_$_{s}", .{sym_name}),
184 try std.fmt.allocPrint(self.allocator, "_OBJC_METACLASS_$_{s}", .{sym_name}),
185 };
186
187 for (expanded) |sym| {
188 if (self.symbols.contains(sym)) continue;
189 try self.symbols.putNoClobber(self.allocator, sym, .{});
190 }
191}
192
193pub fn parseFromStub(self: *Dylib, lib_stub: LibStub) !void {
194 if (lib_stub.inner.len == 0) return error.EmptyStubFile;
195
196 log.debug("parsing shared library from stub '{s}'", .{self.name.?});
197
198 const umbrella_lib = lib_stub.inner[0];
199 self.id = .{
200 .name = try self.allocator.dupe(u8, umbrella_lib.install_name),
201 // TODO parse from the stub
202 .timestamp = 2,
203 .current_version = 0,
204 .compatibility_version = 0,
205 };
206
207 const target_string: []const u8 = switch (self.arch.?) {
208 .aarch64 => "arm64-macos",
209 .x86_64 => "x86_64-macos",
210 else => unreachable,
211 };
212
213 for (lib_stub.inner) |stub| {
214 if (!hasTarget(stub.targets, target_string)) continue;
215
216 if (stub.exports) |exports| {
217 for (exports) |exp| {
218 if (!hasTarget(exp.targets, target_string)) continue;
219
220 if (exp.symbols) |symbols| {
221 for (symbols) |sym_name| {
222 if (self.symbols.contains(sym_name)) continue;
223 try self.symbols.putNoClobber(self.allocator, try self.allocator.dupe(u8, sym_name), {});
224 }
225 }
226
227 if (exp.objc_classes) |classes| {
228 for (classes) |sym_name| {
229 try self.addObjCClassSymbols(sym_name);
230 }
231 }
232 }
233 }
234
235 if (stub.reexports) |reexports| {
236 for (reexports) |reexp| {
237 if (!hasTarget(reexp.targets, target_string)) continue;
238
239 for (reexp.symbols) |sym_name| {
240 if (self.symbols.contains(sym_name)) continue;
241 try self.symbols.putNoClobber(self.allocator, try self.allocator.dupe(u8, sym_name), {});
242 }
243 }
244 }
245
246 if (stub.objc_classes) |classes| {
247 for (classes) |sym_name| {
248 try self.addObjCClassSymbols(sym_name);
249 }
250 }
251 }
252}
253
254fn hasTarget(targets: []const []const u8, target: []const u8) bool {
255 for (targets) |t| {
256 if (mem.eql(u8, t, target)) return true;
257 }
258 return false;
259}
260
179pub fn isDylib(file: fs.File) !bool {261pub fn isDylib(file: fs.File) !bool {
180 const header = file.reader().readStruct(macho.mach_header_64) catch |err| switch (err) {262 const header = file.reader().readStruct(macho.mach_header_64) catch |err| switch (err) {
181 error.EndOfStream => return false,263 error.EndOfStream => return false,
...@@ -197,7 +279,7 @@ pub fn createProxy(self: *Dylib, sym_name: []const u8) !?*Symbol {...@@ -197,7 +279,7 @@ pub fn createProxy(self: *Dylib, sym_name: []const u8) !?*Symbol {
197 .@"type" = .proxy,279 .@"type" = .proxy,
198 .name = name,280 .name = name,
199 },281 },
200 .file = .{ .dylib = self },282 .file = self,
201 };283 };
202284
203 return &proxy.base;285 return &proxy.base;
src/link/MachO/Stub.zig deleted-159
...@@ -1,159 +0,0 @@
1const Stub = @This();
2
3const std = @import("std");
4const assert = std.debug.assert;
5const fs = std.fs;
6const log = std.log.scoped(.stub);
7const macho = std.macho;
8const mem = std.mem;
9
10const Allocator = mem.Allocator;
11const Symbol = @import("Symbol.zig");
12pub const LibStub = @import("../tapi.zig").LibStub;
13
14allocator: *Allocator,
15arch: ?std.Target.Cpu.Arch = null,
16lib_stub: ?LibStub = null,
17name: ?[]const u8 = null,
18
19ordinal: ?u16 = null,
20
21id: ?Id = null,
22
23/// Parsed symbol table represented as hash map of symbols'
24/// names. We can and should defer creating *Symbols until
25/// a symbol is referenced by an object file.
26symbols: std.StringArrayHashMapUnmanaged(void) = .{},
27
28pub const Id = struct {
29 name: []const u8,
30 timestamp: u32,
31 current_version: u32,
32 compatibility_version: u32,
33
34 pub fn deinit(id: *Id, allocator: *Allocator) void {
35 allocator.free(id.name);
36 }
37};
38
39pub fn init(allocator: *Allocator) Stub {
40 return .{ .allocator = allocator };
41}
42
43pub fn deinit(self: *Stub) void {
44 for (self.symbols.keys()) |key| {
45 self.allocator.free(key);
46 }
47 self.symbols.deinit(self.allocator);
48
49 if (self.lib_stub) |*lib_stub| {
50 lib_stub.deinit();
51 }
52
53 if (self.name) |name| {
54 self.allocator.free(name);
55 }
56
57 if (self.id) |*id| {
58 id.deinit(self.allocator);
59 }
60}
61
62fn addObjCClassSymbols(self: *Stub, sym_name: []const u8) !void {
63 const expanded = &[_][]const u8{
64 try std.fmt.allocPrint(self.allocator, "_OBJC_CLASS_$_{s}", .{sym_name}),
65 try std.fmt.allocPrint(self.allocator, "_OBJC_METACLASS_$_{s}", .{sym_name}),
66 };
67
68 for (expanded) |sym| {
69 if (self.symbols.contains(sym)) continue;
70 try self.symbols.putNoClobber(self.allocator, sym, .{});
71 }
72}
73
74pub fn parse(self: *Stub) !void {
75 const lib_stub = self.lib_stub orelse return error.EmptyStubFile;
76 if (lib_stub.inner.len == 0) return error.EmptyStubFile;
77
78 log.debug("parsing shared library from stub '{s}'", .{self.name.?});
79
80 const umbrella_lib = lib_stub.inner[0];
81 self.id = .{
82 .name = try self.allocator.dupe(u8, umbrella_lib.install_name),
83 // TODO parse from the stub
84 .timestamp = 2,
85 .current_version = 0,
86 .compatibility_version = 0,
87 };
88
89 const target_string: []const u8 = switch (self.arch.?) {
90 .aarch64 => "arm64-macos",
91 .x86_64 => "x86_64-macos",
92 else => unreachable,
93 };
94
95 for (lib_stub.inner) |stub| {
96 if (!hasTarget(stub.targets, target_string)) continue;
97
98 if (stub.exports) |exports| {
99 for (exports) |exp| {
100 if (!hasTarget(exp.targets, target_string)) continue;
101
102 if (exp.symbols) |symbols| {
103 for (symbols) |sym_name| {
104 if (self.symbols.contains(sym_name)) continue;
105 try self.symbols.putNoClobber(self.allocator, try self.allocator.dupe(u8, sym_name), {});
106 }
107 }
108
109 if (exp.objc_classes) |classes| {
110 for (classes) |sym_name| {
111 try self.addObjCClassSymbols(sym_name);
112 }
113 }
114 }
115 }
116
117 if (stub.reexports) |reexports| {
118 for (reexports) |reexp| {
119 if (!hasTarget(reexp.targets, target_string)) continue;
120
121 for (reexp.symbols) |sym_name| {
122 if (self.symbols.contains(sym_name)) continue;
123 try self.symbols.putNoClobber(self.allocator, try self.allocator.dupe(u8, sym_name), {});
124 }
125 }
126 }
127
128 if (stub.objc_classes) |classes| {
129 for (classes) |sym_name| {
130 try self.addObjCClassSymbols(sym_name);
131 }
132 }
133 }
134}
135
136fn hasTarget(targets: []const []const u8, target: []const u8) bool {
137 for (targets) |t| {
138 if (mem.eql(u8, t, target)) return true;
139 }
140 return false;
141}
142
143pub fn createProxy(self: *Stub, sym_name: []const u8) !?*Symbol {
144 if (!self.symbols.contains(sym_name)) return null;
145
146 const name = try self.allocator.dupe(u8, sym_name);
147 const proxy = try self.allocator.create(Symbol.Proxy);
148 errdefer self.allocator.destroy(proxy);
149
150 proxy.* = .{
151 .base = .{
152 .@"type" = .proxy,
153 .name = name,
154 },
155 .file = .{ .stub = self },
156 };
157
158 return &proxy.base;
159}
src/link/MachO/Symbol.zig+4-11
...@@ -7,7 +7,6 @@ const mem = std.mem;...@@ -7,7 +7,6 @@ const mem = std.mem;
7const Allocator = mem.Allocator;7const Allocator = mem.Allocator;
8const Dylib = @import("Dylib.zig");8const Dylib = @import("Dylib.zig");
9const Object = @import("Object.zig");9const Object = @import("Object.zig");
10const Stub = @import("Stub.zig");
1110
12pub const Type = enum {11pub const Type = enum {
13 regular,12 regular,
...@@ -94,12 +93,9 @@ pub const Proxy = struct {...@@ -94,12 +93,9 @@ pub const Proxy = struct {
94 address: u64,93 address: u64,
95 }) = .{},94 }) = .{},
9695
97 /// Dylib or stub where to locate this symbol.96 /// Dylib where to locate this symbol.
98 /// null means self-reference.97 /// null means self-reference.
99 file: ?union(enum) {98 file: ?*Dylib = null,
100 dylib: *Dylib,
101 stub: *Stub,
102 } = null,
10399
104 pub const base_type: Symbol.Type = .proxy;100 pub const base_type: Symbol.Type = .proxy;
105101
...@@ -108,11 +104,8 @@ pub const Proxy = struct {...@@ -108,11 +104,8 @@ pub const Proxy = struct {
108 }104 }
109105
110 pub fn dylibOrdinal(proxy: *Proxy) u16 {106 pub fn dylibOrdinal(proxy: *Proxy) u16 {
111 const file = proxy.file orelse return 0;107 const dylib = proxy.file orelse return 0;
112 return switch (file) {108 return dylib.ordinal.?;
113 .dylib => |dylib| dylib.ordinal.?,
114 .stub => |stub| stub.ordinal.?,
115 };
116 }109 }
117};110};
118111
src/link/MachO/Zld.zig+122-145
...@@ -16,8 +16,8 @@ const Allocator = mem.Allocator;...@@ -16,8 +16,8 @@ const Allocator = mem.Allocator;
16const Archive = @import("Archive.zig");16const Archive = @import("Archive.zig");
17const CodeSignature = @import("CodeSignature.zig");17const CodeSignature = @import("CodeSignature.zig");
18const Dylib = @import("Dylib.zig");18const Dylib = @import("Dylib.zig");
19const LibStub = @import("../tapi.zig").LibStub;
19const Object = @import("Object.zig");20const Object = @import("Object.zig");
20const Stub = @import("Stub.zig");
21const Symbol = @import("Symbol.zig");21const Symbol = @import("Symbol.zig");
22const Trie = @import("Trie.zig");22const Trie = @import("Trie.zig");
2323
...@@ -38,9 +38,8 @@ stack_size: u64 = 0,...@@ -38,9 +38,8 @@ stack_size: u64 = 0,
38objects: std.ArrayListUnmanaged(*Object) = .{},38objects: std.ArrayListUnmanaged(*Object) = .{},
39archives: std.ArrayListUnmanaged(*Archive) = .{},39archives: std.ArrayListUnmanaged(*Archive) = .{},
40dylibs: std.ArrayListUnmanaged(*Dylib) = .{},40dylibs: std.ArrayListUnmanaged(*Dylib) = .{},
41lib_stubs: std.ArrayListUnmanaged(*Stub) = .{},
4241
43libsystem_stub_index: ?u16 = null,42libsystem_dylib_index: ?u16 = null,
44next_dylib_ordinal: u16 = 1,43next_dylib_ordinal: u16 = 1,
4544
46load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},45load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},
...@@ -134,10 +133,6 @@ const TlvOffset = struct {...@@ -134,10 +133,6 @@ const TlvOffset = struct {
134/// Default path to dyld133/// Default path to dyld
135const DEFAULT_DYLD_PATH: [*:0]const u8 = "/usr/lib/dyld";134const DEFAULT_DYLD_PATH: [*:0]const u8 = "/usr/lib/dyld";
136135
137const LIB_SYSTEM_NAME: [*:0]const u8 = "System";
138/// TODO this should be inferred from included libSystem.tbd or similar.
139const LIB_SYSTEM_PATH: [*:0]const u8 = "/usr/lib/libSystem.B.dylib";
140
141pub fn init(allocator: *Allocator) Zld {136pub fn init(allocator: *Allocator) Zld {
142 return .{ .allocator = allocator };137 return .{ .allocator = allocator };
143}138}
...@@ -171,12 +166,6 @@ pub fn deinit(self: *Zld) void {...@@ -171,12 +166,6 @@ pub fn deinit(self: *Zld) void {
171 }166 }
172 self.dylibs.deinit(self.allocator);167 self.dylibs.deinit(self.allocator);
173168
174 for (self.lib_stubs.items) |stub| {
175 stub.deinit();
176 self.allocator.destroy(stub);
177 }
178 self.lib_stubs.deinit(self.allocator);
179
180 for (self.imports.values()) |proxy| {169 for (self.imports.values()) |proxy| {
181 proxy.deinit(self.allocator);170 proxy.deinit(self.allocator);
182 self.allocator.destroy(proxy);171 self.allocator.destroy(proxy);
...@@ -269,20 +258,30 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L...@@ -269,20 +258,30 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L
269258
270fn parseInputFiles(self: *Zld, files: []const []const u8) !void {259fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
271 const Input = struct {260 const Input = struct {
272 kind: enum {261 kind: union(enum) {
273 object,262 object: fs.File,
274 archive,263 archive: fs.File,
275 dylib,264 dylib: fs.File,
276 stub,265 stub: LibStub,
277 },
278 origin: union {
279 file: fs.File,
280 stub: Stub.LibStub,
281 },266 },
282 name: []const u8,267 name: []const u8,
268
269 fn deinit(input: *@This()) void {
270 switch (input.kind) {
271 .stub => |*stub| {
272 stub.deinit();
273 },
274 else => {},
275 }
276 }
283 };277 };
284 var classified = std.ArrayList(Input).init(self.allocator);278 var classified = std.ArrayList(Input).init(self.allocator);
285 defer classified.deinit();279 defer {
280 for (classified.items) |*input| {
281 input.deinit();
282 }
283 classified.deinit();
284 }
286285
287 // First, classify input files: object, archive, dylib or stub (tbd).286 // First, classify input files: object, archive, dylib or stub (tbd).
288 for (files) |file_name| {287 for (files) |file_name| {
...@@ -296,8 +295,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {...@@ -296,8 +295,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
296 try_object: {295 try_object: {
297 if (!(try Object.isObject(file))) break :try_object;296 if (!(try Object.isObject(file))) break :try_object;
298 try classified.append(.{297 try classified.append(.{
299 .kind = .object,298 .kind = .{ .object = file },
300 .origin = .{ .file = file },
301 .name = full_path,299 .name = full_path,
302 });300 });
303 continue;301 continue;
...@@ -306,8 +304,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {...@@ -306,8 +304,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
306 try_archive: {304 try_archive: {
307 if (!(try Archive.isArchive(file))) break :try_archive;305 if (!(try Archive.isArchive(file))) break :try_archive;
308 try classified.append(.{306 try classified.append(.{
309 .kind = .archive,307 .kind = .{ .archive = file },
310 .origin = .{ .file = file },
311 .name = full_path,308 .name = full_path,
312 });309 });
313 continue;310 continue;
...@@ -316,20 +313,18 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {...@@ -316,20 +313,18 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
316 try_dylib: {313 try_dylib: {
317 if (!(try Dylib.isDylib(file))) break :try_dylib;314 if (!(try Dylib.isDylib(file))) break :try_dylib;
318 try classified.append(.{315 try classified.append(.{
319 .kind = .dylib,316 .kind = .{ .dylib = file },
320 .origin = .{ .file = file },
321 .name = full_path,317 .name = full_path,
322 });318 });
323 continue;319 continue;
324 }320 }
325321
326 try_stub: {322 try_stub: {
327 var lib_stub = Stub.LibStub.loadFromFile(self.allocator, file) catch {323 var lib_stub = LibStub.loadFromFile(self.allocator, file) catch {
328 break :try_stub;324 break :try_stub;
329 };325 };
330 try classified.append(.{326 try classified.append(.{
331 .kind = .stub,327 .kind = .{ .stub = lib_stub },
332 .origin = .{ .stub = lib_stub },
333 .name = full_path,328 .name = full_path,
334 });329 });
335 file.close();330 file.close();
...@@ -343,53 +338,46 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {...@@ -343,53 +338,46 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
343 // Based on our classification, proceed with parsing.338 // Based on our classification, proceed with parsing.
344 for (classified.items) |input| {339 for (classified.items) |input| {
345 switch (input.kind) {340 switch (input.kind) {
346 .object => {341 .object => |file| {
347 const object = try self.allocator.create(Object);342 const object = try self.allocator.create(Object);
348 errdefer self.allocator.destroy(object);343 errdefer self.allocator.destroy(object);
349344
350 object.* = Object.init(self.allocator);345 object.* = Object.init(self.allocator);
351 object.arch = self.arch.?;346 object.arch = self.arch.?;
352 object.name = input.name;347 object.name = input.name;
353 object.file = input.origin.file;348 object.file = file;
354349
355 try object.parse();350 try object.parse();
356 try self.objects.append(self.allocator, object);351 try self.objects.append(self.allocator, object);
357 },352 },
358 .archive => {353 .archive => |file| {
359 const archive = try self.allocator.create(Archive);354 const archive = try self.allocator.create(Archive);
360 errdefer self.allocator.destroy(archive);355 errdefer self.allocator.destroy(archive);
361356
362 archive.* = Archive.init(self.allocator);357 archive.* = Archive.init(self.allocator);
363 archive.arch = self.arch.?;358 archive.arch = self.arch.?;
364 archive.name = input.name;359 archive.name = input.name;
365 archive.file = input.origin.file;360 archive.file = file;
366361
367 try archive.parse();362 try archive.parse();
368 try self.archives.append(self.allocator, archive);363 try self.archives.append(self.allocator, archive);
369 },364 },
370 .dylib => {365 .dylib, .stub => {
371 const dylib = try self.allocator.create(Dylib);366 const dylib = try self.allocator.create(Dylib);
372 errdefer self.allocator.destroy(dylib);367 errdefer self.allocator.destroy(dylib);
373368
374 dylib.* = Dylib.init(self.allocator);369 dylib.* = Dylib.init(self.allocator);
375 dylib.arch = self.arch.?;370 dylib.arch = self.arch.?;
376 dylib.name = input.name;371 dylib.name = input.name;
377 dylib.file = input.origin.file;
378372
379 try dylib.parse();373 if (input.kind == .dylib) {
380 try self.dylibs.append(self.allocator, dylib);374 dylib.file = input.kind.dylib;
381 },375 try dylib.parse();
382 .stub => {376 } else {
383 const stub = try self.allocator.create(Stub);377 try dylib.parseFromStub(input.kind.stub);
384 errdefer self.allocator.destroy(stub);378 }
385
386 stub.* = Stub.init(self.allocator);
387 stub.arch = self.arch.?;
388 stub.name = input.name;
389 stub.lib_stub = input.origin.stub;
390379
391 try stub.parse();380 try self.dylibs.append(self.allocator, dylib);
392 try self.lib_stubs.append(self.allocator, stub);
393 },381 },
394 }382 }
395 }383 }
...@@ -399,50 +387,64 @@ fn parseLibs(self: *Zld, libs: []const []const u8) !void {...@@ -399,50 +387,64 @@ fn parseLibs(self: *Zld, libs: []const []const u8) !void {
399 for (libs) |lib| {387 for (libs) |lib| {
400 const file = try fs.cwd().openFile(lib, .{});388 const file = try fs.cwd().openFile(lib, .{});
401389
402 if (try Dylib.isDylib(file)) {390 var kind: ?union(enum) {
403 const dylib = try self.allocator.create(Dylib);391 archive,
404 errdefer self.allocator.destroy(dylib);392 dylib,
393 stub: LibStub,
394 } = kind: {
395 if (try Archive.isArchive(file)) break :kind .archive;
396 if (try Dylib.isDylib(file)) break :kind .dylib;
397 var lib_stub = LibStub.loadFromFile(self.allocator, file) catch {
398 break :kind null;
399 };
400 break :kind .{ .stub = lib_stub };
401 };
402 defer {
403 if (kind) |*kk| {
404 switch (kk.*) {
405 .stub => |*stub| {
406 stub.deinit();
407 },
408 else => {},
409 }
410 }
411 }
405412
406 dylib.* = Dylib.init(self.allocator);413 const unwrapped = kind orelse {
407 dylib.arch = self.arch.?;414 file.close();
408 dylib.name = try self.allocator.dupe(u8, lib);415 log.warn("unknown filetype for a library: '{s}'", .{lib});
409 dylib.file = file;416 continue;
417 };
418 switch (unwrapped) {
419 .archive => {
420 const archive = try self.allocator.create(Archive);
421 errdefer self.allocator.destroy(archive);
410422
411 try dylib.parse();423 archive.* = Archive.init(self.allocator);
412 try self.dylibs.append(self.allocator, dylib);424 archive.arch = self.arch.?;
413 } else {425 archive.name = try self.allocator.dupe(u8, lib);
414 // Try tbd stub file next.426 archive.file = file;
415 if (Stub.LibStub.loadFromFile(self.allocator, file)) |lib_stub| {427
416 const stub = try self.allocator.create(Stub);428 try archive.parse();
417 errdefer self.allocator.destroy(stub);429 try self.archives.append(self.allocator, archive);
418430 },
419 stub.* = Stub.init(self.allocator);431 .dylib, .stub => {
420 stub.arch = self.arch.?;432 const dylib = try self.allocator.create(Dylib);
421 stub.name = try self.allocator.dupe(u8, lib);433 errdefer self.allocator.destroy(dylib);
422 stub.lib_stub = lib_stub;434
423435 dylib.* = Dylib.init(self.allocator);
424 try stub.parse();436 dylib.arch = self.arch.?;
425 try self.lib_stubs.append(self.allocator, stub);437 dylib.name = try self.allocator.dupe(u8, lib);
426 } else |_| {438
427 // TODO this entire logic has to be cleaned up.439 if (unwrapped == .dylib) {
428 try file.seekTo(0);440 dylib.file = file;
429441 try dylib.parse();
430 if (try Archive.isArchive(file)) {
431 const archive = try self.allocator.create(Archive);
432 errdefer self.allocator.destroy(archive);
433
434 archive.* = Archive.init(self.allocator);
435 archive.arch = self.arch.?;
436 archive.name = try self.allocator.dupe(u8, lib);
437 archive.file = file;
438
439 try archive.parse();
440 try self.archives.append(self.allocator, archive);
441 } else {442 } else {
442 file.close();443 try dylib.parseFromStub(unwrapped.stub);
443 log.warn("unknown filetype for a library: '{s}'", .{lib});
444 }444 }
445 }445
446 try self.dylibs.append(self.allocator, dylib);
447 },
446 }448 }
447 }449 }
448}450}
...@@ -451,24 +453,24 @@ fn parseLibSystem(self: *Zld, libc_stub_path: []const u8) !void {...@@ -451,24 +453,24 @@ fn parseLibSystem(self: *Zld, libc_stub_path: []const u8) !void {
451 const file = try fs.cwd().openFile(libc_stub_path, .{});453 const file = try fs.cwd().openFile(libc_stub_path, .{});
452 defer file.close();454 defer file.close();
453455
454 var lib_stub = try Stub.LibStub.loadFromFile(self.allocator, file);456 var lib_stub = try LibStub.loadFromFile(self.allocator, file);
457 defer lib_stub.deinit();
455458
456 const stub = try self.allocator.create(Stub);459 const dylib = try self.allocator.create(Dylib);
457 errdefer self.allocator.destroy(stub);460 errdefer self.allocator.destroy(dylib);
458461
459 stub.* = Stub.init(self.allocator);462 dylib.* = Dylib.init(self.allocator);
460 stub.arch = self.arch.?;463 dylib.arch = self.arch.?;
461 stub.name = try self.allocator.dupe(u8, libc_stub_path);464 dylib.name = try self.allocator.dupe(u8, libc_stub_path);
462 stub.lib_stub = lib_stub;
463465
464 try stub.parse();466 try dylib.parseFromStub(lib_stub);
465467
466 self.libsystem_stub_index = @intCast(u16, self.lib_stubs.items.len);468 self.libsystem_dylib_index = @intCast(u16, self.dylibs.items.len);
467 try self.lib_stubs.append(self.allocator, stub);469 try self.dylibs.append(self.allocator, dylib);
468470
469 // Add LC_LOAD_DYLIB load command.471 // Add LC_LOAD_DYLIB load command.
470 stub.ordinal = self.next_dylib_ordinal;472 dylib.ordinal = self.next_dylib_ordinal;
471 const dylib_id = stub.id orelse unreachable;473 const dylib_id = dylib.id orelse unreachable;
472 var dylib_cmd = try createLoadDylibCommand(474 var dylib_cmd = try createLoadDylibCommand(
473 self.allocator,475 self.allocator,
474 dylib_id.name,476 dylib_id.name,
...@@ -1778,25 +1780,16 @@ fn resolveSymbols(self: *Zld) !void {...@@ -1778,25 +1780,16 @@ fn resolveSymbols(self: *Zld) !void {
1778 }1780 }
1779 self.unresolved.clearRetainingCapacity();1781 self.unresolved.clearRetainingCapacity();
17801782
1781 var referenced = std.AutoHashMap(union(enum) {1783 var referenced = std.AutoHashMap(*Dylib, void).init(self.allocator);
1782 dylib: *Dylib,
1783 stub: *Stub,
1784 }, void).init(self.allocator);
1785 defer referenced.deinit();1784 defer referenced.deinit();
17861785
1787 loop: while (unresolved.popOrNull()) |undef| {1786 loop: while (unresolved.popOrNull()) |undef| {
1788 const proxy = self.imports.get(undef.name) orelse outer: {1787 const proxy = self.imports.get(undef.name) orelse outer: {
1789 const proxy = inner: {1788 const proxy = inner: {
1790 for (self.dylibs.items) |dylib| {1789 for (self.dylibs.items) |dylib, i| {
1791 const proxy = (try dylib.createProxy(undef.name)) orelse continue;1790 const proxy = (try dylib.createProxy(undef.name)) orelse continue;
1792 try referenced.put(.{ .dylib = dylib }, {});1791 if (self.libsystem_dylib_index.? != @intCast(u16, i)) { // LibSystem gets load command seperately.
1793 break :inner proxy;1792 try referenced.put(dylib, {});
1794 }
1795 for (self.lib_stubs.items) |stub, i| {
1796 const proxy = (try stub.createProxy(undef.name)) orelse continue;
1797 if (self.libsystem_stub_index.? != @intCast(u16, i)) {
1798 // LibSystem gets its load command separately.
1799 try referenced.put(.{ .stub = stub }, {});
1800 }1793 }
1801 break :inner proxy;1794 break :inner proxy;
1802 }1795 }
...@@ -1829,33 +1822,17 @@ fn resolveSymbols(self: *Zld) !void {...@@ -1829,33 +1822,17 @@ fn resolveSymbols(self: *Zld) !void {
18291822
1830 // Add LC_LOAD_DYLIB load command for each referenced dylib/stub.1823 // Add LC_LOAD_DYLIB load command for each referenced dylib/stub.
1831 var it = referenced.iterator();1824 var it = referenced.iterator();
1832 while (it.next()) |key| {1825 while (it.next()) |entry| {
1833 var dylib_cmd = blk: {1826 const dylib = entry.key_ptr.*;
1834 switch (key.key_ptr.*) {1827 dylib.ordinal = self.next_dylib_ordinal;
1835 .dylib => |dylib| {1828 const dylib_id = dylib.id orelse unreachable;
1836 dylib.ordinal = self.next_dylib_ordinal;1829 var dylib_cmd = try createLoadDylibCommand(
1837 const dylib_id = dylib.id orelse unreachable;1830 self.allocator,
1838 break :blk try createLoadDylibCommand(1831 dylib_id.name,
1839 self.allocator,1832 dylib_id.timestamp,
1840 dylib_id.name,1833 dylib_id.current_version,
1841 dylib_id.timestamp,1834 dylib_id.compatibility_version,
1842 dylib_id.current_version,1835 );
1843 dylib_id.compatibility_version,
1844 );
1845 },
1846 .stub => |stub| {
1847 stub.ordinal = self.next_dylib_ordinal;
1848 const dylib_id = stub.id orelse unreachable;
1849 break :blk try createLoadDylibCommand(
1850 self.allocator,
1851 dylib_id.name,
1852 dylib_id.timestamp,
1853 dylib_id.current_version,
1854 dylib_id.compatibility_version,
1855 );
1856 },
1857 }
1858 };
1859 errdefer dylib_cmd.deinit(self.allocator);1836 errdefer dylib_cmd.deinit(self.allocator);
1860 try self.load_commands.append(self.allocator, .{ .Dylib = dylib_cmd });1837 try self.load_commands.append(self.allocator, .{ .Dylib = dylib_cmd });
1861 self.next_dylib_ordinal += 1;1838 self.next_dylib_ordinal += 1;
...@@ -1873,8 +1850,8 @@ fn resolveSymbols(self: *Zld) !void {...@@ -1873,8 +1850,8 @@ fn resolveSymbols(self: *Zld) !void {
1873 }1850 }
18741851
1875 // Finally put dyld_stub_binder as an Import1852 // Finally put dyld_stub_binder as an Import
1876 const libsystem_stub = self.lib_stubs.items[self.libsystem_stub_index.?];1853 const libsystem_dylib = self.dylibs.items[self.libsystem_dylib_index.?];
1877 const proxy = (try libsystem_stub.createProxy("dyld_stub_binder")) orelse {1854 const proxy = (try libsystem_dylib.createProxy("dyld_stub_binder")) orelse {
1878 log.err("undefined reference to symbol 'dyld_stub_binder'", .{});1855 log.err("undefined reference to symbol 'dyld_stub_binder'", .{});
1879 return error.UndefinedSymbolReference;1856 return error.UndefinedSymbolReference;
1880 };1857 };