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,...@@ -37,10 +37,7 @@ id: ?Id = null,
37/// a symbol is referenced by an object file.37/// a symbol is referenced by an object file.
38symbols: std.StringArrayHashMapUnmanaged(void) = .{},38symbols: std.StringArrayHashMapUnmanaged(void) = .{},
3939
40// TODO we should keep track of already parsed dylibs so that40dependent_libs: std.StringArrayHashMapUnmanaged(void) = .{},
41// we don't unnecessarily reparse them again.
42// TODO add dylib dep analysis and extraction for .dylib files.
43dylibs: std.ArrayListUnmanaged(*Dylib) = .{},
4441
45pub const Id = struct {42pub const Id = struct {
46 name: []const u8,43 name: []const u8,
...@@ -66,7 +63,7 @@ pub fn createAndParseFromPath(...@@ -66,7 +63,7 @@ pub fn createAndParseFromPath(
66 path: []const u8,63 path: []const u8,
67 syslibroot: ?[]const u8,64 syslibroot: ?[]const u8,
68 recurse_libs: bool,65 recurse_libs: bool,
69) Error!?*Dylib {66) Error!?[]*Dylib {
70 const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {67 const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {
71 error.FileNotFound => return null,68 error.FileNotFound => return null,
72 else => |e| return e,69 else => |e| return e,
...@@ -87,7 +84,7 @@ pub fn createAndParseFromPath(...@@ -87,7 +84,7 @@ pub fn createAndParseFromPath(
87 .syslibroot = syslibroot,84 .syslibroot = syslibroot,
88 };85 };
8986
90 dylib.parse(recurse_libs) catch |err| switch (err) {87 dylib.parse() catch |err| switch (err) {
91 error.EndOfStream, error.NotDylib => {88 error.EndOfStream, error.NotDylib => {
92 try file.seekTo(0);89 try file.seekTo(0);
9390
...@@ -98,12 +95,20 @@ pub fn createAndParseFromPath(...@@ -98,12 +95,20 @@ pub fn createAndParseFromPath(
98 };95 };
99 defer lib_stub.deinit();96 defer lib_stub.deinit();
10097
101 try dylib.parseFromStub(lib_stub, recurse_libs);98 try dylib.parseFromStub(lib_stub);
102 },99 },
103 else => |e| return e,100 else => |e| return e,
104 };101 };
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();
107}112}
108113
109pub fn deinit(self: *Dylib) void {114pub fn deinit(self: *Dylib) void {
...@@ -116,7 +121,11 @@ pub fn deinit(self: *Dylib) void {...@@ -116,7 +121,11 @@ pub fn deinit(self: *Dylib) void {
116 self.allocator.free(key);121 self.allocator.free(key);
117 }122 }
118 self.symbols.deinit(self.allocator);123 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
121 if (self.name) |name| {130 if (self.name) |name| {
122 self.allocator.free(name);131 self.allocator.free(name);
...@@ -133,7 +142,7 @@ pub fn closeFile(self: Dylib) void {...@@ -133,7 +142,7 @@ pub fn closeFile(self: Dylib) void {
133 }142 }
134}143}
135144
136pub fn parse(self: *Dylib, recurse_libs: bool) !void {145pub fn parse(self: *Dylib) !void {
137 log.debug("parsing shared library '{s}'", .{self.name.?});146 log.debug("parsing shared library '{s}'", .{self.name.?});
138147
139 var reader = self.file.?.reader();148 var reader = self.file.?.reader();
...@@ -235,6 +244,13 @@ fn parseSymbols(self: *Dylib) !void {...@@ -235,6 +244,13 @@ fn parseSymbols(self: *Dylib) !void {
235 }244 }
236}245}
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
238fn addObjCClassSymbols(self: *Dylib, sym_name: []const u8) !void {254fn addObjCClassSymbols(self: *Dylib, sym_name: []const u8) !void {
239 const expanded = &[_][]const u8{255 const expanded = &[_][]const u8{
240 try std.fmt.allocPrint(self.allocator, "_OBJC_CLASS_$_{s}", .{sym_name}),256 try std.fmt.allocPrint(self.allocator, "_OBJC_CLASS_$_{s}", .{sym_name}),
...@@ -247,7 +263,7 @@ fn addObjCClassSymbols(self: *Dylib, sym_name: []const u8) !void {...@@ -247,7 +263,7 @@ fn addObjCClassSymbols(self: *Dylib, sym_name: []const u8) !void {
247 }263 }
248}264}
249265
250pub fn parseFromStub(self: *Dylib, lib_stub: LibStub, recurse_libs: bool) !void {266pub fn parseFromStub(self: *Dylib, lib_stub: LibStub) !void {
251 if (lib_stub.inner.len == 0) return error.EmptyStubFile;267 if (lib_stub.inner.len == 0) return error.EmptyStubFile;
252268
253 log.debug("parsing shared library from stub '{s}'", .{self.name.?});269 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...@@ -270,6 +286,17 @@ pub fn parseFromStub(self: *Dylib, lib_stub: LibStub, recurse_libs: bool) !void
270 for (lib_stub.inner) |stub| {286 for (lib_stub.inner) |stub| {
271 if (!hasTarget(stub.targets, target_string)) continue;287 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
273 if (stub.exports) |exports| {300 if (stub.exports) |exports| {
274 for (exports) |exp| {301 for (exports) |exp| {
275 if (!hasTarget(exp.targets, target_string)) continue;302 if (!hasTarget(exp.targets, target_string)) continue;
...@@ -314,69 +341,53 @@ pub fn parseFromStub(self: *Dylib, lib_stub: LibStub, recurse_libs: bool) !void...@@ -314,69 +341,53 @@ pub fn parseFromStub(self: *Dylib, lib_stub: LibStub, recurse_libs: bool) !void
314 }341 }
315 }342 }
316 }343 }
344}
317345
318 for (lib_stub.inner) |stub| {346pub fn parseDependentLibs(self: *Dylib, out: *std.ArrayList(*Dylib)) !void {
319 if (!hasTarget(stub.targets, target_string)) continue;347 outer: for (self.dependent_libs.keys()) |lib| {
320348 const dirname = fs.path.dirname(lib) orelse {
321 if (stub.reexported_libraries) |reexports| reexports: {349 log.warn("unable to resolve dependency {s}", .{lib});
322 if (!recurse_libs) break :reexports;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| {382 try out.appendSlice(dylibs);
325 if (!hasTarget(reexp.targets, target_string)) continue;
326383
327 outer: for (reexp.libraries) |lib| {384 continue :outer;
328 const dirname = fs.path.dirname(lib) orelse {385 } else {
329 log.warn("unable to resolve dependency {s}", .{lib});386 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 }387 }
370 }388 }
371}389}
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
380pub fn createProxy(self: *Dylib, sym_name: []const u8) !?*Symbol {391pub fn createProxy(self: *Dylib, sym_name: []const u8) !?*Symbol {
381 if (!self.symbols.contains(sym_name)) return null;392 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 {...@@ -280,8 +280,9 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
280 full_path,280 full_path,
281 self.syslibroot,281 self.syslibroot,
282 true,282 true,
283 )) |dylib| {283 )) |dylibs| {
284 try self.dylibs.append(self.allocator, dylib);284 defer self.allocator.free(dylibs);
285 try self.dylibs.appendSlice(self.allocator, dylibs);
285 continue;286 continue;
286 }287 }
287288
...@@ -290,18 +291,6 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {...@@ -290,18 +291,6 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
290}291}
291292
292fn parseLibs(self: *Zld, libs: []const []const u8) !void {293fn 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
305 for (libs) |lib| {294 for (libs) |lib| {
306 if (try Dylib.createAndParseFromPath(295 if (try Dylib.createAndParseFromPath(
307 self.allocator,296 self.allocator,
...@@ -309,8 +298,9 @@ fn parseLibs(self: *Zld, libs: []const []const u8) !void {...@@ -309,8 +298,9 @@ fn parseLibs(self: *Zld, libs: []const []const u8) !void {
309 lib,298 lib,
310 self.syslibroot,299 self.syslibroot,
311 true,300 true,
312 )) |dylib| {301 )) |dylibs| {
313 try self.dylibs.append(self.allocator, dylib);302 defer self.allocator.free(dylibs);
303 try self.dylibs.appendSlice(self.allocator, dylibs);
314 continue;304 continue;
315 }305 }
316306
...@@ -321,26 +311,21 @@ fn parseLibs(self: *Zld, libs: []const []const u8) !void {...@@ -321,26 +311,21 @@ fn parseLibs(self: *Zld, libs: []const []const u8) !void {
321311
322 log.warn("unknown filetype for a library: '{s}'", .{lib});312 log.warn("unknown filetype for a library: '{s}'", .{lib});
323 }313 }
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());
334}314}
335315
336fn parseLibSystem(self: *Zld, libc_stub_path: []const u8) !void {316fn parseLibSystem(self: *Zld, libc_stub_path: []const u8) !void {
337 const dylib = (try Dylib.createAndParseFromPath(317 const dylibs = (try Dylib.createAndParseFromPath(
338 self.allocator,318 self.allocator,
339 self.arch.?,319 self.arch.?,
340 libc_stub_path,320 libc_stub_path,
341 self.syslibroot,321 self.syslibroot,
342 false,322 false,
343 )) orelse return error.FailedToParseLibSystem;323 )) 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
344 self.libsystem_dylib_index = @intCast(u16, self.dylibs.items.len);329 self.libsystem_dylib_index = @intCast(u16, self.dylibs.items.len);
345 try self.dylibs.append(self.allocator, dylib);330 try self.dylibs.append(self.allocator, dylib);
346331