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
579579 "${CMAKE_SOURCE_DIR}/src/link/MachO/DebugSymbols.zig"
580580 "${CMAKE_SOURCE_DIR}/src/link/MachO/Dylib.zig"
581581 "${CMAKE_SOURCE_DIR}/src/link/MachO/Object.zig"
582 "${CMAKE_SOURCE_DIR}/src/link/MachO/Stub.zig"
583582 "${CMAKE_SOURCE_DIR}/src/link/MachO/Symbol.zig"
584583 "${CMAKE_SOURCE_DIR}/src/link/MachO/Trie.zig"
585584 "${CMAKE_SOURCE_DIR}/src/link/MachO/Zld.zig"
src/link/MachO/Dylib.zig+86-4
......@@ -9,10 +9,12 @@ const mem = std.mem;
99
1010const Allocator = mem.Allocator;
1111const Symbol = @import("Symbol.zig");
12const LibStub = @import("../tapi.zig").LibStub;
1213
1314usingnamespace @import("commands.zig");
1415
1516allocator: *Allocator,
17
1618arch: ?std.Target.Cpu.Arch = null,
1719header: ?macho.mach_header_64 = null,
1820file: ?fs.File = null,
......@@ -103,7 +105,7 @@ pub fn parse(self: *Dylib) !void {
103105 try self.parseSymbols();
104106}
105107
106pub fn readLoadCommands(self: *Dylib, reader: anytype) !void {
108fn readLoadCommands(self: *Dylib, reader: anytype) !void {
107109 try self.load_commands.ensureCapacity(self.allocator, self.header.?.ncmds);
108110
109111 var i: u16 = 0;
......@@ -127,7 +129,7 @@ pub fn readLoadCommands(self: *Dylib, reader: anytype) !void {
127129 }
128130}
129131
130pub fn parseId(self: *Dylib) !void {
132fn parseId(self: *Dylib) !void {
131133 const index = self.id_cmd_index orelse {
132134 log.debug("no LC_ID_DYLIB load command found; using hard-coded defaults...", .{});
133135 self.id = .{
......@@ -153,7 +155,7 @@ pub fn parseId(self: *Dylib) !void {
153155 };
154156}
155157
156pub fn parseSymbols(self: *Dylib) !void {
158fn parseSymbols(self: *Dylib) !void {
157159 const index = self.symtab_cmd_index orelse return;
158160 const symtab_cmd = self.load_commands.items[index].Symtab;
159161
......@@ -176,6 +178,86 @@ pub fn parseSymbols(self: *Dylib) !void {
176178 }
177179}
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
179261pub fn isDylib(file: fs.File) !bool {
180262 const header = file.reader().readStruct(macho.mach_header_64) catch |err| switch (err) {
181263 error.EndOfStream => return false,
......@@ -197,7 +279,7 @@ pub fn createProxy(self: *Dylib, sym_name: []const u8) !?*Symbol {
197279 .@"type" = .proxy,
198280 .name = name,
199281 },
200 .file = .{ .dylib = self },
282 .file = self,
201283 };
202284
203285 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;
77const Allocator = mem.Allocator;
88const Dylib = @import("Dylib.zig");
99const Object = @import("Object.zig");
10const Stub = @import("Stub.zig");
1110
1211pub const Type = enum {
1312 regular,
......@@ -94,12 +93,9 @@ pub const Proxy = struct {
9493 address: u64,
9594 }) = .{},
9695
97 /// Dylib or stub where to locate this symbol.
96 /// Dylib where to locate this symbol.
9897 /// null means self-reference.
99 file: ?union(enum) {
100 dylib: *Dylib,
101 stub: *Stub,
102 } = null,
98 file: ?*Dylib = null,
10399
104100 pub const base_type: Symbol.Type = .proxy;
105101
......@@ -108,11 +104,8 @@ pub const Proxy = struct {
108104 }
109105
110106 pub fn dylibOrdinal(proxy: *Proxy) u16 {
111 const file = proxy.file orelse return 0;
112 return switch (file) {
113 .dylib => |dylib| dylib.ordinal.?,
114 .stub => |stub| stub.ordinal.?,
115 };
107 const dylib = proxy.file orelse return 0;
108 return dylib.ordinal.?;
116109 }
117110};
118111
src/link/MachO/Zld.zig+122-145
......@@ -16,8 +16,8 @@ const Allocator = mem.Allocator;
1616const Archive = @import("Archive.zig");
1717const CodeSignature = @import("CodeSignature.zig");
1818const Dylib = @import("Dylib.zig");
19const LibStub = @import("../tapi.zig").LibStub;
1920const Object = @import("Object.zig");
20const Stub = @import("Stub.zig");
2121const Symbol = @import("Symbol.zig");
2222const Trie = @import("Trie.zig");
2323
......@@ -38,9 +38,8 @@ stack_size: u64 = 0,
3838objects: std.ArrayListUnmanaged(*Object) = .{},
3939archives: std.ArrayListUnmanaged(*Archive) = .{},
4040dylibs: std.ArrayListUnmanaged(*Dylib) = .{},
41lib_stubs: std.ArrayListUnmanaged(*Stub) = .{},
4241
43libsystem_stub_index: ?u16 = null,
42libsystem_dylib_index: ?u16 = null,
4443next_dylib_ordinal: u16 = 1,
4544
4645load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},
......@@ -134,10 +133,6 @@ const TlvOffset = struct {
134133/// Default path to dyld
135134const 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
141136pub fn init(allocator: *Allocator) Zld {
142137 return .{ .allocator = allocator };
143138}
......@@ -171,12 +166,6 @@ pub fn deinit(self: *Zld) void {
171166 }
172167 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
180169 for (self.imports.values()) |proxy| {
181170 proxy.deinit(self.allocator);
182171 self.allocator.destroy(proxy);
......@@ -269,20 +258,30 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L
269258
270259fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
271260 const Input = struct {
272 kind: enum {
273 object,
274 archive,
275 dylib,
276 stub,
277 },
278 origin: union {
279 file: fs.File,
280 stub: Stub.LibStub,
261 kind: union(enum) {
262 object: fs.File,
263 archive: fs.File,
264 dylib: fs.File,
265 stub: LibStub,
281266 },
282267 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 }
283277 };
284278 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
287286 // First, classify input files: object, archive, dylib or stub (tbd).
288287 for (files) |file_name| {
......@@ -296,8 +295,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
296295 try_object: {
297296 if (!(try Object.isObject(file))) break :try_object;
298297 try classified.append(.{
299 .kind = .object,
300 .origin = .{ .file = file },
298 .kind = .{ .object = file },
301299 .name = full_path,
302300 });
303301 continue;
......@@ -306,8 +304,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
306304 try_archive: {
307305 if (!(try Archive.isArchive(file))) break :try_archive;
308306 try classified.append(.{
309 .kind = .archive,
310 .origin = .{ .file = file },
307 .kind = .{ .archive = file },
311308 .name = full_path,
312309 });
313310 continue;
......@@ -316,20 +313,18 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
316313 try_dylib: {
317314 if (!(try Dylib.isDylib(file))) break :try_dylib;
318315 try classified.append(.{
319 .kind = .dylib,
320 .origin = .{ .file = file },
316 .kind = .{ .dylib = file },
321317 .name = full_path,
322318 });
323319 continue;
324320 }
325321
326322 try_stub: {
327 var lib_stub = Stub.LibStub.loadFromFile(self.allocator, file) catch {
323 var lib_stub = LibStub.loadFromFile(self.allocator, file) catch {
328324 break :try_stub;
329325 };
330326 try classified.append(.{
331 .kind = .stub,
332 .origin = .{ .stub = lib_stub },
327 .kind = .{ .stub = lib_stub },
333328 .name = full_path,
334329 });
335330 file.close();
......@@ -343,53 +338,46 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
343338 // Based on our classification, proceed with parsing.
344339 for (classified.items) |input| {
345340 switch (input.kind) {
346 .object => {
341 .object => |file| {
347342 const object = try self.allocator.create(Object);
348343 errdefer self.allocator.destroy(object);
349344
350345 object.* = Object.init(self.allocator);
351346 object.arch = self.arch.?;
352347 object.name = input.name;
353 object.file = input.origin.file;
348 object.file = file;
354349
355350 try object.parse();
356351 try self.objects.append(self.allocator, object);
357352 },
358 .archive => {
353 .archive => |file| {
359354 const archive = try self.allocator.create(Archive);
360355 errdefer self.allocator.destroy(archive);
361356
362357 archive.* = Archive.init(self.allocator);
363358 archive.arch = self.arch.?;
364359 archive.name = input.name;
365 archive.file = input.origin.file;
360 archive.file = file;
366361
367362 try archive.parse();
368363 try self.archives.append(self.allocator, archive);
369364 },
370 .dylib => {
365 .dylib, .stub => {
371366 const dylib = try self.allocator.create(Dylib);
372367 errdefer self.allocator.destroy(dylib);
373368
374369 dylib.* = Dylib.init(self.allocator);
375370 dylib.arch = self.arch.?;
376371 dylib.name = input.name;
377 dylib.file = input.origin.file;
378372
379 try dylib.parse();
380 try self.dylibs.append(self.allocator, dylib);
381 },
382 .stub => {
383 const stub = try self.allocator.create(Stub);
384 errdefer self.allocator.destroy(stub);
385
386 stub.* = Stub.init(self.allocator);
387 stub.arch = self.arch.?;
388 stub.name = input.name;
389 stub.lib_stub = input.origin.stub;
373 if (input.kind == .dylib) {
374 dylib.file = input.kind.dylib;
375 try dylib.parse();
376 } else {
377 try dylib.parseFromStub(input.kind.stub);
378 }
390379
391 try stub.parse();
392 try self.lib_stubs.append(self.allocator, stub);
380 try self.dylibs.append(self.allocator, dylib);
393381 },
394382 }
395383 }
......@@ -399,50 +387,64 @@ fn parseLibs(self: *Zld, libs: []const []const u8) !void {
399387 for (libs) |lib| {
400388 const file = try fs.cwd().openFile(lib, .{});
401389
402 if (try Dylib.isDylib(file)) {
403 const dylib = try self.allocator.create(Dylib);
404 errdefer self.allocator.destroy(dylib);
390 var kind: ?union(enum) {
391 archive,
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);
407 dylib.arch = self.arch.?;
408 dylib.name = try self.allocator.dupe(u8, lib);
409 dylib.file = file;
413 const unwrapped = kind orelse {
414 file.close();
415 log.warn("unknown filetype for a library: '{s}'", .{lib});
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();
412 try self.dylibs.append(self.allocator, dylib);
413 } else {
414 // Try tbd stub file next.
415 if (Stub.LibStub.loadFromFile(self.allocator, file)) |lib_stub| {
416 const stub = try self.allocator.create(Stub);
417 errdefer self.allocator.destroy(stub);
418
419 stub.* = Stub.init(self.allocator);
420 stub.arch = self.arch.?;
421 stub.name = try self.allocator.dupe(u8, lib);
422 stub.lib_stub = lib_stub;
423
424 try stub.parse();
425 try self.lib_stubs.append(self.allocator, stub);
426 } else |_| {
427 // TODO this entire logic has to be cleaned up.
428 try file.seekTo(0);
429
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);
423 archive.* = Archive.init(self.allocator);
424 archive.arch = self.arch.?;
425 archive.name = try self.allocator.dupe(u8, lib);
426 archive.file = file;
427
428 try archive.parse();
429 try self.archives.append(self.allocator, archive);
430 },
431 .dylib, .stub => {
432 const dylib = try self.allocator.create(Dylib);
433 errdefer self.allocator.destroy(dylib);
434
435 dylib.* = Dylib.init(self.allocator);
436 dylib.arch = self.arch.?;
437 dylib.name = try self.allocator.dupe(u8, lib);
438
439 if (unwrapped == .dylib) {
440 dylib.file = file;
441 try dylib.parse();
441442 } else {
442 file.close();
443 log.warn("unknown filetype for a library: '{s}'", .{lib});
443 try dylib.parseFromStub(unwrapped.stub);
444444 }
445 }
445
446 try self.dylibs.append(self.allocator, dylib);
447 },
446448 }
447449 }
448450}
......@@ -451,24 +453,24 @@ fn parseLibSystem(self: *Zld, libc_stub_path: []const u8) !void {
451453 const file = try fs.cwd().openFile(libc_stub_path, .{});
452454 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);
457 errdefer self.allocator.destroy(stub);
459 const dylib = try self.allocator.create(Dylib);
460 errdefer self.allocator.destroy(dylib);
458461
459 stub.* = Stub.init(self.allocator);
460 stub.arch = self.arch.?;
461 stub.name = try self.allocator.dupe(u8, libc_stub_path);
462 stub.lib_stub = lib_stub;
462 dylib.* = Dylib.init(self.allocator);
463 dylib.arch = self.arch.?;
464 dylib.name = try self.allocator.dupe(u8, libc_stub_path);
463465
464 try stub.parse();
466 try dylib.parseFromStub(lib_stub);
465467
466 self.libsystem_stub_index = @intCast(u16, self.lib_stubs.items.len);
467 try self.lib_stubs.append(self.allocator, stub);
468 self.libsystem_dylib_index = @intCast(u16, self.dylibs.items.len);
469 try self.dylibs.append(self.allocator, dylib);
468470
469471 // Add LC_LOAD_DYLIB load command.
470 stub.ordinal = self.next_dylib_ordinal;
471 const dylib_id = stub.id orelse unreachable;
472 dylib.ordinal = self.next_dylib_ordinal;
473 const dylib_id = dylib.id orelse unreachable;
472474 var dylib_cmd = try createLoadDylibCommand(
473475 self.allocator,
474476 dylib_id.name,
......@@ -1778,25 +1780,16 @@ fn resolveSymbols(self: *Zld) !void {
17781780 }
17791781 self.unresolved.clearRetainingCapacity();
17801782
1781 var referenced = std.AutoHashMap(union(enum) {
1782 dylib: *Dylib,
1783 stub: *Stub,
1784 }, void).init(self.allocator);
1783 var referenced = std.AutoHashMap(*Dylib, void).init(self.allocator);
17851784 defer referenced.deinit();
17861785
17871786 loop: while (unresolved.popOrNull()) |undef| {
17881787 const proxy = self.imports.get(undef.name) orelse outer: {
17891788 const proxy = inner: {
1790 for (self.dylibs.items) |dylib| {
1789 for (self.dylibs.items) |dylib, i| {
17911790 const proxy = (try dylib.createProxy(undef.name)) orelse continue;
1792 try referenced.put(.{ .dylib = dylib }, {});
1793 break :inner proxy;
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 }, {});
1791 if (self.libsystem_dylib_index.? != @intCast(u16, i)) { // LibSystem gets load command seperately.
1792 try referenced.put(dylib, {});
18001793 }
18011794 break :inner proxy;
18021795 }
......@@ -1829,33 +1822,17 @@ fn resolveSymbols(self: *Zld) !void {
18291822
18301823 // Add LC_LOAD_DYLIB load command for each referenced dylib/stub.
18311824 var it = referenced.iterator();
1832 while (it.next()) |key| {
1833 var dylib_cmd = blk: {
1834 switch (key.key_ptr.*) {
1835 .dylib => |dylib| {
1836 dylib.ordinal = self.next_dylib_ordinal;
1837 const dylib_id = dylib.id orelse unreachable;
1838 break :blk try createLoadDylibCommand(
1839 self.allocator,
1840 dylib_id.name,
1841 dylib_id.timestamp,
1842 dylib_id.current_version,
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 };
1825 while (it.next()) |entry| {
1826 const dylib = entry.key_ptr.*;
1827 dylib.ordinal = self.next_dylib_ordinal;
1828 const dylib_id = dylib.id orelse unreachable;
1829 var dylib_cmd = try createLoadDylibCommand(
1830 self.allocator,
1831 dylib_id.name,
1832 dylib_id.timestamp,
1833 dylib_id.current_version,
1834 dylib_id.compatibility_version,
1835 );
18591836 errdefer dylib_cmd.deinit(self.allocator);
18601837 try self.load_commands.append(self.allocator, .{ .Dylib = dylib_cmd });
18611838 self.next_dylib_ordinal += 1;
......@@ -1873,8 +1850,8 @@ fn resolveSymbols(self: *Zld) !void {
18731850 }
18741851
18751852 // Finally put dyld_stub_binder as an Import
1876 const libsystem_stub = self.lib_stubs.items[self.libsystem_stub_index.?];
1877 const proxy = (try libsystem_stub.createProxy("dyld_stub_binder")) orelse {
1853 const libsystem_dylib = self.dylibs.items[self.libsystem_dylib_index.?];
1854 const proxy = (try libsystem_dylib.createProxy("dyld_stub_binder")) orelse {
18781855 log.err("undefined reference to symbol 'dyld_stub_binder'", .{});
18791856 return error.UndefinedSymbolReference;
18801857 };