authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-06-24 14:39:30+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-06-24 18:57:21+02:00
log8669e3d46b24fcd6b6aa1053a16cf5301ed0e87a
treea374adcea5428b2dd598f2365ac3bb3a63f4792b
parent5ac5cd9de7c5387e37baa4f287d609c5d2f34564

zld: when parsing dylibs, allow multiple return values


2 files changed, 90 insertions(+), 94 deletions(-)

src/link/MachO/Dylib.zig+78-67
......@@ -37,10 +37,7 @@ id: ?Id = null,
3737/// a symbol is referenced by an object file.
3838symbols: std.StringArrayHashMapUnmanaged(void) = .{},
3939
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) = .{},
40dependent_libs: std.StringArrayHashMapUnmanaged(void) = .{},
4441
4542pub const Id = struct {
4643 name: []const u8,
......@@ -66,7 +63,7 @@ pub fn createAndParseFromPath(
6663 path: []const u8,
6764 syslibroot: ?[]const u8,
6865 recurse_libs: bool,
69) Error!?*Dylib {
66) Error!?[]*Dylib {
7067 const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {
7168 error.FileNotFound => return null,
7269 else => |e| return e,
......@@ -87,7 +84,7 @@ pub fn createAndParseFromPath(
8784 .syslibroot = syslibroot,
8885 };
8986
90 dylib.parse(recurse_libs) catch |err| switch (err) {
87 dylib.parse() catch |err| switch (err) {
9188 error.EndOfStream, error.NotDylib => {
9289 try file.seekTo(0);
9390
......@@ -98,12 +95,20 @@ pub fn createAndParseFromPath(
9895 };
9996 defer lib_stub.deinit();
10097
101 try dylib.parseFromStub(lib_stub, recurse_libs);
98 try dylib.parseFromStub(lib_stub);
10299 },
103100 else => |e| return e,
104101 };
105102
106 return dylib;
103 var dylibs = std.ArrayList(*Dylib).init(allocator);
104 defer dylibs.deinit();
105 try dylibs.append(dylib);
106
107 if (recurse_libs) {
108 try dylib.parseDependentLibs(&dylibs);
109 }
110
111 return dylibs.toOwnedSlice();
107112}
108113
109114pub fn deinit(self: *Dylib) void {
......@@ -116,7 +121,11 @@ pub fn deinit(self: *Dylib) void {
116121 self.allocator.free(key);
117122 }
118123 self.symbols.deinit(self.allocator);
119 self.dylibs.deinit(self.allocator);
124
125 for (self.dependent_libs.keys()) |key| {
126 self.allocator.free(key);
127 }
128 self.dependent_libs.deinit(self.allocator);
120129
121130 if (self.name) |name| {
122131 self.allocator.free(name);
......@@ -133,7 +142,7 @@ pub fn closeFile(self: Dylib) void {
133142 }
134143}
135144
136pub fn parse(self: *Dylib, recurse_libs: bool) !void {
145pub fn parse(self: *Dylib) !void {
137146 log.debug("parsing shared library '{s}'", .{self.name.?});
138147
139148 var reader = self.file.?.reader();
......@@ -235,6 +244,13 @@ fn parseSymbols(self: *Dylib) !void {
235244 }
236245}
237246
247fn hasTarget(targets: []const []const u8, target: []const u8) bool {
248 for (targets) |t| {
249 if (mem.eql(u8, t, target)) return true;
250 }
251 return false;
252}
253
238254fn addObjCClassSymbols(self: *Dylib, sym_name: []const u8) !void {
239255 const expanded = &[_][]const u8{
240256 try std.fmt.allocPrint(self.allocator, "_OBJC_CLASS_$_{s}", .{sym_name}),
......@@ -247,7 +263,7 @@ fn addObjCClassSymbols(self: *Dylib, sym_name: []const u8) !void {
247263 }
248264}
249265
250pub fn parseFromStub(self: *Dylib, lib_stub: LibStub, recurse_libs: bool) !void {
266pub fn parseFromStub(self: *Dylib, lib_stub: LibStub) !void {
251267 if (lib_stub.inner.len == 0) return error.EmptyStubFile;
252268
253269 log.debug("parsing shared library from stub '{s}'", .{self.name.?});
......@@ -270,6 +286,17 @@ pub fn parseFromStub(self: *Dylib, lib_stub: LibStub, recurse_libs: bool) !void
270286 for (lib_stub.inner) |stub| {
271287 if (!hasTarget(stub.targets, target_string)) continue;
272288
289 if (stub.reexported_libraries) |reexports| {
290 for (reexports) |reexp| {
291 if (!hasTarget(reexp.targets, target_string)) continue;
292
293 try self.dependent_libs.ensureUnusedCapacity(self.allocator, reexp.libraries.len);
294 for (reexp.libraries) |lib| {
295 self.dependent_libs.putAssumeCapacity(try self.allocator.dupe(u8, lib), {});
296 }
297 }
298 }
299
273300 if (stub.exports) |exports| {
274301 for (exports) |exp| {
275302 if (!hasTarget(exp.targets, target_string)) continue;
......@@ -314,69 +341,53 @@ pub fn parseFromStub(self: *Dylib, lib_stub: LibStub, recurse_libs: bool) !void
314341 }
315342 }
316343 }
344}
317345
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;
346pub fn parseDependentLibs(self: *Dylib, out: *std.ArrayList(*Dylib)) !void {
347 outer: for (self.dependent_libs.keys()) |lib| {
348 const dirname = fs.path.dirname(lib) orelse {
349 log.warn("unable to resolve dependency {s}", .{lib});
350 continue;
351 };
352 const filename = fs.path.basename(lib);
353 const without_ext = if (mem.lastIndexOfScalar(u8, filename, '.')) |index|
354 filename[0..index]
355 else
356 filename;
357
358 for (&[_][]const u8{ "dylib", "tbd" }) |ext| {
359 const with_ext = try std.fmt.allocPrint(self.allocator, "{s}.{s}", .{
360 without_ext,
361 ext,
362 });
363 defer self.allocator.free(with_ext);
364
365 const lib_path = if (self.syslibroot) |syslibroot|
366 try fs.path.join(self.allocator, &.{ syslibroot, dirname, with_ext })
367 else
368 try fs.path.join(self.allocator, &.{ dirname, with_ext });
369
370 log.debug("trying dependency at fully resolved path {s}", .{lib_path});
371
372 const dylibs = (try createAndParseFromPath(
373 self.allocator,
374 self.arch.?,
375 lib_path,
376 self.syslibroot,
377 true,
378 )) orelse {
379 continue;
380 };
323381
324 for (reexports) |reexp| {
325 if (!hasTarget(reexp.targets, target_string)) continue;
382 try out.appendSlice(dylibs);
326383
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 }
384 continue :outer;
385 } else {
386 log.warn("unable to resolve dependency {s}", .{lib});
369387 }
370388 }
371389}
372390
373fn hasTarget(targets: []const []const u8, target: []const u8) bool {
374 for (targets) |t| {
375 if (mem.eql(u8, t, target)) return true;
376 }
377 return false;
378}
379
380391pub fn createProxy(self: *Dylib, sym_name: []const u8) !?*Symbol {
381392 if (!self.symbols.contains(sym_name)) return null;
382393
src/link/MachO/Zld.zig+12-27
......@@ -280,8 +280,9 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
280280 full_path,
281281 self.syslibroot,
282282 true,
283 )) |dylib| {
284 try self.dylibs.append(self.allocator, dylib);
283 )) |dylibs| {
284 defer self.allocator.free(dylibs);
285 try self.dylibs.appendSlice(self.allocator, dylibs);
285286 continue;
286287 }
287288
......@@ -290,18 +291,6 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
290291}
291292
292293fn parseLibs(self: *Zld, libs: []const []const u8) !void {
293 const DylibDeps = struct {
294 fn bubbleUp(out: *std.ArrayList(*Dylib), next: *Dylib) error{OutOfMemory}!void {
295 try out.ensureUnusedCapacity(next.dylibs.items.len);
296 for (next.dylibs.items) |dylib| {
297 out.appendAssumeCapacity(dylib);
298 }
299 for (next.dylibs.items) |dylib| {
300 try bubbleUp(out, dylib);
301 }
302 }
303 };
304
305294 for (libs) |lib| {
306295 if (try Dylib.createAndParseFromPath(
307296 self.allocator,
......@@ -309,8 +298,9 @@ fn parseLibs(self: *Zld, libs: []const []const u8) !void {
309298 lib,
310299 self.syslibroot,
311300 true,
312 )) |dylib| {
313 try self.dylibs.append(self.allocator, dylib);
301 )) |dylibs| {
302 defer self.allocator.free(dylibs);
303 try self.dylibs.appendSlice(self.allocator, dylibs);
314304 continue;
315305 }
316306
......@@ -321,26 +311,21 @@ fn parseLibs(self: *Zld, libs: []const []const u8) !void {
321311
322312 log.warn("unknown filetype for a library: '{s}'", .{lib});
323313 }
324
325 // Flatten out any parsed dependencies.
326 var deps = std.ArrayList(*Dylib).init(self.allocator);
327 defer deps.deinit();
328
329 for (self.dylibs.items) |dylib| {
330 try DylibDeps.bubbleUp(&deps, dylib);
331 }
332
333 try self.dylibs.appendSlice(self.allocator, deps.toOwnedSlice());
334314}
335315
336316fn parseLibSystem(self: *Zld, libc_stub_path: []const u8) !void {
337 const dylib = (try Dylib.createAndParseFromPath(
317 const dylibs = (try Dylib.createAndParseFromPath(
338318 self.allocator,
339319 self.arch.?,
340320 libc_stub_path,
341321 self.syslibroot,
342322 false,
343323 )) orelse return error.FailedToParseLibSystem;
324 defer self.allocator.free(dylibs);
325
326 assert(dylibs.len == 1); // More than one dylib output from parsing libSystem!
327 const dylib = dylibs[0];
328
344329 self.libsystem_dylib_index = @intCast(u16, self.dylibs.items.len);
345330 try self.dylibs.append(self.allocator, dylib);
346331