authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-06-23 15:11:31+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-06-24 18:57:11+02:00
log5ac5cd9de7c5387e37baa4f287d609c5d2f34564
tree65d97ee06e85f411493dbef7a5b1688e627f70c6
parent3cb6b6bd90c3b304bf771b37e974dd943c060e2b

zld: naively parse all dylib deps in stubs


6 files changed, 263 insertions(+), 234 deletions(-)

src/link/MachO.zig+1
...@@ -789,6 +789,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -789,6 +789,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
789 zld.deinit();789 zld.deinit();
790 }790 }
791 zld.arch = target.cpu.arch;791 zld.arch = target.cpu.arch;
792 zld.syslibroot = self.base.options.syslibroot;
792 zld.stack_size = stack_size;793 zld.stack_size = stack_size;
793794
794 // Positional arguments to the linker such as object files and static archives.795 // Positional arguments to the linker such as object files and static archives.
src/link/MachO/Archive.zig+41-22
...@@ -8,12 +8,13 @@ const macho = std.macho;...@@ -8,12 +8,13 @@ const macho = std.macho;
8const mem = std.mem;8const mem = std.mem;
99
10const Allocator = mem.Allocator;10const Allocator = mem.Allocator;
11const Arch = std.Target.Cpu.Arch;
11const Object = @import("Object.zig");12const Object = @import("Object.zig");
1213
13usingnamespace @import("commands.zig");14usingnamespace @import("commands.zig");
1415
15allocator: *Allocator,16allocator: *Allocator,
16arch: ?std.Target.Cpu.Arch = null,17arch: ?Arch = null,
17file: ?fs.File = null,18file: ?fs.File = null,
18header: ?ar_hdr = null,19header: ?ar_hdr = null,
19name: ?[]const u8 = null,20name: ?[]const u8 = null,
...@@ -85,10 +86,36 @@ const ar_hdr = extern struct {...@@ -85,10 +86,36 @@ const ar_hdr = extern struct {
85 }86 }
86};87};
8788
88pub fn init(allocator: *Allocator) Archive {89pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u8) !?*Archive {
89 return .{90 const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {
91 error.FileNotFound => return null,
92 else => |e| return e,
93 };
94 errdefer file.close();
95
96 const archive = try allocator.create(Archive);
97 errdefer allocator.destroy(archive);
98
99 const name = try allocator.dupe(u8, path);
100 errdefer allocator.free(name);
101
102 archive.* = .{
90 .allocator = allocator,103 .allocator = allocator,
104 .arch = arch,
105 .name = name,
106 .file = file,
107 };
108
109 archive.parse() catch |err| switch (err) {
110 error.EndOfStream, error.NotArchive => {
111 archive.deinit();
112 allocator.destroy(archive);
113 return null;
114 },
115 else => |e| return e,
91 };116 };
117
118 return archive;
92}119}
93120
94pub fn deinit(self: *Archive) void {121pub fn deinit(self: *Archive) void {
...@@ -116,15 +143,15 @@ pub fn parse(self: *Archive) !void {...@@ -116,15 +143,15 @@ pub fn parse(self: *Archive) !void {
116 const magic = try reader.readBytesNoEof(SARMAG);143 const magic = try reader.readBytesNoEof(SARMAG);
117144
118 if (!mem.eql(u8, &magic, ARMAG)) {145 if (!mem.eql(u8, &magic, ARMAG)) {
119 log.err("invalid magic: expected '{s}', found '{s}'", .{ ARMAG, magic });146 log.debug("invalid magic: expected '{s}', found '{s}'", .{ ARMAG, magic });
120 return error.MalformedArchive;147 return error.NotArchive;
121 }148 }
122149
123 self.header = try reader.readStruct(ar_hdr);150 self.header = try reader.readStruct(ar_hdr);
124151
125 if (!mem.eql(u8, &self.header.?.ar_fmag, ARFMAG)) {152 if (!mem.eql(u8, &self.header.?.ar_fmag, ARFMAG)) {
126 log.err("invalid header delimiter: expected '{s}', found '{s}'", .{ ARFMAG, self.header.?.ar_fmag });153 log.debug("invalid header delimiter: expected '{s}', found '{s}'", .{ ARFMAG, self.header.?.ar_fmag });
127 return error.MalformedArchive;154 return error.NotArchive;
128 }155 }
129156
130 var embedded_name = try parseName(self.allocator, self.header.?, reader);157 var embedded_name = try parseName(self.allocator, self.header.?, reader);
...@@ -222,23 +249,15 @@ pub fn parseObject(self: Archive, offset: u32) !*Object {...@@ -222,23 +249,15 @@ pub fn parseObject(self: Archive, offset: u32) !*Object {
222 var object = try self.allocator.create(Object);249 var object = try self.allocator.create(Object);
223 errdefer self.allocator.destroy(object);250 errdefer self.allocator.destroy(object);
224251
225 object.* = Object.init(self.allocator);252 object.* = .{
226 object.arch = self.arch.?;253 .allocator = self.allocator,
227 object.file = try fs.cwd().openFile(self.name.?, .{});254 .arch = self.arch.?,
228 object.name = name;255 .file = try fs.cwd().openFile(self.name.?, .{}),
229 object.file_offset = @intCast(u32, try reader.context.getPos());256 .name = name,
257 .file_offset = @intCast(u32, try reader.context.getPos()),
258 };
230 try object.parse();259 try object.parse();
231
232 try reader.context.seekTo(0);260 try reader.context.seekTo(0);
233261
234 return object;262 return object;
235}263}
236
237pub fn isArchive(file: fs.File) !bool {
238 const magic = file.reader().readBytesNoEof(Archive.SARMAG) catch |err| switch (err) {
239 error.EndOfStream => return false,
240 else => |e| return e,
241 };
242 try file.seekTo(0);
243 return mem.eql(u8, &magic, Archive.ARMAG);
244}
src/link/MachO/Dylib.zig+129-19
...@@ -8,6 +8,7 @@ const macho = std.macho;...@@ -8,6 +8,7 @@ const macho = std.macho;
8const mem = std.mem;8const mem = std.mem;
99
10const Allocator = mem.Allocator;10const Allocator = mem.Allocator;
11const Arch = std.Target.Cpu.Arch;
11const Symbol = @import("Symbol.zig");12const Symbol = @import("Symbol.zig");
12const LibStub = @import("../tapi.zig").LibStub;13const LibStub = @import("../tapi.zig").LibStub;
1314
...@@ -15,10 +16,11 @@ usingnamespace @import("commands.zig");...@@ -15,10 +16,11 @@ usingnamespace @import("commands.zig");
1516
16allocator: *Allocator,17allocator: *Allocator,
1718
18arch: ?std.Target.Cpu.Arch = null,19arch: ?Arch = null,
19header: ?macho.mach_header_64 = null,20header: ?macho.mach_header_64 = null,
20file: ?fs.File = null,21file: ?fs.File = null,
21name: ?[]const u8 = null,22name: ?[]const u8 = null,
23syslibroot: ?[]const u8 = null,
2224
23ordinal: ?u16 = null,25ordinal: ?u16 = null,
2426
...@@ -35,6 +37,11 @@ id: ?Id = null,...@@ -35,6 +37,11 @@ id: ?Id = null,
35/// a symbol is referenced by an object file.37/// a symbol is referenced by an object file.
36symbols: std.StringArrayHashMapUnmanaged(void) = .{},38symbols: std.StringArrayHashMapUnmanaged(void) = .{},
3739
40// TODO we should keep track of already parsed dylibs so that
41// we don't unnecessarily reparse them again.
42// TODO add dylib dep analysis and extraction for .dylib files.
43dylibs: std.ArrayListUnmanaged(*Dylib) = .{},
44
38pub const Id = struct {45pub const Id = struct {
39 name: []const u8,46 name: []const u8,
40 timestamp: u32,47 timestamp: u32,
...@@ -46,8 +53,57 @@ pub const Id = struct {...@@ -46,8 +53,57 @@ pub const Id = struct {
46 }53 }
47};54};
4855
49pub fn init(allocator: *Allocator) Dylib {56pub const Error = error{
50 return .{ .allocator = allocator };57 OutOfMemory,
58 EmptyStubFile,
59 MismatchedCpuArchitecture,
60 UnsupportedCpuArchitecture,
61} || fs.File.OpenError || std.os.PReadError;
62
63pub fn createAndParseFromPath(
64 allocator: *Allocator,
65 arch: Arch,
66 path: []const u8,
67 syslibroot: ?[]const u8,
68 recurse_libs: bool,
69) Error!?*Dylib {
70 const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {
71 error.FileNotFound => return null,
72 else => |e| return e,
73 };
74 errdefer file.close();
75
76 const dylib = try allocator.create(Dylib);
77 errdefer allocator.destroy(dylib);
78
79 const name = try allocator.dupe(u8, path);
80 errdefer allocator.free(name);
81
82 dylib.* = .{
83 .allocator = allocator,
84 .arch = arch,
85 .name = name,
86 .file = file,
87 .syslibroot = syslibroot,
88 };
89
90 dylib.parse(recurse_libs) catch |err| switch (err) {
91 error.EndOfStream, error.NotDylib => {
92 try file.seekTo(0);
93
94 var lib_stub = LibStub.loadFromFile(allocator, file) catch {
95 dylib.deinit();
96 allocator.destroy(dylib);
97 return null;
98 };
99 defer lib_stub.deinit();
100
101 try dylib.parseFromStub(lib_stub, recurse_libs);
102 },
103 else => |e| return e,
104 };
105
106 return dylib;
51}107}
52108
53pub fn deinit(self: *Dylib) void {109pub fn deinit(self: *Dylib) void {
...@@ -60,6 +116,7 @@ pub fn deinit(self: *Dylib) void {...@@ -60,6 +116,7 @@ pub fn deinit(self: *Dylib) void {
60 self.allocator.free(key);116 self.allocator.free(key);
61 }117 }
62 self.symbols.deinit(self.allocator);118 self.symbols.deinit(self.allocator);
119 self.dylibs.deinit(self.allocator);
63120
64 if (self.name) |name| {121 if (self.name) |name| {
65 self.allocator.free(name);122 self.allocator.free(name);
...@@ -76,15 +133,15 @@ pub fn closeFile(self: Dylib) void {...@@ -76,15 +133,15 @@ pub fn closeFile(self: Dylib) void {
76 }133 }
77}134}
78135
79pub fn parse(self: *Dylib) !void {136pub fn parse(self: *Dylib, recurse_libs: bool) !void {
80 log.debug("parsing shared library '{s}'", .{self.name.?});137 log.debug("parsing shared library '{s}'", .{self.name.?});
81138
82 var reader = self.file.?.reader();139 var reader = self.file.?.reader();
83 self.header = try reader.readStruct(macho.mach_header_64);140 self.header = try reader.readStruct(macho.mach_header_64);
84141
85 if (self.header.?.filetype != macho.MH_DYLIB) {142 if (self.header.?.filetype != macho.MH_DYLIB) {
86 log.err("invalid filetype: expected 0x{x}, found 0x{x}", .{ macho.MH_DYLIB, self.header.?.filetype });143 log.debug("invalid filetype: expected 0x{x}, found 0x{x}", .{ macho.MH_DYLIB, self.header.?.filetype });
87 return error.MalformedDylib;144 return error.NotDylib;
88 }145 }
89146
90 const this_arch: std.Target.Cpu.Arch = switch (self.header.?.cputype) {147 const this_arch: std.Target.Cpu.Arch = switch (self.header.?.cputype) {
...@@ -190,7 +247,7 @@ fn addObjCClassSymbols(self: *Dylib, sym_name: []const u8) !void {...@@ -190,7 +247,7 @@ fn addObjCClassSymbols(self: *Dylib, sym_name: []const u8) !void {
190 }247 }
191}248}
192249
193pub fn parseFromStub(self: *Dylib, lib_stub: LibStub) !void {250pub fn parseFromStub(self: *Dylib, lib_stub: LibStub, recurse_libs: bool) !void {
194 if (lib_stub.inner.len == 0) return error.EmptyStubFile;251 if (lib_stub.inner.len == 0) return error.EmptyStubFile;
195252
196 log.debug("parsing shared library from stub '{s}'", .{self.name.?});253 log.debug("parsing shared library from stub '{s}'", .{self.name.?});
...@@ -236,9 +293,17 @@ pub fn parseFromStub(self: *Dylib, lib_stub: LibStub) !void {...@@ -236,9 +293,17 @@ pub fn parseFromStub(self: *Dylib, lib_stub: LibStub) !void {
236 for (reexports) |reexp| {293 for (reexports) |reexp| {
237 if (!hasTarget(reexp.targets, target_string)) continue;294 if (!hasTarget(reexp.targets, target_string)) continue;
238295
239 for (reexp.symbols) |sym_name| {296 if (reexp.symbols) |symbols| {
240 if (self.symbols.contains(sym_name)) continue;297 for (symbols) |sym_name| {
241 try self.symbols.putNoClobber(self.allocator, try self.allocator.dupe(u8, sym_name), {});298 if (self.symbols.contains(sym_name)) continue;
299 try self.symbols.putNoClobber(self.allocator, try self.allocator.dupe(u8, sym_name), {});
300 }
301 }
302
303 if (reexp.objc_classes) |classes| {
304 for (classes) |sym_name| {
305 try self.addObjCClassSymbols(sym_name);
306 }
242 }307 }
243 }308 }
244 }309 }
...@@ -249,6 +314,60 @@ pub fn parseFromStub(self: *Dylib, lib_stub: LibStub) !void {...@@ -249,6 +314,60 @@ pub fn parseFromStub(self: *Dylib, lib_stub: LibStub) !void {
249 }314 }
250 }315 }
251 }316 }
317
318 for (lib_stub.inner) |stub| {
319 if (!hasTarget(stub.targets, target_string)) continue;
320
321 if (stub.reexported_libraries) |reexports| reexports: {
322 if (!recurse_libs) break :reexports;
323
324 for (reexports) |reexp| {
325 if (!hasTarget(reexp.targets, target_string)) continue;
326
327 outer: for (reexp.libraries) |lib| {
328 const dirname = fs.path.dirname(lib) orelse {
329 log.warn("unable to resolve dependency {s}", .{lib});
330 continue;
331 };
332 const filename = fs.path.basename(lib);
333 const without_ext = if (mem.lastIndexOfScalar(u8, filename, '.')) |index|
334 filename[0..index]
335 else
336 filename;
337
338 for (&[_][]const u8{ "dylib", "tbd" }) |ext| {
339 const with_ext = try std.fmt.allocPrint(self.allocator, "{s}.{s}", .{
340 without_ext,
341 ext,
342 });
343 defer self.allocator.free(with_ext);
344
345 const lib_path = if (self.syslibroot) |syslibroot|
346 try fs.path.join(self.allocator, &.{ syslibroot, dirname, with_ext })
347 else
348 try fs.path.join(self.allocator, &.{ dirname, with_ext });
349
350 log.debug("trying dependency at fully resolved path {s}", .{lib_path});
351
352 const dylib = (try createAndParseFromPath(
353 self.allocator,
354 self.arch.?,
355 lib_path,
356 self.syslibroot,
357 true,
358 )) orelse {
359 continue;
360 };
361
362 try self.dylibs.append(self.allocator, dylib);
363 continue :outer;
364 } else {
365 log.warn("unable to resolve dependency {s}", .{lib});
366 }
367 }
368 }
369 }
370 }
252}371}
253372
254fn hasTarget(targets: []const []const u8, target: []const u8) bool {373fn hasTarget(targets: []const []const u8, target: []const u8) bool {
...@@ -258,15 +377,6 @@ fn hasTarget(targets: []const []const u8, target: []const u8) bool {...@@ -258,15 +377,6 @@ fn hasTarget(targets: []const []const u8, target: []const u8) bool {
258 return false;377 return false;
259}378}
260379
261pub fn isDylib(file: fs.File) !bool {
262 const header = file.reader().readStruct(macho.mach_header_64) catch |err| switch (err) {
263 error.EndOfStream => return false,
264 else => |e| return e,
265 };
266 try file.seekTo(0);
267 return header.filetype == macho.MH_DYLIB;
268}
269
270pub fn createProxy(self: *Dylib, sym_name: []const u8) !?*Symbol {380pub fn createProxy(self: *Dylib, sym_name: []const u8) !?*Symbol {
271 if (!self.symbols.contains(sym_name)) return null;381 if (!self.symbols.contains(sym_name)) return null;
272382
src/link/MachO/Object.zig+37-15
...@@ -11,6 +11,7 @@ const mem = std.mem;...@@ -11,6 +11,7 @@ const mem = std.mem;
11const reloc = @import("reloc.zig");11const reloc = @import("reloc.zig");
1212
13const Allocator = mem.Allocator;13const Allocator = mem.Allocator;
14const Arch = std.Target.Cpu.Arch;
14const Relocation = reloc.Relocation;15const Relocation = reloc.Relocation;
15const Symbol = @import("Symbol.zig");16const Symbol = @import("Symbol.zig");
16const parseName = @import("Zld.zig").parseName;17const parseName = @import("Zld.zig").parseName;
...@@ -18,7 +19,7 @@ const parseName = @import("Zld.zig").parseName;...@@ -18,7 +19,7 @@ const parseName = @import("Zld.zig").parseName;
18usingnamespace @import("commands.zig");19usingnamespace @import("commands.zig");
1920
20allocator: *Allocator,21allocator: *Allocator,
21arch: ?std.Target.Cpu.Arch = null,22arch: ?Arch = null,
22header: ?macho.mach_header_64 = null,23header: ?macho.mach_header_64 = null,
23file: ?fs.File = null,24file: ?fs.File = null,
24file_offset: ?u32 = null,25file_offset: ?u32 = null,
...@@ -173,10 +174,36 @@ const DebugInfo = struct {...@@ -173,10 +174,36 @@ const DebugInfo = struct {
173 }174 }
174};175};
175176
176pub fn init(allocator: *Allocator) Object {177pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u8) !?*Object {
177 return .{178 const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {
179 error.FileNotFound => return null,
180 else => |e| return e,
181 };
182 errdefer file.close();
183
184 const object = try allocator.create(Object);
185 errdefer allocator.destroy(object);
186
187 const name = try allocator.dupe(u8, path);
188 errdefer allocator.free(name);
189
190 object.* = .{
178 .allocator = allocator,191 .allocator = allocator,
192 .arch = arch,
193 .name = name,
194 .file = file,
179 };195 };
196
197 object.parse() catch |err| switch (err) {
198 error.EndOfStream, error.NotObject => {
199 object.deinit();
200 allocator.destroy(object);
201 return null;
202 },
203 else => |e| return e,
204 };
205
206 return object;
180}207}
181208
182pub fn deinit(self: *Object) void {209pub fn deinit(self: *Object) void {
...@@ -223,11 +250,15 @@ pub fn parse(self: *Object) !void {...@@ -223,11 +250,15 @@ pub fn parse(self: *Object) !void {
223 self.header = try reader.readStruct(macho.mach_header_64);250 self.header = try reader.readStruct(macho.mach_header_64);
224251
225 if (self.header.?.filetype != macho.MH_OBJECT) {252 if (self.header.?.filetype != macho.MH_OBJECT) {
226 log.err("invalid filetype: expected 0x{x}, found 0x{x}", .{ macho.MH_OBJECT, self.header.?.filetype });253 log.debug("invalid filetype: expected 0x{x}, found 0x{x}", .{
227 return error.MalformedObject;254 macho.MH_OBJECT,
255 self.header.?.filetype,
256 });
257
258 return error.NotObject;
228 }259 }
229260
230 const this_arch: std.Target.Cpu.Arch = switch (self.header.?.cputype) {261 const this_arch: Arch = switch (self.header.?.cputype) {
231 macho.CPU_TYPE_ARM64 => .aarch64,262 macho.CPU_TYPE_ARM64 => .aarch64,
232 macho.CPU_TYPE_X86_64 => .x86_64,263 macho.CPU_TYPE_X86_64 => .x86_64,
233 else => |value| {264 else => |value| {
...@@ -533,12 +564,3 @@ pub fn parseDataInCode(self: *Object) !void {...@@ -533,12 +564,3 @@ pub fn parseDataInCode(self: *Object) !void {
533 try self.data_in_code_entries.append(self.allocator, dice);564 try self.data_in_code_entries.append(self.allocator, dice);
534 }565 }
535}566}
536
537pub fn isObject(file: fs.File) !bool {
538 const header = file.reader().readStruct(macho.mach_header_64) catch |err| switch (err) {
539 error.EndOfStream => return false,
540 else => |e| return e,
541 };
542 try file.seekTo(0);
543 return header.filetype == macho.MH_OBJECT;
544}
src/link/MachO/Zld.zig+53-177
...@@ -16,7 +16,6 @@ const Allocator = mem.Allocator;...@@ -16,7 +16,6 @@ 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;
20const Object = @import("Object.zig");19const Object = @import("Object.zig");
21const Symbol = @import("Symbol.zig");20const Symbol = @import("Symbol.zig");
22const Trie = @import("Trie.zig");21const Trie = @import("Trie.zig");
...@@ -33,6 +32,7 @@ out_path: ?[]const u8 = null,...@@ -33,6 +32,7 @@ out_path: ?[]const u8 = null,
3332
34// TODO these args will become obselete once Zld is coalesced with incremental33// TODO these args will become obselete once Zld is coalesced with incremental
35// linker.34// linker.
35syslibroot: ?[]const u8 = null,
36stack_size: u64 = 0,36stack_size: u64 = 0,
3737
38objects: std.ArrayListUnmanaged(*Object) = .{},38objects: std.ArrayListUnmanaged(*Object) = .{},
...@@ -257,214 +257,90 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L...@@ -257,214 +257,90 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L
257}257}
258258
259fn parseInputFiles(self: *Zld, files: []const []const u8) !void {259fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
260 const Input = struct {
261 kind: union(enum) {
262 object: fs.File,
263 archive: fs.File,
264 dylib: fs.File,
265 stub: LibStub,
266 },
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 }
277 };
278 var classified = std.ArrayList(Input).init(self.allocator);
279 defer {
280 for (classified.items) |*input| {
281 input.deinit();
282 }
283 classified.deinit();
284 }
285
286 // First, classify input files: object, archive, dylib or stub (tbd).
287 for (files) |file_name| {260 for (files) |file_name| {
288 const file = try fs.cwd().openFile(file_name, .{});
289 const full_path = full_path: {261 const full_path = full_path: {
290 var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;262 var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
291 const path = try std.fs.realpath(file_name, &buffer);263 const path = try std.fs.realpath(file_name, &buffer);
292 break :full_path try self.allocator.dupe(u8, path);264 break :full_path try self.allocator.dupe(u8, path);
293 };265 };
294266
295 try_object: {267 if (try Object.createAndParseFromPath(self.allocator, self.arch.?, full_path)) |object| {
296 if (!(try Object.isObject(file))) break :try_object;268 try self.objects.append(self.allocator, object);
297 try classified.append(.{
298 .kind = .{ .object = file },
299 .name = full_path,
300 });
301 continue;
302 }
303
304 try_archive: {
305 if (!(try Archive.isArchive(file))) break :try_archive;
306 try classified.append(.{
307 .kind = .{ .archive = file },
308 .name = full_path,
309 });
310 continue;269 continue;
311 }270 }
312271
313 try_dylib: {272 if (try Archive.createAndParseFromPath(self.allocator, self.arch.?, full_path)) |archive| {
314 if (!(try Dylib.isDylib(file))) break :try_dylib;273 try self.archives.append(self.allocator, archive);
315 try classified.append(.{
316 .kind = .{ .dylib = file },
317 .name = full_path,
318 });
319 continue;274 continue;
320 }275 }
321276
322 try_stub: {277 if (try Dylib.createAndParseFromPath(
323 var lib_stub = LibStub.loadFromFile(self.allocator, file) catch {278 self.allocator,
324 break :try_stub;279 self.arch.?,
325 };280 full_path,
326 try classified.append(.{281 self.syslibroot,
327 .kind = .{ .stub = lib_stub },282 true,
328 .name = full_path,283 )) |dylib| {
329 });284 try self.dylibs.append(self.allocator, dylib);
330 file.close();
331 continue;285 continue;
332 }286 }
333287
334 file.close();
335 log.warn("unknown filetype for positional input file: '{s}'", .{file_name});288 log.warn("unknown filetype for positional input file: '{s}'", .{file_name});
336 }289 }
337
338 // Based on our classification, proceed with parsing.
339 for (classified.items) |input| {
340 switch (input.kind) {
341 .object => |file| {
342 const object = try self.allocator.create(Object);
343 errdefer self.allocator.destroy(object);
344
345 object.* = Object.init(self.allocator);
346 object.arch = self.arch.?;
347 object.name = input.name;
348 object.file = file;
349
350 try object.parse();
351 try self.objects.append(self.allocator, object);
352 },
353 .archive => |file| {
354 const archive = try self.allocator.create(Archive);
355 errdefer self.allocator.destroy(archive);
356
357 archive.* = Archive.init(self.allocator);
358 archive.arch = self.arch.?;
359 archive.name = input.name;
360 archive.file = file;
361
362 try archive.parse();
363 try self.archives.append(self.allocator, archive);
364 },
365 .dylib, .stub => {
366 const dylib = try self.allocator.create(Dylib);
367 errdefer self.allocator.destroy(dylib);
368
369 dylib.* = Dylib.init(self.allocator);
370 dylib.arch = self.arch.?;
371 dylib.name = input.name;
372
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 }
379
380 try self.dylibs.append(self.allocator, dylib);
381 },
382 }
383 }
384}290}
385291
386fn parseLibs(self: *Zld, libs: []const []const u8) !void {292fn parseLibs(self: *Zld, libs: []const []const u8) !void {
387 for (libs) |lib| {293 const DylibDeps = struct {
388 const file = try fs.cwd().openFile(lib, .{});294 fn bubbleUp(out: *std.ArrayList(*Dylib), next: *Dylib) error{OutOfMemory}!void {
389295 try out.ensureUnusedCapacity(next.dylibs.items.len);
390 var kind: ?union(enum) {296 for (next.dylibs.items) |dylib| {
391 archive,297 out.appendAssumeCapacity(dylib);
392 dylib,298 }
393 stub: LibStub,299 for (next.dylibs.items) |dylib| {
394 } = kind: {300 try bubbleUp(out, dylib);
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 }301 }
411 }302 }
303 };
412304
413 const unwrapped = kind orelse {305 for (libs) |lib| {
414 file.close();306 if (try Dylib.createAndParseFromPath(
415 log.warn("unknown filetype for a library: '{s}'", .{lib});307 self.allocator,
308 self.arch.?,
309 lib,
310 self.syslibroot,
311 true,
312 )) |dylib| {
313 try self.dylibs.append(self.allocator, dylib);
416 continue;314 continue;
417 };
418 switch (unwrapped) {
419 .archive => {
420 const archive = try self.allocator.create(Archive);
421 errdefer self.allocator.destroy(archive);
422
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();
442 } else {
443 try dylib.parseFromStub(unwrapped.stub);
444 }
445
446 try self.dylibs.append(self.allocator, dylib);
447 },
448 }315 }
449 }
450}
451316
452fn parseLibSystem(self: *Zld, libc_stub_path: []const u8) !void {317 if (try Archive.createAndParseFromPath(self.allocator, self.arch.?, lib)) |archive| {
453 const file = try fs.cwd().openFile(libc_stub_path, .{});318 try self.archives.append(self.allocator, archive);
454 defer file.close();319 continue;
320 }
455321
456 var lib_stub = try LibStub.loadFromFile(self.allocator, file);322 log.warn("unknown filetype for a library: '{s}'", .{lib});
457 defer lib_stub.deinit();323 }
458324
459 const dylib = try self.allocator.create(Dylib);325 // Flatten out any parsed dependencies.
460 errdefer self.allocator.destroy(dylib);326 var deps = std.ArrayList(*Dylib).init(self.allocator);
327 defer deps.deinit();
461328
462 dylib.* = Dylib.init(self.allocator);329 for (self.dylibs.items) |dylib| {
463 dylib.arch = self.arch.?;330 try DylibDeps.bubbleUp(&deps, dylib);
464 dylib.name = try self.allocator.dupe(u8, libc_stub_path);331 }
465332
466 try dylib.parseFromStub(lib_stub);333 try self.dylibs.appendSlice(self.allocator, deps.toOwnedSlice());
334}
467335
336fn parseLibSystem(self: *Zld, libc_stub_path: []const u8) !void {
337 const dylib = (try Dylib.createAndParseFromPath(
338 self.allocator,
339 self.arch.?,
340 libc_stub_path,
341 self.syslibroot,
342 false,
343 )) orelse return error.FailedToParseLibSystem;
468 self.libsystem_dylib_index = @intCast(u16, self.dylibs.items.len);344 self.libsystem_dylib_index = @intCast(u16, self.dylibs.items.len);
469 try self.dylibs.append(self.allocator, dylib);345 try self.dylibs.append(self.allocator, dylib);
470346
src/link/tapi.zig+2-1
...@@ -41,7 +41,8 @@ pub const LibStub = struct {...@@ -41,7 +41,8 @@ pub const LibStub = struct {
41 },41 },
42 reexports: ?[]const struct {42 reexports: ?[]const struct {
43 targets: []const []const u8,43 targets: []const []const u8,
44 symbols: []const []const u8,44 symbols: ?[]const []const u8,
45 objc_classes: ?[]const []const u8,
45 },46 },
46 allowable_clients: ?[]const struct {47 allowable_clients: ?[]const struct {
47 targets: []const []const u8,48 targets: []const []const u8,