| ... | @@ -243,14 +243,16 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { | ... | @@ -243,14 +243,16 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { |
| 243 | object, | 243 | object, |
| 244 | archive, | 244 | archive, |
| 245 | dylib, | 245 | dylib, |
| | 246 | stub, |
| 246 | }, | 247 | }, |
| 247 | file: fs.File, | 248 | file: fs.File, |
| 248 | name: []const u8, | 249 | name: []const u8, |
| | 250 | stub: ?LibStub = null, |
| 249 | }; | 251 | }; |
| 250 | var classified = std.ArrayList(Input).init(self.allocator); | 252 | var classified = std.ArrayList(Input).init(self.allocator); |
| 251 | defer classified.deinit(); | 253 | defer classified.deinit(); |
| 252 | | 254 | |
| 253 | // First, classify input files: object, archive or dylib. | 255 | // First, classify input files: object, archive, dylib or stub (tbd). |
| 254 | for (files) |file_name| { | 256 | for (files) |file_name| { |
| 255 | const file = try fs.cwd().openFile(file_name, .{}); | 257 | const file = try fs.cwd().openFile(file_name, .{}); |
| 256 | const full_path = full_path: { | 258 | const full_path = full_path: { |
| ... | @@ -260,7 +262,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { | ... | @@ -260,7 +262,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { |
| 260 | }; | 262 | }; |
| 261 | | 263 | |
| 262 | try_object: { | 264 | try_object: { |
| 263 | if (!(try Object.isObject(file))) break :try_object; | 265 | if (!Object.isObject(file)) break :try_object; |
| 264 | try classified.append(.{ | 266 | try classified.append(.{ |
| 265 | .kind = .object, | 267 | .kind = .object, |
| 266 | .file = file, | 268 | .file = file, |
| ... | @@ -270,7 +272,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { | ... | @@ -270,7 +272,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { |
| 270 | } | 272 | } |
| 271 | | 273 | |
| 272 | try_archive: { | 274 | try_archive: { |
| 273 | if (!(try Archive.isArchive(file))) break :try_archive; | 275 | if (!Archive.isArchive(file)) break :try_archive; |
| 274 | try classified.append(.{ | 276 | try classified.append(.{ |
| 275 | .kind = .archive, | 277 | .kind = .archive, |
| 276 | .file = file, | 278 | .file = file, |
| ... | @@ -280,7 +282,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { | ... | @@ -280,7 +282,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { |
| 280 | } | 282 | } |
| 281 | | 283 | |
| 282 | try_dylib: { | 284 | try_dylib: { |
| 283 | if (!(try Dylib.isDylib(file))) break :try_dylib; | 285 | if (!Dylib.isDylib(file)) break :try_dylib; |
| 284 | try classified.append(.{ | 286 | try classified.append(.{ |
| 285 | .kind = .dylib, | 287 | .kind = .dylib, |
| 286 | .file = file, | 288 | .file = file, |
| ... | @@ -289,6 +291,19 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { | ... | @@ -289,6 +291,19 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { |
| 289 | continue; | 291 | continue; |
| 290 | } | 292 | } |
| 291 | | 293 | |
| | 294 | try_stub: { |
| | 295 | var lib_stub = LibStub.loadFromFile(self.allocator, file) catch |_| { |
| | 296 | break :try_stub; |
| | 297 | }; |
| | 298 | try classified.append(.{ |
| | 299 | .kind = .stub, |
| | 300 | .file = file, |
| | 301 | .name = full_path, |
| | 302 | .stub = lib_stub, |
| | 303 | }); |
| | 304 | continue; |
| | 305 | } |
| | 306 | |
| 292 | file.close(); | 307 | file.close(); |
| 293 | log.warn("unknown filetype for positional input file: '{s}'", .{file_name}); | 308 | log.warn("unknown filetype for positional input file: '{s}'", .{file_name}); |
| 294 | } | 309 | } |
| ... | @@ -318,7 +333,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { | ... | @@ -318,7 +333,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { |
| 318 | try archive.parse(); | 333 | try archive.parse(); |
| 319 | try self.archives.append(self.allocator, archive); | 334 | try self.archives.append(self.allocator, archive); |
| 320 | }, | 335 | }, |
| 321 | .dylib => { | 336 | .dylib, .stub => { |
| 322 | const dylib = try self.allocator.create(Dylib); | 337 | const dylib = try self.allocator.create(Dylib); |
| 323 | errdefer self.allocator.destroy(dylib); | 338 | errdefer self.allocator.destroy(dylib); |
| 324 | | 339 | |
| ... | @@ -329,7 +344,11 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { | ... | @@ -329,7 +344,11 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { |
| 329 | dylib.ordinal = @intCast(u16, self.dylibs.items.len) + 1; | 344 | dylib.ordinal = @intCast(u16, self.dylibs.items.len) + 1; |
| 330 | | 345 | |
| 331 | // TODO Defer parsing of the dylibs until they are actually needed | 346 | // TODO Defer parsing of the dylibs until they are actually needed |
| 332 | try dylib.parse(); | 347 | if (input.stub) |stub| { |
| | 348 | try dylib.parseFromStub(stub); |
| | 349 | } else { |
| | 350 | try dylib.parse(); |
| | 351 | } |
| 333 | try self.dylibs.append(self.allocator, dylib); | 352 | try self.dylibs.append(self.allocator, dylib); |
| 334 | | 353 | |
| 335 | // Add LC_LOAD_DYLIB command | 354 | // Add LC_LOAD_DYLIB command |
| ... | @@ -353,7 +372,7 @@ fn parseLibs(self: *Zld, libs: []const []const u8) !void { | ... | @@ -353,7 +372,7 @@ fn parseLibs(self: *Zld, libs: []const []const u8) !void { |
| 353 | for (libs) |lib| { | 372 | for (libs) |lib| { |
| 354 | const file = try fs.cwd().openFile(lib, .{}); | 373 | const file = try fs.cwd().openFile(lib, .{}); |
| 355 | | 374 | |
| 356 | if (try Dylib.isDylib(file)) { | 375 | if (Dylib.isDylib(file)) { |
| 357 | const dylib = try self.allocator.create(Dylib); | 376 | const dylib = try self.allocator.create(Dylib); |
| 358 | errdefer self.allocator.destroy(dylib); | 377 | errdefer self.allocator.destroy(dylib); |
| 359 | | 378 | |
| ... | @@ -379,28 +398,55 @@ fn parseLibs(self: *Zld, libs: []const []const u8) !void { | ... | @@ -379,28 +398,55 @@ fn parseLibs(self: *Zld, libs: []const []const u8) !void { |
| 379 | errdefer dylib_cmd.deinit(self.allocator); | 398 | errdefer dylib_cmd.deinit(self.allocator); |
| 380 | | 399 | |
| 381 | try self.load_commands.append(self.allocator, .{ .Dylib = dylib_cmd }); | 400 | try self.load_commands.append(self.allocator, .{ .Dylib = dylib_cmd }); |
| 382 | } else if (try Archive.isArchive(file)) { | | |
| 383 | const archive = try self.allocator.create(Archive); | | |
| 384 | errdefer self.allocator.destroy(archive); | | |
| 385 | | | |
| 386 | archive.* = Archive.init(self.allocator); | | |
| 387 | archive.arch = self.arch.?; | | |
| 388 | archive.name = try self.allocator.dupe(u8, lib); | | |
| 389 | archive.file = file; | | |
| 390 | try archive.parse(); | | |
| 391 | try self.archives.append(self.allocator, archive); | | |
| 392 | } else { | 401 | } else { |
| 393 | file.close(); | 402 | // Try tbd stub file next. |
| 394 | log.warn("unknown filetype for a library: '{s}'", .{lib}); | 403 | if (LibStub.loadFromFile(self.allocator, file)) |*lib_stub| { |
| 395 | } | 404 | defer lib_stub.deinit(); |
| 396 | } | 405 | |
| 397 | } | 406 | const dylib = try self.allocator.create(Dylib); |
| | 407 | errdefer self.allocator.destroy(dylib); |
| | 408 | |
| | 409 | dylib.* = Dylib.init(self.allocator); |
| | 410 | dylib.arch = self.arch.?; |
| | 411 | dylib.name = try self.allocator.dupe(u8, lib); |
| | 412 | dylib.file = file; |
| | 413 | dylib.ordinal = @intCast(u16, self.dylibs.items.len) + 1; |
| | 414 | |
| | 415 | try dylib.parseFromStub(lib_stub.*); |
| | 416 | try self.dylibs.append(self.allocator, dylib); |
| | 417 | |
| | 418 | // Add LC_LOAD_DYLIB command |
| | 419 | const dylib_id = dylib.id orelse unreachable; |
| | 420 | var dylib_cmd = try createLoadDylibCommand( |
| | 421 | self.allocator, |
| | 422 | dylib_id.name, |
| | 423 | dylib_id.timestamp, |
| | 424 | dylib_id.current_version, |
| | 425 | dylib_id.compatibility_version, |
| | 426 | ); |
| | 427 | errdefer dylib_cmd.deinit(self.allocator); |
| 398 | | 428 | |
| 399 | fn hasTarget(targets: []const []const u8, target: []const u8) bool { | 429 | try self.load_commands.append(self.allocator, .{ .Dylib = dylib_cmd }); |
| 400 | for (targets) |t| { | 430 | } else |_| { |
| 401 | if (mem.eql(u8, t, target)) return true; | 431 | // TODO this entire logic has to be cleaned up. |
| | 432 | try file.seekTo(0); |
| | 433 | if (Archive.isArchive(file)) { |
| | 434 | const archive = try self.allocator.create(Archive); |
| | 435 | errdefer self.allocator.destroy(archive); |
| | 436 | |
| | 437 | archive.* = Archive.init(self.allocator); |
| | 438 | archive.arch = self.arch.?; |
| | 439 | archive.name = try self.allocator.dupe(u8, lib); |
| | 440 | archive.file = file; |
| | 441 | try archive.parse(); |
| | 442 | try self.archives.append(self.allocator, archive); |
| | 443 | } else { |
| | 444 | file.close(); |
| | 445 | log.warn("unknown filetype for a library: '{s}'", .{lib}); |
| | 446 | } |
| | 447 | } |
| | 448 | } |
| 402 | } | 449 | } |
| 403 | return false; | | |
| 404 | } | 450 | } |
| 405 | | 451 | |
| 406 | fn parseLibSystem(self: *Zld, lib_system_path: []const u8) !void { | 452 | fn parseLibSystem(self: *Zld, lib_system_path: []const u8) !void { |
| ... | @@ -418,73 +464,7 @@ fn parseLibSystem(self: *Zld, lib_system_path: []const u8) !void { | ... | @@ -418,73 +464,7 @@ fn parseLibSystem(self: *Zld, lib_system_path: []const u8) !void { |
| 418 | dylib.file = file; | 464 | dylib.file = file; |
| 419 | dylib.ordinal = @intCast(u16, self.dylibs.items.len) + 1; | 465 | dylib.ordinal = @intCast(u16, self.dylibs.items.len) + 1; |
| 420 | | 466 | |
| 421 | const umbrella_lib = lib_stub.inner[0]; | 467 | try dylib.parseFromStub(lib_stub); |
| 422 | dylib.id = .{ | | |
| 423 | .name = try self.allocator.dupe(u8, umbrella_lib.install_name), | | |
| 424 | // TODO parse from the stub | | |
| 425 | .timestamp = 2, | | |
| 426 | .current_version = 0, | | |
| 427 | .compatibility_version = 0, | | |
| 428 | }; | | |
| 429 | | | |
| 430 | const target_string: []const u8 = switch (self.arch.?) { | | |
| 431 | .aarch64 => "arm64-macos", | | |
| 432 | .x86_64 => "x86_64-macos", | | |
| 433 | else => unreachable, | | |
| 434 | }; | | |
| 435 | | | |
| 436 | for (lib_stub.inner) |stub| { | | |
| 437 | if (!hasTarget(stub.targets, target_string)) continue; | | |
| 438 | | | |
| 439 | if (stub.exports) |exports| { | | |
| 440 | for (exports) |exp| { | | |
| 441 | if (!hasTarget(exp.targets, target_string)) continue; | | |
| 442 | | | |
| 443 | for (exp.symbols) |sym_name| { | | |
| 444 | if (dylib.symbols.contains(sym_name)) continue; | | |
| 445 | | | |
| 446 | const name = try self.allocator.dupe(u8, sym_name); | | |
| 447 | const proxy = try self.allocator.create(Symbol.Proxy); | | |
| 448 | errdefer self.allocator.destroy(proxy); | | |
| 449 | | | |
| 450 | proxy.* = .{ | | |
| 451 | .base = .{ | | |
| 452 | .@"type" = .proxy, | | |
| 453 | .name = name, | | |
| 454 | }, | | |
| 455 | .dylib = dylib, | | |
| 456 | }; | | |
| 457 | | | |
| 458 | try dylib.symbols.putNoClobber(self.allocator, name, &proxy.base); | | |
| 459 | } | | |
| 460 | } | | |
| 461 | } | | |
| 462 | | | |
| 463 | if (stub.reexports) |reexports| { | | |
| 464 | for (reexports) |reexp| { | | |
| 465 | if (!hasTarget(reexp.targets, target_string)) continue; | | |
| 466 | | | |
| 467 | for (reexp.symbols) |sym_name| { | | |
| 468 | if (dylib.symbols.contains(sym_name)) continue; | | |
| 469 | | | |
| 470 | const name = try self.allocator.dupe(u8, sym_name); | | |
| 471 | const proxy = try self.allocator.create(Symbol.Proxy); | | |
| 472 | errdefer self.allocator.destroy(proxy); | | |
| 473 | | | |
| 474 | proxy.* = .{ | | |
| 475 | .base = .{ | | |
| 476 | .@"type" = .proxy, | | |
| 477 | .name = name, | | |
| 478 | }, | | |
| 479 | .dylib = dylib, | | |
| 480 | }; | | |
| 481 | | | |
| 482 | try dylib.symbols.putNoClobber(self.allocator, name, &proxy.base); | | |
| 483 | } | | |
| 484 | } | | |
| 485 | } | | |
| 486 | } | | |
| 487 | | | |
| 488 | try self.dylibs.append(self.allocator, dylib); | 468 | try self.dylibs.append(self.allocator, dylib); |
| 489 | | 469 | |
| 490 | // Add LC_LOAD_DYLIB command | 470 | // Add LC_LOAD_DYLIB command |