| ... | ... | @@ -243,14 +243,16 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { |
| 243 | 243 | object, |
| 244 | 244 | archive, |
| 245 | 245 | dylib, |
| 246 | stub, |
| 246 | 247 | }, |
| 247 | 248 | file: fs.File, |
| 248 | 249 | name: []const u8, |
| 250 | stub: ?LibStub = null, |
| 249 | 251 | }; |
| 250 | 252 | var classified = std.ArrayList(Input).init(self.allocator); |
| 251 | 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 | 256 | for (files) |file_name| { |
| 255 | 257 | const file = try fs.cwd().openFile(file_name, .{}); |
| 256 | 258 | const full_path = full_path: { |
| ... | ... | @@ -260,7 +262,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { |
| 260 | 262 | }; |
| 261 | 263 | |
| 262 | 264 | try_object: { |
| 263 | | if (!(try Object.isObject(file))) break :try_object; |
| 265 | if (!Object.isObject(file)) break :try_object; |
| 264 | 266 | try classified.append(.{ |
| 265 | 267 | .kind = .object, |
| 266 | 268 | .file = file, |
| ... | ... | @@ -270,7 +272,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { |
| 270 | 272 | } |
| 271 | 273 | |
| 272 | 274 | try_archive: { |
| 273 | | if (!(try Archive.isArchive(file))) break :try_archive; |
| 275 | if (!Archive.isArchive(file)) break :try_archive; |
| 274 | 276 | try classified.append(.{ |
| 275 | 277 | .kind = .archive, |
| 276 | 278 | .file = file, |
| ... | ... | @@ -280,7 +282,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { |
| 280 | 282 | } |
| 281 | 283 | |
| 282 | 284 | try_dylib: { |
| 283 | | if (!(try Dylib.isDylib(file))) break :try_dylib; |
| 285 | if (!Dylib.isDylib(file)) break :try_dylib; |
| 284 | 286 | try classified.append(.{ |
| 285 | 287 | .kind = .dylib, |
| 286 | 288 | .file = file, |
| ... | ... | @@ -289,6 +291,19 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { |
| 289 | 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 | 307 | file.close(); |
| 293 | 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 | 333 | try archive.parse(); |
| 319 | 334 | try self.archives.append(self.allocator, archive); |
| 320 | 335 | }, |
| 321 | | .dylib => { |
| 336 | .dylib, .stub => { |
| 322 | 337 | const dylib = try self.allocator.create(Dylib); |
| 323 | 338 | errdefer self.allocator.destroy(dylib); |
| 324 | 339 | |
| ... | ... | @@ -329,7 +344,11 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { |
| 329 | 344 | dylib.ordinal = @intCast(u16, self.dylibs.items.len) + 1; |
| 330 | 345 | |
| 331 | 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 | 352 | try self.dylibs.append(self.allocator, dylib); |
| 334 | 353 | |
| 335 | 354 | // Add LC_LOAD_DYLIB command |
| ... | ... | @@ -353,7 +372,7 @@ fn parseLibs(self: *Zld, libs: []const []const u8) !void { |
| 353 | 372 | for (libs) |lib| { |
| 354 | 373 | const file = try fs.cwd().openFile(lib, .{}); |
| 355 | 374 | |
| 356 | | if (try Dylib.isDylib(file)) { |
| 375 | if (Dylib.isDylib(file)) { |
| 357 | 376 | const dylib = try self.allocator.create(Dylib); |
| 358 | 377 | errdefer self.allocator.destroy(dylib); |
| 359 | 378 | |
| ... | ... | @@ -379,28 +398,55 @@ fn parseLibs(self: *Zld, libs: []const []const u8) !void { |
| 379 | 398 | errdefer dylib_cmd.deinit(self.allocator); |
| 380 | 399 | |
| 381 | 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 | 401 | } else { |
| 393 | | file.close(); |
| 394 | | log.warn("unknown filetype for a library: '{s}'", .{lib}); |
| 395 | | } |
| 396 | | } |
| 397 | | } |
| 402 | // Try tbd stub file next. |
| 403 | if (LibStub.loadFromFile(self.allocator, file)) |*lib_stub| { |
| 404 | defer lib_stub.deinit(); |
| 405 | |
| 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 { |
| 400 | | for (targets) |t| { |
| 401 | | if (mem.eql(u8, t, target)) return true; |
| 429 | try self.load_commands.append(self.allocator, .{ .Dylib = dylib_cmd }); |
| 430 | } else |_| { |
| 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 | 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 | 464 | dylib.file = file; |
| 419 | 465 | dylib.ordinal = @intCast(u16, self.dylibs.items.len) + 1; |
| 420 | 466 | |
| 421 | | const umbrella_lib = lib_stub.inner[0]; |
| 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 | | |
| 467 | try dylib.parseFromStub(lib_stub); |
| 488 | 468 | try self.dylibs.append(self.allocator, dylib); |
| 489 | 469 | |
| 490 | 470 | // Add LC_LOAD_DYLIB command |