| ... | ... | @@ -70,10 +70,10 @@ d_sym: ?DebugSymbols = null, |
| 70 | 70 | /// For x86_64 that's 4KB, whereas for aarch64, that's 16KB. |
| 71 | 71 | page_size: u16, |
| 72 | 72 | |
| 73 | | /// If true, the linker will preallocate several sections and segments before starting the linking |
| 74 | | /// process. This is for example true for stage2 debug builds, however, this is false for stage1 |
| 75 | | /// and potentially stage2 release builds in the future. |
| 76 | | needs_prealloc: bool = true, |
| 73 | /// Mode of operation: incremental - will preallocate segments/sections and is compatible with |
| 74 | /// watch and HCS modes of operation; one_shot - will link relocatables in a traditional, one-shot |
| 75 | /// fashion (default for LLVM backend). |
| 76 | mode: enum { incremental, one_shot }, |
| 77 | 77 | |
| 78 | 78 | /// The absolute address of the entry point. |
| 79 | 79 | entry_addr: ?u64 = null, |
| ... | ... | @@ -153,7 +153,7 @@ rustc_section_size: u64 = 0, |
| 153 | 153 | |
| 154 | 154 | locals: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 155 | 155 | globals: std.StringArrayHashMapUnmanaged(SymbolWithLoc) = .{}, |
| 156 | | unresolved: std.AutoArrayHashMapUnmanaged(u32, void) = .{}, |
| 156 | unresolved: std.AutoArrayHashMapUnmanaged(u32, bool) = .{}, |
| 157 | 157 | |
| 158 | 158 | locals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 159 | 159 | |
| ... | ... | @@ -161,7 +161,7 @@ dyld_stub_binder_index: ?u32 = null, |
| 161 | 161 | dyld_private_atom: ?*Atom = null, |
| 162 | 162 | stub_helper_preamble_atom: ?*Atom = null, |
| 163 | 163 | |
| 164 | | strtab: StringTable(.link) = .{}, |
| 164 | strtab: StringTable(.strtab) = .{}, |
| 165 | 165 | |
| 166 | 166 | tlv_ptr_entries: std.ArrayListUnmanaged(Entry) = .{}, |
| 167 | 167 | tlv_ptr_entries_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| ... | ... | @@ -182,6 +182,12 @@ sections_order_dirty: bool = false, |
| 182 | 182 | has_dices: bool = false, |
| 183 | 183 | has_stabs: bool = false, |
| 184 | 184 | |
| 185 | /// A helper var to indicate if we are at the start of the incremental updates, or |
| 186 | /// already somewhere further along the update-and-run chain. |
| 187 | /// TODO once we add opening a prelinked output binary from file, this will become |
| 188 | /// obsolete as we will carry on where we left off. |
| 189 | cold_start: bool = true, |
| 190 | |
| 185 | 191 | section_ordinals: std.AutoArrayHashMapUnmanaged(MatchingSection, void) = .{}, |
| 186 | 192 | |
| 187 | 193 | /// A list of atoms that have surplus capacity. This list can have false |
| ... | ... | @@ -387,7 +393,6 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO { |
| 387 | 393 | const requires_adhoc_codesig = cpu_arch == .aarch64 and (os_tag == .macos or abi == .simulator); |
| 388 | 394 | const use_llvm = build_options.have_llvm and options.use_llvm; |
| 389 | 395 | const use_stage1 = build_options.is_stage1 and options.use_stage1; |
| 390 | | const needs_prealloc = !(use_stage1 or use_llvm or options.cache_mode == .whole); |
| 391 | 396 | |
| 392 | 397 | const self = try gpa.create(MachO); |
| 393 | 398 | errdefer gpa.destroy(self); |
| ... | ... | @@ -400,8 +405,14 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO { |
| 400 | 405 | .file = null, |
| 401 | 406 | }, |
| 402 | 407 | .page_size = page_size, |
| 403 | | .code_signature = if (requires_adhoc_codesig) CodeSignature.init(page_size) else null, |
| 404 | | .needs_prealloc = needs_prealloc, |
| 408 | .code_signature = if (requires_adhoc_codesig) |
| 409 | CodeSignature.init(page_size) |
| 410 | else |
| 411 | null, |
| 412 | .mode = if (use_stage1 or use_llvm or options.cache_mode == .whole) |
| 413 | .one_shot |
| 414 | else |
| 415 | .incremental, |
| 405 | 416 | }; |
| 406 | 417 | |
| 407 | 418 | if (use_llvm and !use_stage1) { |
| ... | ... | @@ -429,32 +440,198 @@ pub fn flush(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) !v |
| 429 | 440 | return error.TODOImplementWritingStaticLibFiles; |
| 430 | 441 | } |
| 431 | 442 | } |
| 432 | | return self.flushModule(comp, prog_node); |
| 443 | |
| 444 | switch (self.mode) { |
| 445 | .one_shot => return self.linkOneShot(comp, prog_node), |
| 446 | .incremental => return self.flushModule(comp, prog_node), |
| 447 | } |
| 433 | 448 | } |
| 434 | 449 | |
| 435 | 450 | pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) !void { |
| 436 | 451 | const tracy = trace(@src()); |
| 437 | 452 | defer tracy.end(); |
| 438 | 453 | |
| 439 | | const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1; |
| 440 | | |
| 441 | | if (build_options.have_llvm and !use_stage1) { |
| 454 | if (build_options.have_llvm) { |
| 442 | 455 | if (self.llvm_object) |llvm_object| { |
| 443 | | try llvm_object.flushModule(comp, prog_node); |
| 444 | | |
| 445 | | llvm_object.destroy(self.base.allocator); |
| 446 | | self.llvm_object = null; |
| 447 | | |
| 448 | | if (self.base.options.output_mode == .Lib and self.base.options.link_mode == .Static) { |
| 449 | | return; |
| 450 | | } |
| 456 | return try llvm_object.flushModule(comp, prog_node); |
| 451 | 457 | } |
| 452 | 458 | } |
| 453 | 459 | |
| 460 | var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator); |
| 461 | defer arena_allocator.deinit(); |
| 462 | const arena = arena_allocator.allocator(); |
| 463 | |
| 454 | 464 | var sub_prog_node = prog_node.start("MachO Flush", 0); |
| 455 | 465 | sub_prog_node.activate(); |
| 456 | 466 | defer sub_prog_node.end(); |
| 457 | 467 | |
| 468 | const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; |
| 469 | |
| 470 | if (self.d_sym) |*d_sym| { |
| 471 | try d_sym.dwarf.flushModule(&self.base, module); |
| 472 | } |
| 473 | |
| 474 | var libs = std.StringArrayHashMap(SystemLib).init(arena); |
| 475 | try self.resolveLibSystem(arena, comp, &.{}, &libs); |
| 476 | |
| 477 | const id_symlink_basename = "zld.id"; |
| 478 | |
| 479 | const cache_dir_handle = module.zig_cache_artifact_directory.handle; |
| 480 | var man: Cache.Manifest = undefined; |
| 481 | defer if (!self.base.options.disable_lld_caching) man.deinit(); |
| 482 | |
| 483 | var digest: [Cache.hex_digest_len]u8 = undefined; |
| 484 | var cache_miss: bool = self.cold_start; |
| 485 | |
| 486 | if (!self.base.options.disable_lld_caching) { |
| 487 | man = comp.cache_parent.obtain(); |
| 488 | self.base.releaseLock(); |
| 489 | |
| 490 | man.hash.addListOfBytes(libs.keys()); |
| 491 | |
| 492 | _ = try man.hit(); |
| 493 | digest = man.final(); |
| 494 | |
| 495 | var prev_digest_buf: [digest.len]u8 = undefined; |
| 496 | const prev_digest: []u8 = Cache.readSmallFile( |
| 497 | cache_dir_handle, |
| 498 | id_symlink_basename, |
| 499 | &prev_digest_buf, |
| 500 | ) catch |err| blk: { |
| 501 | log.debug("MachO Zld new_digest={s} error: {s}", .{ |
| 502 | std.fmt.fmtSliceHexLower(&digest), |
| 503 | @errorName(err), |
| 504 | }); |
| 505 | // Handle this as a cache miss. |
| 506 | break :blk prev_digest_buf[0..0]; |
| 507 | }; |
| 508 | if (mem.eql(u8, prev_digest, &digest)) { |
| 509 | log.debug("MachO Zld digest={s} match - skipping parsing linker line objects", .{ |
| 510 | std.fmt.fmtSliceHexLower(&digest), |
| 511 | }); |
| 512 | self.base.lock = man.toOwnedLock(); |
| 513 | } else { |
| 514 | log.debug("MachO Zld prev_digest={s} new_digest={s}", .{ |
| 515 | std.fmt.fmtSliceHexLower(prev_digest), |
| 516 | std.fmt.fmtSliceHexLower(&digest), |
| 517 | }); |
| 518 | // We are about to change the output file to be different, so we invalidate the build hash now. |
| 519 | cache_dir_handle.deleteFile(id_symlink_basename) catch |err| switch (err) { |
| 520 | error.FileNotFound => {}, |
| 521 | else => |e| return e, |
| 522 | }; |
| 523 | cache_miss = true; |
| 524 | } |
| 525 | } |
| 526 | |
| 527 | if (cache_miss) { |
| 528 | var dependent_libs = std.fifo.LinearFifo(struct { |
| 529 | id: Dylib.Id, |
| 530 | parent: u16, |
| 531 | }, .Dynamic).init(self.base.allocator); |
| 532 | defer dependent_libs.deinit(); |
| 533 | try self.parseLibs(libs.keys(), libs.values(), self.base.options.sysroot, &dependent_libs); |
| 534 | try self.parseDependentLibs(self.base.options.sysroot, &dependent_libs); |
| 535 | } |
| 536 | |
| 537 | try self.createMhExecuteHeaderSymbol(); |
| 538 | try self.resolveDyldStubBinder(); |
| 539 | try self.createDyldPrivateAtom(); |
| 540 | try self.createStubHelperPreambleAtom(); |
| 541 | try self.resolveSymbolsInDylibs(); |
| 542 | try self.addCodeSignatureLC(); |
| 543 | |
| 544 | if (self.unresolved.count() > 0) { |
| 545 | return error.UndefinedSymbolReference; |
| 546 | } |
| 547 | |
| 548 | try self.allocateSpecialSymbols(); |
| 549 | |
| 550 | if (build_options.enable_logging) { |
| 551 | self.logSymtab(); |
| 552 | self.logSectionOrdinals(); |
| 553 | self.logAtoms(); |
| 554 | } |
| 555 | |
| 556 | try self.writeAtomsIncremental(); |
| 557 | |
| 558 | try self.setEntryPoint(); |
| 559 | try self.updateSectionOrdinals(); |
| 560 | try self.writeLinkeditSegment(); |
| 561 | |
| 562 | if (self.d_sym) |*d_sym| { |
| 563 | // Flush debug symbols bundle. |
| 564 | try d_sym.flushModule(self.base.allocator, self.base.options); |
| 565 | } |
| 566 | |
| 567 | // code signature and entitlements |
| 568 | if (self.base.options.entitlements) |path| { |
| 569 | if (self.code_signature) |*csig| { |
| 570 | try csig.addEntitlements(self.base.allocator, path); |
| 571 | csig.code_directory.ident = self.base.options.emit.?.sub_path; |
| 572 | } else { |
| 573 | var csig = CodeSignature.init(self.page_size); |
| 574 | try csig.addEntitlements(self.base.allocator, path); |
| 575 | csig.code_directory.ident = self.base.options.emit.?.sub_path; |
| 576 | self.code_signature = csig; |
| 577 | } |
| 578 | } |
| 579 | |
| 580 | if (self.code_signature) |*csig| { |
| 581 | csig.clear(self.base.allocator); |
| 582 | csig.code_directory.ident = self.base.options.emit.?.sub_path; |
| 583 | // Preallocate space for the code signature. |
| 584 | // We need to do this at this stage so that we have the load commands with proper values |
| 585 | // written out to the file. |
| 586 | // The most important here is to have the correct vm and filesize of the __LINKEDIT segment |
| 587 | // where the code signature goes into. |
| 588 | try self.writeCodeSignaturePadding(csig); |
| 589 | } |
| 590 | |
| 591 | try self.writeLoadCommands(); |
| 592 | try self.writeHeader(); |
| 593 | |
| 594 | if (self.entry_addr == null and self.base.options.output_mode == .Exe) { |
| 595 | log.debug("flushing. no_entry_point_found = true", .{}); |
| 596 | self.error_flags.no_entry_point_found = true; |
| 597 | } else { |
| 598 | log.debug("flushing. no_entry_point_found = false", .{}); |
| 599 | self.error_flags.no_entry_point_found = false; |
| 600 | } |
| 601 | |
| 602 | assert(!self.load_commands_dirty); |
| 603 | |
| 604 | if (self.code_signature) |*csig| { |
| 605 | try self.writeCodeSignature(csig); // code signing always comes last |
| 606 | } |
| 607 | |
| 608 | if (build_options.enable_link_snapshots) { |
| 609 | if (self.base.options.enable_link_snapshots) |
| 610 | try self.snapshotState(); |
| 611 | } |
| 612 | |
| 613 | if (!self.base.options.disable_lld_caching and cache_miss) { |
| 614 | // Update the file with the digest. If it fails we can continue; it only |
| 615 | // means that the next invocation will have an unnecessary cache miss. |
| 616 | Cache.writeSmallFile(cache_dir_handle, id_symlink_basename, &digest) catch |err| { |
| 617 | log.debug("failed to save linking hash digest file: {s}", .{@errorName(err)}); |
| 618 | }; |
| 619 | // Again failure here only means an unnecessary cache miss. |
| 620 | man.writeManifest() catch |err| { |
| 621 | log.debug("failed to write cache manifest when linking: {s}", .{@errorName(err)}); |
| 622 | }; |
| 623 | // We hang on to this lock so that the output file path can be used without |
| 624 | // other processes clobbering it. |
| 625 | self.base.lock = man.toOwnedLock(); |
| 626 | } |
| 627 | |
| 628 | self.cold_start = false; |
| 629 | } |
| 630 | |
| 631 | fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) !void { |
| 632 | const tracy = trace(@src()); |
| 633 | defer tracy.end(); |
| 634 | |
| 458 | 635 | var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator); |
| 459 | 636 | defer arena_allocator.deinit(); |
| 460 | 637 | const arena = arena_allocator.allocator(); |
| ... | ... | @@ -465,7 +642,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 465 | 642 | // If there is no Zig code to compile, then we should skip flushing the output file because it |
| 466 | 643 | // will not be part of the linker line anyway. |
| 467 | 644 | const module_obj_path: ?[]const u8 = if (self.base.options.module) |module| blk: { |
| 468 | | if (use_stage1) { |
| 645 | if (self.base.options.use_stage1) { |
| 469 | 646 | const obj_basename = try std.zig.binNameAlloc(arena, .{ |
| 470 | 647 | .root_name = self.base.options.root_name, |
| 471 | 648 | .target = self.base.options.target, |
| ... | ... | @@ -482,20 +659,19 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 482 | 659 | } |
| 483 | 660 | } |
| 484 | 661 | |
| 485 | | const obj_basename = self.base.intermediary_basename orelse break :blk null; |
| 662 | try self.flushModule(comp, prog_node); |
| 486 | 663 | |
| 487 | 664 | if (fs.path.dirname(full_out_path)) |dirname| { |
| 488 | | break :blk try fs.path.join(arena, &.{ dirname, obj_basename }); |
| 665 | break :blk try fs.path.join(arena, &.{ dirname, self.base.intermediary_basename.? }); |
| 489 | 666 | } else { |
| 490 | | break :blk obj_basename; |
| 667 | break :blk self.base.intermediary_basename.?; |
| 491 | 668 | } |
| 492 | 669 | } else null; |
| 493 | 670 | |
| 494 | | if (self.d_sym) |*d_sym| { |
| 495 | | if (self.base.options.module) |module| { |
| 496 | | try d_sym.dwarf.flushModule(&self.base, module); |
| 497 | | } |
| 498 | | } |
| 671 | var sub_prog_node = prog_node.start("MachO Flush", 0); |
| 672 | sub_prog_node.activate(); |
| 673 | sub_prog_node.context.refresh(); |
| 674 | defer sub_prog_node.end(); |
| 499 | 675 | |
| 500 | 676 | const is_lib = self.base.options.output_mode == .Lib; |
| 501 | 677 | const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib; |
| ... | ... | @@ -503,25 +679,13 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 503 | 679 | const stack_size = self.base.options.stack_size_override orelse 0; |
| 504 | 680 | |
| 505 | 681 | const id_symlink_basename = "zld.id"; |
| 506 | | const cache_dir_handle = blk: { |
| 507 | | if (use_stage1) { |
| 508 | | break :blk directory.handle; |
| 509 | | } |
| 510 | | if (self.base.options.module) |module| { |
| 511 | | break :blk module.zig_cache_artifact_directory.handle; |
| 512 | | } |
| 513 | | break :blk directory.handle; |
| 514 | | }; |
| 515 | 682 | |
| 516 | 683 | var man: Cache.Manifest = undefined; |
| 517 | 684 | defer if (!self.base.options.disable_lld_caching) man.deinit(); |
| 518 | 685 | |
| 519 | 686 | var digest: [Cache.hex_digest_len]u8 = undefined; |
| 520 | 687 | |
| 521 | | cache: { |
| 522 | | if ((use_stage1 and self.base.options.disable_lld_caching) or self.base.options.cache_mode == .whole) |
| 523 | | break :cache; |
| 524 | | |
| 688 | if (!self.base.options.disable_lld_caching) { |
| 525 | 689 | man = comp.cache_parent.obtain(); |
| 526 | 690 | |
| 527 | 691 | // We are about to obtain this lock, so here we give other processes a chance first. |
| ... | ... | @@ -564,7 +728,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 564 | 728 | |
| 565 | 729 | var prev_digest_buf: [digest.len]u8 = undefined; |
| 566 | 730 | const prev_digest: []u8 = Cache.readSmallFile( |
| 567 | | cache_dir_handle, |
| 731 | directory.handle, |
| 568 | 732 | id_symlink_basename, |
| 569 | 733 | &prev_digest_buf, |
| 570 | 734 | ) catch |err| blk: { |
| ... | ... | @@ -577,15 +741,11 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 577 | 741 | }; |
| 578 | 742 | if (mem.eql(u8, prev_digest, &digest)) { |
| 579 | 743 | // Hot diggity dog! The output binary is already there. |
| 580 | | |
| 581 | | const use_llvm = build_options.have_llvm and self.base.options.use_llvm; |
| 582 | | if (use_llvm or use_stage1) { |
| 583 | | log.debug("MachO Zld digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)}); |
| 584 | | self.base.lock = man.toOwnedLock(); |
| 585 | | return; |
| 586 | | } else { |
| 587 | | log.debug("MachO Zld digest={s} match", .{std.fmt.fmtSliceHexLower(&digest)}); |
| 588 | | } |
| 744 | log.debug("MachO Zld digest={s} match - skipping invocation", .{ |
| 745 | std.fmt.fmtSliceHexLower(&digest), |
| 746 | }); |
| 747 | self.base.lock = man.toOwnedLock(); |
| 748 | return; |
| 589 | 749 | } |
| 590 | 750 | log.debug("MachO Zld prev_digest={s} new_digest={s}", .{ |
| 591 | 751 | std.fmt.fmtSliceHexLower(prev_digest), |
| ... | ... | @@ -593,7 +753,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 593 | 753 | }); |
| 594 | 754 | |
| 595 | 755 | // We are about to change the output file to be different, so we invalidate the build hash now. |
| 596 | | cache_dir_handle.deleteFile(id_symlink_basename) catch |err| switch (err) { |
| 756 | directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) { |
| 597 | 757 | error.FileNotFound => {}, |
| 598 | 758 | else => |e| return e, |
| 599 | 759 | }; |
| ... | ... | @@ -624,24 +784,22 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 624 | 784 | try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{}); |
| 625 | 785 | } |
| 626 | 786 | } else { |
| 627 | | if (use_stage1) { |
| 628 | | const sub_path = self.base.options.emit.?.sub_path; |
| 629 | | self.base.file = try cache_dir_handle.createFile(sub_path, .{ |
| 630 | | .truncate = true, |
| 631 | | .read = true, |
| 632 | | .mode = link.determineMode(self.base.options), |
| 633 | | }); |
| 634 | | // Index 0 is always a null symbol. |
| 635 | | try self.locals.append(self.base.allocator, .{ |
| 636 | | .n_strx = 0, |
| 637 | | .n_type = 0, |
| 638 | | .n_sect = 0, |
| 639 | | .n_desc = 0, |
| 640 | | .n_value = 0, |
| 641 | | }); |
| 642 | | try self.strtab.buffer.append(self.base.allocator, 0); |
| 643 | | try self.populateMissingMetadata(); |
| 644 | | } |
| 787 | const sub_path = self.base.options.emit.?.sub_path; |
| 788 | self.base.file = try directory.handle.createFile(sub_path, .{ |
| 789 | .truncate = true, |
| 790 | .read = true, |
| 791 | .mode = link.determineMode(self.base.options), |
| 792 | }); |
| 793 | // Index 0 is always a null symbol. |
| 794 | try self.locals.append(self.base.allocator, .{ |
| 795 | .n_strx = 0, |
| 796 | .n_type = 0, |
| 797 | .n_sect = 0, |
| 798 | .n_desc = 0, |
| 799 | .n_value = 0, |
| 800 | }); |
| 801 | try self.strtab.buffer.append(self.base.allocator, 0); |
| 802 | try self.populateMissingMetadata(); |
| 645 | 803 | |
| 646 | 804 | var lib_not_found = false; |
| 647 | 805 | var framework_not_found = false; |
| ... | ... | @@ -757,40 +915,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 757 | 915 | } |
| 758 | 916 | } |
| 759 | 917 | |
| 760 | | // If we were given the sysroot, try to look there first for libSystem.B.{dylib, tbd}. |
| 761 | | var libsystem_available = false; |
| 762 | | if (self.base.options.sysroot != null) blk: { |
| 763 | | // Try stub file first. If we hit it, then we're done as the stub file |
| 764 | | // re-exports every single symbol definition. |
| 765 | | for (lib_dirs.items) |dir| { |
| 766 | | if (try resolveLib(arena, dir, "System", ".tbd")) |full_path| { |
| 767 | | try libs.put(full_path, .{ .needed = true }); |
| 768 | | libsystem_available = true; |
| 769 | | break :blk; |
| 770 | | } |
| 771 | | } |
| 772 | | // If we didn't hit the stub file, try .dylib next. However, libSystem.dylib |
| 773 | | // doesn't export libc.dylib which we'll need to resolve subsequently also. |
| 774 | | for (lib_dirs.items) |dir| { |
| 775 | | if (try resolveLib(arena, dir, "System", ".dylib")) |libsystem_path| { |
| 776 | | if (try resolveLib(arena, dir, "c", ".dylib")) |libc_path| { |
| 777 | | try libs.put(libsystem_path, .{ .needed = true }); |
| 778 | | try libs.put(libc_path, .{ .needed = true }); |
| 779 | | libsystem_available = true; |
| 780 | | break :blk; |
| 781 | | } |
| 782 | | } |
| 783 | | } |
| 784 | | } |
| 785 | | if (!libsystem_available) { |
| 786 | | const libsystem_name = try std.fmt.allocPrint(arena, "libSystem.{d}.tbd", .{ |
| 787 | | self.base.options.target.os.version_range.semver.min.major, |
| 788 | | }); |
| 789 | | const full_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ |
| 790 | | "libc", "darwin", libsystem_name, |
| 791 | | }); |
| 792 | | try libs.put(full_path, .{ .needed = true }); |
| 793 | | } |
| 918 | try self.resolveLibSystem(arena, comp, lib_dirs.items, &libs); |
| 794 | 919 | |
| 795 | 920 | // frameworks |
| 796 | 921 | var framework_dirs = std.ArrayList([]const u8).init(arena); |
| ... | ... | @@ -1003,7 +1128,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 1003 | 1128 | try self.parseLibs(libs.keys(), libs.values(), self.base.options.sysroot, &dependent_libs); |
| 1004 | 1129 | try self.parseDependentLibs(self.base.options.sysroot, &dependent_libs); |
| 1005 | 1130 | |
| 1006 | | try self.createMhExecuteHeaderSymbol(); |
| 1007 | 1131 | for (self.objects.items) |*object, object_id| { |
| 1008 | 1132 | try self.resolveSymbolsInObject(object, @intCast(u16, object_id)); |
| 1009 | 1133 | } |
| ... | ... | @@ -1013,6 +1137,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 1013 | 1137 | try self.createDyldPrivateAtom(); |
| 1014 | 1138 | try self.createStubHelperPreambleAtom(); |
| 1015 | 1139 | try self.resolveSymbolsInDylibs(); |
| 1140 | try self.createMhExecuteHeaderSymbol(); |
| 1016 | 1141 | try self.createDsoHandleSymbol(); |
| 1017 | 1142 | try self.addCodeSignatureLC(); |
| 1018 | 1143 | try self.resolveSymbolsAtLoading(); |
| ... | ... | @@ -1029,20 +1154,15 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 1029 | 1154 | |
| 1030 | 1155 | try self.createTentativeDefAtoms(); |
| 1031 | 1156 | |
| 1032 | | const use_llvm = build_options.have_llvm and self.base.options.use_llvm; |
| 1033 | | if (use_llvm or use_stage1) { |
| 1034 | | for (self.objects.items) |*object, object_id| { |
| 1035 | | try object.splitIntoAtomsWhole(self, @intCast(u32, object_id)); |
| 1036 | | } |
| 1037 | | |
| 1038 | | try self.gcAtoms(); |
| 1039 | | try self.pruneAndSortSections(); |
| 1040 | | try self.allocateSegments(); |
| 1041 | | try self.allocateSymbols(); |
| 1042 | | } else { |
| 1043 | | // TODO incremental mode: parsing objects into atoms |
| 1157 | for (self.objects.items) |*object, object_id| { |
| 1158 | try object.splitIntoAtomsOneShot(self, @intCast(u32, object_id)); |
| 1044 | 1159 | } |
| 1045 | 1160 | |
| 1161 | try self.gcAtoms(); |
| 1162 | try self.pruneAndSortSections(); |
| 1163 | try self.allocateSegments(); |
| 1164 | try self.allocateSymbols(); |
| 1165 | |
| 1046 | 1166 | try self.allocateSpecialSymbols(); |
| 1047 | 1167 | |
| 1048 | 1168 | if (build_options.enable_logging) { |
| ... | ... | @@ -1051,11 +1171,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 1051 | 1171 | self.logAtoms(); |
| 1052 | 1172 | } |
| 1053 | 1173 | |
| 1054 | | if (use_llvm or use_stage1) { |
| 1055 | | try self.writeAtomsWhole(); |
| 1056 | | } else { |
| 1057 | | // try self.writeAtoms(); |
| 1058 | | } |
| 1174 | try self.writeAtomsOneShot(); |
| 1059 | 1175 | |
| 1060 | 1176 | if (self.rustc_section_index) |id| { |
| 1061 | 1177 | const sect = self.getSectionPtr(.{ |
| ... | ... | @@ -1066,14 +1182,8 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 1066 | 1182 | } |
| 1067 | 1183 | |
| 1068 | 1184 | try self.setEntryPoint(); |
| 1069 | | try self.updateSectionOrdinals(); |
| 1070 | 1185 | try self.writeLinkeditSegment(); |
| 1071 | 1186 | |
| 1072 | | if (self.d_sym) |*d_sym| { |
| 1073 | | // Flush debug symbols bundle. |
| 1074 | | try d_sym.flushModule(self.base.allocator, self.base.options); |
| 1075 | | } |
| 1076 | | |
| 1077 | 1187 | if (self.code_signature) |*csig| { |
| 1078 | 1188 | csig.clear(self.base.allocator); |
| 1079 | 1189 | csig.code_directory.ident = self.base.options.emit.?.sub_path; |
| ... | ... | @@ -1088,32 +1198,17 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 1088 | 1198 | try self.writeLoadCommands(); |
| 1089 | 1199 | try self.writeHeader(); |
| 1090 | 1200 | |
| 1091 | | if (self.entry_addr == null and self.base.options.output_mode == .Exe) { |
| 1092 | | log.debug("flushing. no_entry_point_found = true", .{}); |
| 1093 | | self.error_flags.no_entry_point_found = true; |
| 1094 | | } else { |
| 1095 | | log.debug("flushing. no_entry_point_found = false", .{}); |
| 1096 | | self.error_flags.no_entry_point_found = false; |
| 1097 | | } |
| 1098 | | |
| 1099 | 1201 | assert(!self.load_commands_dirty); |
| 1100 | 1202 | |
| 1101 | 1203 | if (self.code_signature) |*csig| { |
| 1102 | 1204 | try self.writeCodeSignature(csig); // code signing always comes last |
| 1103 | 1205 | } |
| 1104 | | |
| 1105 | | // if (build_options.enable_link_snapshots) { |
| 1106 | | // if (self.base.options.enable_link_snapshots) |
| 1107 | | // try self.snapshotState(); |
| 1108 | | // } |
| 1109 | 1206 | } |
| 1110 | 1207 | |
| 1111 | | cache: { |
| 1112 | | if ((use_stage1 and self.base.options.disable_lld_caching) or self.base.options.cache_mode == .whole) |
| 1113 | | break :cache; |
| 1208 | if (!self.base.options.disable_lld_caching) { |
| 1114 | 1209 | // Update the file with the digest. If it fails we can continue; it only |
| 1115 | 1210 | // means that the next invocation will have an unnecessary cache miss. |
| 1116 | | Cache.writeSmallFile(cache_dir_handle, id_symlink_basename, &digest) catch |err| { |
| 1211 | Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| { |
| 1117 | 1212 | log.debug("failed to save linking hash digest file: {s}", .{@errorName(err)}); |
| 1118 | 1213 | }; |
| 1119 | 1214 | // Again failure here only means an unnecessary cache miss. |
| ... | ... | @@ -1126,6 +1221,49 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 1126 | 1221 | } |
| 1127 | 1222 | } |
| 1128 | 1223 | |
| 1224 | fn resolveLibSystem( |
| 1225 | self: *MachO, |
| 1226 | arena: Allocator, |
| 1227 | comp: *Compilation, |
| 1228 | search_dirs: []const []const u8, |
| 1229 | out_libs: anytype, |
| 1230 | ) !void { |
| 1231 | // If we were given the sysroot, try to look there first for libSystem.B.{dylib, tbd}. |
| 1232 | var libsystem_available = false; |
| 1233 | if (self.base.options.sysroot != null) blk: { |
| 1234 | // Try stub file first. If we hit it, then we're done as the stub file |
| 1235 | // re-exports every single symbol definition. |
| 1236 | for (search_dirs) |dir| { |
| 1237 | if (try resolveLib(arena, dir, "System", ".tbd")) |full_path| { |
| 1238 | try out_libs.put(full_path, .{ .needed = true }); |
| 1239 | libsystem_available = true; |
| 1240 | break :blk; |
| 1241 | } |
| 1242 | } |
| 1243 | // If we didn't hit the stub file, try .dylib next. However, libSystem.dylib |
| 1244 | // doesn't export libc.dylib which we'll need to resolve subsequently also. |
| 1245 | for (search_dirs) |dir| { |
| 1246 | if (try resolveLib(arena, dir, "System", ".dylib")) |libsystem_path| { |
| 1247 | if (try resolveLib(arena, dir, "c", ".dylib")) |libc_path| { |
| 1248 | try out_libs.put(libsystem_path, .{ .needed = true }); |
| 1249 | try out_libs.put(libc_path, .{ .needed = true }); |
| 1250 | libsystem_available = true; |
| 1251 | break :blk; |
| 1252 | } |
| 1253 | } |
| 1254 | } |
| 1255 | } |
| 1256 | if (!libsystem_available) { |
| 1257 | const libsystem_name = try std.fmt.allocPrint(arena, "libSystem.{d}.tbd", .{ |
| 1258 | self.base.options.target.os.version_range.semver.min.major, |
| 1259 | }); |
| 1260 | const full_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ |
| 1261 | "libc", "darwin", libsystem_name, |
| 1262 | }); |
| 1263 | try out_libs.put(full_path, .{ .needed = true }); |
| 1264 | } |
| 1265 | } |
| 1266 | |
| 1129 | 1267 | fn resolveSearchDir( |
| 1130 | 1268 | arena: Allocator, |
| 1131 | 1269 | dir: []const u8, |
| ... | ... | @@ -1168,6 +1306,16 @@ fn resolveSearchDir( |
| 1168 | 1306 | return null; |
| 1169 | 1307 | } |
| 1170 | 1308 | |
| 1309 | fn resolveSearchDirs(arena: Allocator, dirs: []const []const u8, syslibroot: ?[]const u8, out_dirs: anytype) !void { |
| 1310 | for (dirs) |dir| { |
| 1311 | if (try resolveSearchDir(arena, dir, syslibroot)) |search_dir| { |
| 1312 | try out_dirs.append(search_dir); |
| 1313 | } else { |
| 1314 | log.warn("directory not found for '-L{s}'", .{dir}); |
| 1315 | } |
| 1316 | } |
| 1317 | } |
| 1318 | |
| 1171 | 1319 | fn resolveLib( |
| 1172 | 1320 | arena: Allocator, |
| 1173 | 1321 | search_dir: []const u8, |
| ... | ... | @@ -2128,6 +2276,7 @@ fn allocateSpecialSymbols(self: *MachO) !void { |
| 2128 | 2276 | "__mh_execute_header", |
| 2129 | 2277 | }) |name| { |
| 2130 | 2278 | const global = self.globals.get(name) orelse continue; |
| 2279 | if (global.file != null) continue; |
| 2131 | 2280 | const sym = self.getSymbolPtr(global); |
| 2132 | 2281 | const seg = self.load_commands.items[self.text_segment_cmd_index.?].segment; |
| 2133 | 2282 | sym.n_sect = self.getSectionOrdinal(.{ |
| ... | ... | @@ -2143,7 +2292,9 @@ fn allocateSpecialSymbols(self: *MachO) !void { |
| 2143 | 2292 | } |
| 2144 | 2293 | } |
| 2145 | 2294 | |
| 2146 | | fn writeAtomsWhole(self: *MachO) !void { |
| 2295 | fn writeAtomsOneShot(self: *MachO) !void { |
| 2296 | assert(self.mode == .one_shot); |
| 2297 | |
| 2147 | 2298 | var it = self.atoms.iterator(); |
| 2148 | 2299 | while (it.next()) |entry| { |
| 2149 | 2300 | const sect = self.getSection(entry.key_ptr.*); |
| ... | ... | @@ -2227,7 +2378,9 @@ fn writePadding(self: *MachO, match: MatchingSection, size: usize, writer: anyty |
| 2227 | 2378 | } |
| 2228 | 2379 | } |
| 2229 | 2380 | |
| 2230 | | fn writeAtoms(self: *MachO) !void { |
| 2381 | fn writeAtomsIncremental(self: *MachO) !void { |
| 2382 | assert(self.mode == .incremental); |
| 2383 | |
| 2231 | 2384 | var it = self.atoms.iterator(); |
| 2232 | 2385 | while (it.next()) |entry| { |
| 2233 | 2386 | const match = entry.key_ptr.*; |
| ... | ... | @@ -2240,7 +2393,7 @@ fn writeAtoms(self: *MachO) !void { |
| 2240 | 2393 | log.debug("writing atoms in {s},{s}", .{ sect.segName(), sect.sectName() }); |
| 2241 | 2394 | |
| 2242 | 2395 | while (true) { |
| 2243 | | if (atom.dirty or self.invalidate_relocs) { |
| 2396 | if (atom.dirty) { |
| 2244 | 2397 | try self.writeAtom(atom, match); |
| 2245 | 2398 | atom.dirty = false; |
| 2246 | 2399 | } |
| ... | ... | @@ -2746,11 +2899,13 @@ fn createTentativeDefAtoms(self: *MachO) !void { |
| 2746 | 2899 | |
| 2747 | 2900 | fn createMhExecuteHeaderSymbol(self: *MachO) !void { |
| 2748 | 2901 | if (self.base.options.output_mode != .Exe) return; |
| 2749 | | if (self.globals.contains("__mh_execute_header")) return; |
| 2902 | if (self.globals.get("__mh_execute_header")) |global| { |
| 2903 | const sym = self.getSymbol(global); |
| 2904 | if (!sym.undf() and !(sym.pext() or sym.weakDef())) return; |
| 2905 | } |
| 2750 | 2906 | |
| 2751 | 2907 | const gpa = self.base.allocator; |
| 2752 | | const name = try gpa.dupe(u8, "__mh_execute_header"); |
| 2753 | | const n_strx = try self.strtab.insert(gpa, name); |
| 2908 | const n_strx = try self.strtab.insert(gpa, "__mh_execute_header"); |
| 2754 | 2909 | const sym_index = @intCast(u32, self.locals.items.len); |
| 2755 | 2910 | try self.locals.append(gpa, .{ |
| 2756 | 2911 | .n_strx = n_strx, |
| ... | ... | @@ -2759,10 +2914,14 @@ fn createMhExecuteHeaderSymbol(self: *MachO) !void { |
| 2759 | 2914 | .n_desc = 0, |
| 2760 | 2915 | .n_value = 0, |
| 2761 | 2916 | }); |
| 2762 | | try self.globals.putNoClobber(gpa, name, .{ |
| 2917 | |
| 2918 | const name = try gpa.dupe(u8, "__mh_execute_header"); |
| 2919 | const gop = try self.globals.getOrPut(gpa, name); |
| 2920 | defer if (gop.found_existing) gpa.free(name); |
| 2921 | gop.value_ptr.* = .{ |
| 2763 | 2922 | .sym_index = sym_index, |
| 2764 | 2923 | .file = null, |
| 2765 | | }); |
| 2924 | }; |
| 2766 | 2925 | } |
| 2767 | 2926 | |
| 2768 | 2927 | fn createDsoHandleSymbol(self: *MachO) !void { |
| ... | ... | @@ -2787,9 +2946,68 @@ fn createDsoHandleSymbol(self: *MachO) !void { |
| 2787 | 2946 | _ = self.unresolved.swapRemove(@intCast(u32, self.globals.getIndex("___dso_handle").?)); |
| 2788 | 2947 | } |
| 2789 | 2948 | |
| 2790 | | fn resolveSymbolsInObject(self: *MachO, object: *Object, object_id: u16) !void { |
| 2949 | fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void { |
| 2791 | 2950 | const gpa = self.base.allocator; |
| 2951 | const sym = self.getSymbol(current); |
| 2952 | const sym_name = self.getSymbolName(current); |
| 2953 | |
| 2954 | const name = try gpa.dupe(u8, sym_name); |
| 2955 | const global_index = @intCast(u32, self.globals.values().len); |
| 2956 | const gop = try self.globals.getOrPut(gpa, name); |
| 2957 | defer if (gop.found_existing) gpa.free(name); |
| 2958 | |
| 2959 | if (!gop.found_existing) { |
| 2960 | gop.value_ptr.* = current; |
| 2961 | if (sym.undf() and !sym.tentative()) { |
| 2962 | try self.unresolved.putNoClobber(gpa, global_index, false); |
| 2963 | } |
| 2964 | return; |
| 2965 | } |
| 2792 | 2966 | |
| 2967 | const global = gop.value_ptr.*; |
| 2968 | const global_sym = self.getSymbol(global); |
| 2969 | |
| 2970 | // Cases to consider: sym vs global_sym |
| 2971 | // 1. strong(sym) and strong(global_sym) => error |
| 2972 | // 2. strong(sym) and weak(global_sym) => sym |
| 2973 | // 3. strong(sym) and tentative(global_sym) => sym |
| 2974 | // 4. strong(sym) and undf(global_sym) => sym |
| 2975 | // 5. weak(sym) and strong(global_sym) => global_sym |
| 2976 | // 6. weak(sym) and tentative(global_sym) => sym |
| 2977 | // 7. weak(sym) and undf(global_sym) => sym |
| 2978 | // 8. tentative(sym) and strong(global_sym) => global_sym |
| 2979 | // 9. tentative(sym) and weak(global_sym) => global_sym |
| 2980 | // 10. tentative(sym) and tentative(global_sym) => pick larger |
| 2981 | // 11. tentative(sym) and undf(global_sym) => sym |
| 2982 | // 12. undf(sym) and * => global_sym |
| 2983 | // |
| 2984 | // Reduces to: |
| 2985 | // 1. strong(sym) and strong(global_sym) => error |
| 2986 | // 2. * and strong(global_sym) => global_sym |
| 2987 | // 3. weak(sym) and weak(global_sym) => global_sym |
| 2988 | // 4. tentative(sym) and tentative(global_sym) => pick larger |
| 2989 | // 5. undf(sym) and * => global_sym |
| 2990 | // 6. else => sym |
| 2991 | |
| 2992 | const sym_is_strong = sym.sect() and !(sym.weakDef() or sym.pext()); |
| 2993 | const global_is_strong = global_sym.sect() and !(global_sym.weakDef() or global_sym.pext()); |
| 2994 | const sym_is_weak = sym.sect() and (sym.weakDef() or sym.pext()); |
| 2995 | const global_is_weak = global_sym.sect() and (global_sym.weakDef() or global_sym.pext()); |
| 2996 | |
| 2997 | if (sym_is_strong and global_is_strong) return error.MultipleSymbolDefinitions; |
| 2998 | if (global_is_strong) return; |
| 2999 | if (sym_is_weak and global_is_weak) return; |
| 3000 | if (sym.tentative() and global_sym.tentative()) { |
| 3001 | if (global_sym.n_value >= sym.n_value) return; |
| 3002 | } |
| 3003 | if (sym.undf() and !sym.tentative()) return; |
| 3004 | |
| 3005 | _ = self.unresolved.swapRemove(@intCast(u32, self.globals.getIndex(name).?)); |
| 3006 | |
| 3007 | gop.value_ptr.* = current; |
| 3008 | } |
| 3009 | |
| 3010 | fn resolveSymbolsInObject(self: *MachO, object: *Object, object_id: u16) !void { |
| 2793 | 3011 | log.debug("resolving symbols in '{s}'", .{object.name}); |
| 2794 | 3012 | |
| 2795 | 3013 | for (object.symtab.items) |sym, index| { |
| ... | ... | @@ -2825,72 +3043,18 @@ fn resolveSymbolsInObject(self: *MachO, object: *Object, object_id: u16) !void { |
| 2825 | 3043 | continue; |
| 2826 | 3044 | } |
| 2827 | 3045 | |
| 2828 | | const name = try gpa.dupe(u8, sym_name); |
| 2829 | | const global_index = @intCast(u32, self.globals.values().len); |
| 2830 | | const gop = try self.globals.getOrPut(gpa, name); |
| 2831 | | defer if (gop.found_existing) gpa.free(name); |
| 2832 | | |
| 2833 | | if (!gop.found_existing) { |
| 2834 | | gop.value_ptr.* = .{ |
| 2835 | | .sym_index = sym_index, |
| 2836 | | .file = object_id, |
| 2837 | | }; |
| 2838 | | if (sym.undf() and !sym.tentative()) { |
| 2839 | | try self.unresolved.putNoClobber(gpa, global_index, {}); |
| 2840 | | } |
| 2841 | | continue; |
| 2842 | | } |
| 2843 | | |
| 2844 | | const global = gop.value_ptr.*; |
| 2845 | | const global_sym = self.getSymbol(global); |
| 2846 | | |
| 2847 | | // Cases to consider: sym vs global_sym |
| 2848 | | // 1. strong(sym) and strong(global_sym) => error |
| 2849 | | // 2. strong(sym) and weak(global_sym) => sym |
| 2850 | | // 3. strong(sym) and tentative(global_sym) => sym |
| 2851 | | // 4. strong(sym) and undf(global_sym) => sym |
| 2852 | | // 5. weak(sym) and strong(global_sym) => global_sym |
| 2853 | | // 6. weak(sym) and tentative(global_sym) => sym |
| 2854 | | // 7. weak(sym) and undf(global_sym) => sym |
| 2855 | | // 8. tentative(sym) and strong(global_sym) => global_sym |
| 2856 | | // 9. tentative(sym) and weak(global_sym) => global_sym |
| 2857 | | // 10. tentative(sym) and tentative(global_sym) => pick larger |
| 2858 | | // 11. tentative(sym) and undf(global_sym) => sym |
| 2859 | | // 12. undf(sym) and * => global_sym |
| 2860 | | // |
| 2861 | | // Reduces to: |
| 2862 | | // 1. strong(sym) and strong(global_sym) => error |
| 2863 | | // 2. * and strong(global_sym) => global_sym |
| 2864 | | // 3. weak(sym) and weak(global_sym) => global_sym |
| 2865 | | // 4. tentative(sym) and tentative(global_sym) => pick larger |
| 2866 | | // 5. undf(sym) and * => global_sym |
| 2867 | | // 6. else => sym |
| 2868 | | |
| 2869 | | const sym_is_strong = sym.sect() and !(sym.weakDef() or sym.pext()); |
| 2870 | | const global_is_strong = global_sym.sect() and !(global_sym.weakDef() or global_sym.pext()); |
| 2871 | | const sym_is_weak = sym.sect() and (sym.weakDef() or sym.pext()); |
| 2872 | | const global_is_weak = global_sym.sect() and (global_sym.weakDef() or global_sym.pext()); |
| 2873 | | |
| 2874 | | if (sym_is_strong and global_is_strong) { |
| 2875 | | log.err("symbol '{s}' defined multiple times", .{sym_name}); |
| 2876 | | if (global.file) |file| { |
| 2877 | | log.err(" first definition in '{s}'", .{self.objects.items[file].name}); |
| 2878 | | } |
| 2879 | | log.err(" next definition in '{s}'", .{object.name}); |
| 2880 | | return error.MultipleSymbolDefinitions; |
| 2881 | | } |
| 2882 | | if (global_is_strong) continue; |
| 2883 | | if (sym_is_weak and global_is_weak) continue; |
| 2884 | | if (sym.tentative() and global_sym.tentative()) { |
| 2885 | | if (global_sym.n_value >= sym.n_value) continue; |
| 2886 | | } |
| 2887 | | if (sym.undf() and !sym.tentative()) continue; |
| 2888 | | |
| 2889 | | _ = self.unresolved.swapRemove(@intCast(u32, self.globals.getIndex(name).?)); |
| 2890 | | |
| 2891 | | gop.value_ptr.* = .{ |
| 2892 | | .sym_index = sym_index, |
| 2893 | | .file = object_id, |
| 3046 | const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = object_id }; |
| 3047 | self.resolveGlobalSymbol(sym_loc) catch |err| switch (err) { |
| 3048 | error.MultipleSymbolDefinitions => { |
| 3049 | const global = self.globals.get(sym_name).?; |
| 3050 | log.err("symbol '{s}' defined multiple times", .{sym_name}); |
| 3051 | if (global.file) |file| { |
| 3052 | log.err(" first definition in '{s}'", .{self.objects.items[file].name}); |
| 3053 | } |
| 3054 | log.err(" next definition in '{s}'", .{self.objects.items[object_id].name}); |
| 3055 | return error.MultipleSymbolDefinitions; |
| 3056 | }, |
| 3057 | else => |e| return e, |
| 2894 | 3058 | }; |
| 2895 | 3059 | } |
| 2896 | 3060 | } |
| ... | ... | @@ -2950,7 +3114,18 @@ fn resolveSymbolsInDylibs(self: *MachO) !void { |
| 2950 | 3114 | sym.n_desc |= macho.N_WEAK_REF; |
| 2951 | 3115 | } |
| 2952 | 3116 | |
| 2953 | | assert(self.unresolved.swapRemove(global_index)); |
| 3117 | if (self.unresolved.fetchSwapRemove(global_index)) |entry| blk: { |
| 3118 | if (!entry.value) break :blk; |
| 3119 | if (!sym.undf()) break :blk; |
| 3120 | if (self.stubs_table.contains(global)) break :blk; |
| 3121 | |
| 3122 | const stub_index = try self.allocateStubEntry(global); |
| 3123 | const stub_helper_atom = try self.createStubHelperAtom(); |
| 3124 | const laptr_atom = try self.createLazyPointerAtom(stub_helper_atom.sym_index, global); |
| 3125 | const stub_atom = try self.createStubAtom(laptr_atom.sym_index); |
| 3126 | |
| 3127 | self.stubs.items[stub_index].atom = stub_atom; |
| 3128 | } |
| 2954 | 3129 | |
| 2955 | 3130 | continue :loop; |
| 2956 | 3131 | } |
| ... | ... | @@ -3272,7 +3447,7 @@ fn growAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, match |
| 3272 | 3447 | return self.allocateAtom(atom, new_atom_size, alignment, match); |
| 3273 | 3448 | } |
| 3274 | 3449 | |
| 3275 | | fn allocateLocalSymbol(self: *MachO) !u32 { |
| 3450 | fn allocateSymbol(self: *MachO) !u32 { |
| 3276 | 3451 | try self.locals.ensureUnusedCapacity(self.base.allocator, 1); |
| 3277 | 3452 | |
| 3278 | 3453 | const index = blk: { |
| ... | ... | @@ -3366,12 +3541,9 @@ pub fn allocateDeclIndexes(self: *MachO, decl_index: Module.Decl.Index) !void { |
| 3366 | 3541 | const decl = self.base.options.module.?.declPtr(decl_index); |
| 3367 | 3542 | if (decl.link.macho.sym_index != 0) return; |
| 3368 | 3543 | |
| 3369 | | decl.link.macho.sym_index = try self.allocateLocalSymbol(); |
| 3544 | decl.link.macho.sym_index = try self.allocateSymbol(); |
| 3370 | 3545 | try self.atom_by_index_table.putNoClobber(self.base.allocator, decl.link.macho.sym_index, &decl.link.macho); |
| 3371 | 3546 | try self.decls.putNoClobber(self.base.allocator, decl_index, null); |
| 3372 | | |
| 3373 | | const got_target = .{ .sym_index = decl.link.macho.sym_index, .file = null }; |
| 3374 | | _ = try self.allocateGotEntry(got_target); |
| 3375 | 3547 | } |
| 3376 | 3548 | |
| 3377 | 3549 | pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { |
| ... | ... | @@ -3468,7 +3640,7 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu |
| 3468 | 3640 | log.debug("allocating symbol indexes for {s}", .{name}); |
| 3469 | 3641 | |
| 3470 | 3642 | const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); |
| 3471 | | const sym_index = try self.allocateLocalSymbol(); |
| 3643 | const sym_index = try self.allocateSymbol(); |
| 3472 | 3644 | const atom = try MachO.createEmptyAtom( |
| 3473 | 3645 | gpa, |
| 3474 | 3646 | sym_index, |
| ... | ... | @@ -3787,6 +3959,12 @@ fn placeDecl(self: *MachO, decl_index: Module.Decl.Index, code_len: usize) !*mac |
| 3787 | 3959 | log.debug("growing {s} and moving from 0x{x} to 0x{x}", .{ sym_name, symbol.n_value, vaddr }); |
| 3788 | 3960 | log.debug(" (required alignment 0x{x})", .{required_alignment}); |
| 3789 | 3961 | symbol.n_value = vaddr; |
| 3962 | |
| 3963 | const got_atom = self.getGotAtomForSymbol(.{ |
| 3964 | .sym_index = decl.link.macho.sym_index, |
| 3965 | .file = null, |
| 3966 | }).?; |
| 3967 | got_atom.dirty = true; |
| 3790 | 3968 | } else if (code_len < decl.link.macho.size) { |
| 3791 | 3969 | self.shrinkAtom(&decl.link.macho, code_len, match); |
| 3792 | 3970 | } |
| ... | ... | @@ -3814,11 +3992,8 @@ fn placeDecl(self: *MachO, decl_index: Module.Decl.Index, code_len: usize) !*mac |
| 3814 | 3992 | .n_value = addr, |
| 3815 | 3993 | }; |
| 3816 | 3994 | |
| 3817 | | const got_target = SymbolWithLoc{ |
| 3818 | | .sym_index = decl.link.macho.sym_index, |
| 3819 | | .file = null, |
| 3820 | | }; |
| 3821 | | const got_index = self.got_entries_table.get(got_target).?; |
| 3995 | const got_target = SymbolWithLoc{ .sym_index = decl.link.macho.sym_index, .file = null }; |
| 3996 | const got_index = try self.allocateGotEntry(got_target); |
| 3822 | 3997 | const got_atom = try self.createGotAtom(got_target); |
| 3823 | 3998 | self.got_entries.items[got_index].atom = got_atom; |
| 3824 | 3999 | } |
| ... | ... | @@ -3843,19 +4018,23 @@ pub fn updateDeclExports( |
| 3843 | 4018 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 3844 | 4019 | } |
| 3845 | 4020 | if (build_options.have_llvm) { |
| 3846 | | if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(module, decl_index, exports); |
| 4021 | if (self.llvm_object) |llvm_object| |
| 4022 | return llvm_object.updateDeclExports(module, decl_index, exports); |
| 3847 | 4023 | } |
| 3848 | 4024 | const tracy = trace(@src()); |
| 3849 | 4025 | defer tracy.end(); |
| 3850 | 4026 | |
| 3851 | | try self.globals.ensureUnusedCapacity(self.base.allocator, exports.len); |
| 4027 | const gpa = self.base.allocator; |
| 4028 | |
| 3852 | 4029 | const decl = module.declPtr(decl_index); |
| 3853 | 4030 | if (decl.link.macho.sym_index == 0) return; |
| 3854 | | const decl_sym = &self.locals.items[decl.link.macho.sym_index]; |
| 4031 | const decl_sym = decl.link.macho.getSymbol(self); |
| 3855 | 4032 | |
| 3856 | 4033 | for (exports) |exp| { |
| 3857 | | const exp_name = try std.fmt.allocPrint(self.base.allocator, "_{s}", .{exp.options.name}); |
| 3858 | | defer self.base.allocator.free(exp_name); |
| 4034 | const exp_name = try std.fmt.allocPrint(gpa, "_{s}", .{exp.options.name}); |
| 4035 | defer gpa.free(exp_name); |
| 4036 | |
| 4037 | log.debug("adding new export '{s}'", .{exp_name}); |
| 3859 | 4038 | |
| 3860 | 4039 | if (exp.options.section) |section_name| { |
| 3861 | 4040 | if (!mem.eql(u8, section_name, "__text")) { |
| ... | ... | @@ -3863,7 +4042,7 @@ pub fn updateDeclExports( |
| 3863 | 4042 | module.gpa, |
| 3864 | 4043 | exp, |
| 3865 | 4044 | try Module.ErrorMsg.create( |
| 3866 | | self.base.allocator, |
| 4045 | gpa, |
| 3867 | 4046 | decl.srcLoc(), |
| 3868 | 4047 | "Unimplemented: ExportOptions.section", |
| 3869 | 4048 | .{}, |
| ... | ... | @@ -3878,7 +4057,7 @@ pub fn updateDeclExports( |
| 3878 | 4057 | module.gpa, |
| 3879 | 4058 | exp, |
| 3880 | 4059 | try Module.ErrorMsg.create( |
| 3881 | | self.base.allocator, |
| 4060 | gpa, |
| 3882 | 4061 | decl.srcLoc(), |
| 3883 | 4062 | "Unimplemented: GlobalLinkage.LinkOnce", |
| 3884 | 4063 | .{}, |
| ... | ... | @@ -3887,107 +4066,84 @@ pub fn updateDeclExports( |
| 3887 | 4066 | continue; |
| 3888 | 4067 | } |
| 3889 | 4068 | |
| 3890 | | const is_weak = exp.options.linkage == .Internal or exp.options.linkage == .Weak; |
| 3891 | | _ = is_weak; |
| 3892 | | const n_strx = try self.strtab.insert(self.base.allocator, exp_name); |
| 3893 | | // if (self.symbol_resolver.getPtr(n_strx)) |resolv| { |
| 3894 | | // switch (resolv.where) { |
| 3895 | | // .global => { |
| 3896 | | // if (resolv.sym_index == decl.link.macho.sym_index) continue; |
| 3897 | | |
| 3898 | | // const sym = &self.globals.items[resolv.where_index]; |
| 3899 | | |
| 3900 | | // if (sym.tentative()) { |
| 3901 | | // assert(self.tentatives.swapRemove(resolv.where_index)); |
| 3902 | | // } else if (!is_weak and !(sym.weakDef() or sym.pext())) { |
| 3903 | | // _ = try module.failed_exports.put( |
| 3904 | | // module.gpa, |
| 3905 | | // exp, |
| 3906 | | // try Module.ErrorMsg.create( |
| 3907 | | // self.base.allocator, |
| 3908 | | // decl.srcLoc(), |
| 3909 | | // \\LinkError: symbol '{s}' defined multiple times |
| 3910 | | // \\ first definition in '{s}' |
| 3911 | | // , |
| 3912 | | // .{ exp_name, self.objects.items[resolv.file.?].name }, |
| 3913 | | // ), |
| 3914 | | // ); |
| 3915 | | // continue; |
| 3916 | | // } else if (is_weak) continue; // Current symbol is weak, so skip it. |
| 3917 | | |
| 3918 | | // // Otherwise, update the resolver and the global symbol. |
| 3919 | | // sym.n_type = macho.N_SECT | macho.N_EXT; |
| 3920 | | // resolv.sym_index = decl.link.macho.sym_index; |
| 3921 | | // resolv.file = null; |
| 3922 | | // exp.link.macho.sym_index = resolv.where_index; |
| 3923 | | |
| 3924 | | // continue; |
| 3925 | | // }, |
| 3926 | | // .undef => { |
| 3927 | | // assert(self.unresolved.swapRemove(resolv.where_index)); |
| 3928 | | // _ = self.symbol_resolver.remove(n_strx); |
| 3929 | | // }, |
| 3930 | | // } |
| 3931 | | // } |
| 3932 | | |
| 3933 | | var n_type: u8 = macho.N_SECT | macho.N_EXT; |
| 3934 | | var n_desc: u16 = 0; |
| 4069 | const sym_index = exp.link.macho.sym_index orelse blk: { |
| 4070 | const sym_index = try self.allocateSymbol(); |
| 4071 | exp.link.macho.sym_index = sym_index; |
| 4072 | break :blk sym_index; |
| 4073 | }; |
| 4074 | const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null }; |
| 4075 | const sym = self.getSymbolPtr(sym_loc); |
| 4076 | sym.* = .{ |
| 4077 | .n_strx = try self.strtab.insert(gpa, exp_name), |
| 4078 | .n_type = macho.N_SECT | macho.N_EXT, |
| 4079 | .n_sect = self.getSectionOrdinal(.{ |
| 4080 | .seg = self.text_segment_cmd_index.?, |
| 4081 | .sect = self.text_section_index.?, // TODO what if we export a variable? |
| 4082 | }), |
| 4083 | .n_desc = 0, |
| 4084 | .n_value = decl_sym.n_value, |
| 4085 | }; |
| 3935 | 4086 | |
| 3936 | 4087 | switch (exp.options.linkage) { |
| 3937 | 4088 | .Internal => { |
| 3938 | 4089 | // Symbol should be hidden, or in MachO lingo, private extern. |
| 3939 | 4090 | // We should also mark the symbol as Weak: n_desc == N_WEAK_DEF. |
| 3940 | | // TODO work out when to add N_WEAK_REF. |
| 3941 | | n_type |= macho.N_PEXT; |
| 3942 | | n_desc |= macho.N_WEAK_DEF; |
| 4091 | sym.n_type |= macho.N_PEXT; |
| 4092 | sym.n_desc |= macho.N_WEAK_DEF; |
| 3943 | 4093 | }, |
| 3944 | 4094 | .Strong => {}, |
| 3945 | 4095 | .Weak => { |
| 3946 | 4096 | // Weak linkage is specified as part of n_desc field. |
| 3947 | 4097 | // Symbol's n_type is like for a symbol with strong linkage. |
| 3948 | | n_desc |= macho.N_WEAK_DEF; |
| 4098 | sym.n_desc |= macho.N_WEAK_DEF; |
| 3949 | 4099 | }, |
| 3950 | 4100 | else => unreachable, |
| 3951 | 4101 | } |
| 3952 | 4102 | |
| 3953 | | const global_sym_index: u32 = 0; |
| 3954 | | // const global_sym_index = if (exp.link.macho.sym_index) |i| i else blk: { |
| 3955 | | // const i = if (self.globals_free_list.popOrNull()) |i| i else inner: { |
| 3956 | | // _ = self.globals.addOneAssumeCapacity(); |
| 3957 | | // break :inner @intCast(u32, self.globals.items.len - 1); |
| 3958 | | // }; |
| 3959 | | // break :blk i; |
| 3960 | | // }; |
| 3961 | | const sym = &self.locals.items[global_sym_index]; |
| 3962 | | sym.* = .{ |
| 3963 | | .n_strx = try self.strtab.insert(self.base.allocator, exp_name), |
| 3964 | | .n_type = n_type, |
| 3965 | | .n_sect = @intCast(u8, self.text_section_index.?) + 1, |
| 3966 | | .n_desc = n_desc, |
| 3967 | | .n_value = decl_sym.n_value, |
| 4103 | self.resolveGlobalSymbol(sym_loc) catch |err| switch (err) { |
| 4104 | error.MultipleSymbolDefinitions => { |
| 4105 | const global = self.globals.get(exp_name).?; |
| 4106 | if (sym_loc.sym_index != global.sym_index and global.file != null) { |
| 4107 | _ = try module.failed_exports.put(module.gpa, exp, try Module.ErrorMsg.create( |
| 4108 | gpa, |
| 4109 | decl.srcLoc(), |
| 4110 | \\LinkError: symbol '{s}' defined multiple times |
| 4111 | \\ first definition in '{s}' |
| 4112 | , |
| 4113 | .{ exp_name, self.objects.items[global.file.?].name }, |
| 4114 | )); |
| 4115 | } |
| 4116 | }, |
| 4117 | else => |e| return e, |
| 3968 | 4118 | }; |
| 3969 | | exp.link.macho.sym_index = global_sym_index; |
| 3970 | | _ = n_strx; |
| 3971 | | |
| 3972 | | // try self.symbol_resolver.putNoClobber(self.base.allocator, n_strx, .{ |
| 3973 | | // .where = .global, |
| 3974 | | // .where_index = global_sym_index, |
| 3975 | | // .sym_index = decl.link.macho.sym_index, |
| 3976 | | // }); |
| 3977 | 4119 | } |
| 3978 | 4120 | } |
| 3979 | 4121 | |
| 3980 | 4122 | pub fn deleteExport(self: *MachO, exp: Export) void { |
| 3981 | 4123 | if (self.llvm_object) |_| return; |
| 3982 | 4124 | const sym_index = exp.sym_index orelse return; |
| 3983 | | _ = sym_index; |
| 3984 | | // self.globals_free_list.append(self.base.allocator, sym_index) catch {}; |
| 3985 | | // const global = &self.globals.items[sym_index]; |
| 3986 | | // log.warn("deleting export '{s}': {}", .{ self.getString(global.n_strx), global }); |
| 3987 | | // assert(self.symbol_resolver.remove(global.n_strx)); |
| 3988 | | // global.n_type = 0; |
| 3989 | | // global.n_strx = 0; |
| 3990 | | // global.n_value = 0; |
| 4125 | |
| 4126 | const gpa = self.base.allocator; |
| 4127 | |
| 4128 | const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null }; |
| 4129 | const sym = self.getSymbolPtr(sym_loc); |
| 4130 | const sym_name = self.getSymbolName(sym_loc); |
| 4131 | log.debug("deleting export '{s}'", .{sym_name}); |
| 4132 | sym.* = .{ |
| 4133 | .n_strx = 0, |
| 4134 | .n_type = 0, |
| 4135 | .n_sect = 0, |
| 4136 | .n_desc = 0, |
| 4137 | .n_value = 0, |
| 4138 | }; |
| 4139 | self.locals_free_list.append(gpa, sym_index) catch {}; |
| 4140 | |
| 4141 | if (self.globals.get(sym_name)) |global| blk: { |
| 4142 | if (global.sym_index != sym_index) break :blk; |
| 4143 | if (global.file != null) break :blk; |
| 4144 | const kv = self.globals.fetchSwapRemove(sym_name); |
| 4145 | gpa.free(kv.?.key); |
| 4146 | } |
| 3991 | 4147 | } |
| 3992 | 4148 | |
| 3993 | 4149 | fn freeUnnamedConsts(self: *MachO, decl_index: Module.Decl.Index) void { |
| ... | ... | @@ -4026,7 +4182,10 @@ pub fn freeDecl(self: *MachO, decl_index: Module.Decl.Index) void { |
| 4026 | 4182 | const got_target = SymbolWithLoc{ .sym_index = decl.link.macho.sym_index, .file = null }; |
| 4027 | 4183 | if (self.got_entries_table.get(got_target)) |got_index| { |
| 4028 | 4184 | self.got_entries_free_list.append(self.base.allocator, @intCast(u32, got_index)) catch {}; |
| 4029 | | self.got_entries.items[got_index] = .{ .target = .{ .sym_index = 0, .file = null }, .atom = undefined }; |
| 4185 | self.got_entries.items[got_index] = .{ |
| 4186 | .target = .{ .sym_index = 0, .file = null }, |
| 4187 | .atom = undefined, |
| 4188 | }; |
| 4030 | 4189 | _ = self.got_entries_table.swapRemove(got_target); |
| 4031 | 4190 | |
| 4032 | 4191 | if (self.d_sym) |*d_sym| { |
| ... | ... | @@ -4102,7 +4261,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4102 | 4261 | |
| 4103 | 4262 | if (self.text_segment_cmd_index == null) { |
| 4104 | 4263 | self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 4105 | | const needed_size = if (self.needs_prealloc) blk: { |
| 4264 | const needed_size = if (self.mode == .incremental) blk: { |
| 4106 | 4265 | const headerpad_size = @maximum(self.base.options.headerpad_size orelse 0, default_headerpad_size); |
| 4107 | 4266 | const program_code_size_hint = self.base.options.program_code_size_hint; |
| 4108 | 4267 | const got_size_hint = @sizeOf(u64) * self.base.options.symbol_count_hint; |
| ... | ... | @@ -4133,7 +4292,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4133 | 4292 | .aarch64 => 2, |
| 4134 | 4293 | else => unreachable, // unhandled architecture type |
| 4135 | 4294 | }; |
| 4136 | | const needed_size = if (self.needs_prealloc) self.base.options.program_code_size_hint else 0; |
| 4295 | const needed_size = if (self.mode == .incremental) self.base.options.program_code_size_hint else 0; |
| 4137 | 4296 | self.text_section_index = try self.initSection( |
| 4138 | 4297 | self.text_segment_cmd_index.?, |
| 4139 | 4298 | "__text", |
| ... | ... | @@ -4156,7 +4315,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4156 | 4315 | .aarch64 => 3 * @sizeOf(u32), |
| 4157 | 4316 | else => unreachable, // unhandled architecture type |
| 4158 | 4317 | }; |
| 4159 | | const needed_size = if (self.needs_prealloc) stub_size * self.base.options.symbol_count_hint else 0; |
| 4318 | const needed_size = if (self.mode == .incremental) stub_size * self.base.options.symbol_count_hint else 0; |
| 4160 | 4319 | self.stubs_section_index = try self.initSection( |
| 4161 | 4320 | self.text_segment_cmd_index.?, |
| 4162 | 4321 | "__stubs", |
| ... | ... | @@ -4185,7 +4344,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4185 | 4344 | .aarch64 => 3 * @sizeOf(u32), |
| 4186 | 4345 | else => unreachable, |
| 4187 | 4346 | }; |
| 4188 | | const needed_size = if (self.needs_prealloc) |
| 4347 | const needed_size = if (self.mode == .incremental) |
| 4189 | 4348 | stub_size * self.base.options.symbol_count_hint + preamble_size |
| 4190 | 4349 | else |
| 4191 | 4350 | 0; |
| ... | ... | @@ -4205,7 +4364,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4205 | 4364 | var vmaddr: u64 = 0; |
| 4206 | 4365 | var fileoff: u64 = 0; |
| 4207 | 4366 | var needed_size: u64 = 0; |
| 4208 | | if (self.needs_prealloc) { |
| 4367 | if (self.mode == .incremental) { |
| 4209 | 4368 | const base = self.getSegmentAllocBase(&.{self.text_segment_cmd_index.?}); |
| 4210 | 4369 | vmaddr = base.vmaddr; |
| 4211 | 4370 | fileoff = base.fileoff; |
| ... | ... | @@ -4234,7 +4393,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4234 | 4393 | } |
| 4235 | 4394 | |
| 4236 | 4395 | if (self.got_section_index == null) { |
| 4237 | | const needed_size = if (self.needs_prealloc) |
| 4396 | const needed_size = if (self.mode == .incremental) |
| 4238 | 4397 | @sizeOf(u64) * self.base.options.symbol_count_hint |
| 4239 | 4398 | else |
| 4240 | 4399 | 0; |
| ... | ... | @@ -4255,7 +4414,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4255 | 4414 | var vmaddr: u64 = 0; |
| 4256 | 4415 | var fileoff: u64 = 0; |
| 4257 | 4416 | var needed_size: u64 = 0; |
| 4258 | | if (self.needs_prealloc) { |
| 4417 | if (self.mode == .incremental) { |
| 4259 | 4418 | const base = self.getSegmentAllocBase(&.{self.data_const_segment_cmd_index.?}); |
| 4260 | 4419 | vmaddr = base.vmaddr; |
| 4261 | 4420 | fileoff = base.fileoff; |
| ... | ... | @@ -4284,7 +4443,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4284 | 4443 | } |
| 4285 | 4444 | |
| 4286 | 4445 | if (self.la_symbol_ptr_section_index == null) { |
| 4287 | | const needed_size = if (self.needs_prealloc) |
| 4446 | const needed_size = if (self.mode == .incremental) |
| 4288 | 4447 | @sizeOf(u64) * self.base.options.symbol_count_hint |
| 4289 | 4448 | else |
| 4290 | 4449 | 0; |
| ... | ... | @@ -4301,7 +4460,10 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4301 | 4460 | } |
| 4302 | 4461 | |
| 4303 | 4462 | if (self.data_section_index == null) { |
| 4304 | | const needed_size = if (self.needs_prealloc) @sizeOf(u64) * self.base.options.symbol_count_hint else 0; |
| 4463 | const needed_size = if (self.mode == .incremental) |
| 4464 | @sizeOf(u64) * self.base.options.symbol_count_hint |
| 4465 | else |
| 4466 | 0; |
| 4305 | 4467 | const alignment: u16 = 3; // 2^3 = @sizeOf(u64) |
| 4306 | 4468 | self.data_section_index = try self.initSection( |
| 4307 | 4469 | self.data_segment_cmd_index.?, |
| ... | ... | @@ -4313,7 +4475,10 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4313 | 4475 | } |
| 4314 | 4476 | |
| 4315 | 4477 | if (self.tlv_section_index == null) { |
| 4316 | | const needed_size = if (self.needs_prealloc) @sizeOf(u64) * self.base.options.symbol_count_hint else 0; |
| 4478 | const needed_size = if (self.mode == .incremental) |
| 4479 | @sizeOf(u64) * self.base.options.symbol_count_hint |
| 4480 | else |
| 4481 | 0; |
| 4317 | 4482 | const alignment: u16 = 3; // 2^3 = @sizeOf(u64) |
| 4318 | 4483 | self.tlv_section_index = try self.initSection( |
| 4319 | 4484 | self.data_segment_cmd_index.?, |
| ... | ... | @@ -4327,7 +4492,10 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4327 | 4492 | } |
| 4328 | 4493 | |
| 4329 | 4494 | if (self.tlv_data_section_index == null) { |
| 4330 | | const needed_size = if (self.needs_prealloc) @sizeOf(u64) * self.base.options.symbol_count_hint else 0; |
| 4495 | const needed_size = if (self.mode == .incremental) |
| 4496 | @sizeOf(u64) * self.base.options.symbol_count_hint |
| 4497 | else |
| 4498 | 0; |
| 4331 | 4499 | const alignment: u16 = 3; // 2^3 = @sizeOf(u64) |
| 4332 | 4500 | self.tlv_data_section_index = try self.initSection( |
| 4333 | 4501 | self.data_segment_cmd_index.?, |
| ... | ... | @@ -4341,7 +4509,10 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4341 | 4509 | } |
| 4342 | 4510 | |
| 4343 | 4511 | if (self.tlv_bss_section_index == null) { |
| 4344 | | const needed_size = if (self.needs_prealloc) @sizeOf(u64) * self.base.options.symbol_count_hint else 0; |
| 4512 | const needed_size = if (self.mode == .incremental) |
| 4513 | @sizeOf(u64) * self.base.options.symbol_count_hint |
| 4514 | else |
| 4515 | 0; |
| 4345 | 4516 | const alignment: u16 = 3; // 2^3 = @sizeOf(u64) |
| 4346 | 4517 | self.tlv_bss_section_index = try self.initSection( |
| 4347 | 4518 | self.data_segment_cmd_index.?, |
| ... | ... | @@ -4355,7 +4526,10 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4355 | 4526 | } |
| 4356 | 4527 | |
| 4357 | 4528 | if (self.bss_section_index == null) { |
| 4358 | | const needed_size = if (self.needs_prealloc) @sizeOf(u64) * self.base.options.symbol_count_hint else 0; |
| 4529 | const needed_size = if (self.mode == .incremental) |
| 4530 | @sizeOf(u64) * self.base.options.symbol_count_hint |
| 4531 | else |
| 4532 | 0; |
| 4359 | 4533 | const alignment: u16 = 3; // 2^3 = @sizeOf(u64) |
| 4360 | 4534 | self.bss_section_index = try self.initSection( |
| 4361 | 4535 | self.data_segment_cmd_index.?, |
| ... | ... | @@ -4372,7 +4546,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4372 | 4546 | self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 4373 | 4547 | var vmaddr: u64 = 0; |
| 4374 | 4548 | var fileoff: u64 = 0; |
| 4375 | | if (self.needs_prealloc) { |
| 4549 | if (self.mode == .incremental) { |
| 4376 | 4550 | const base = self.getSegmentAllocBase(&.{self.data_segment_cmd_index.?}); |
| 4377 | 4551 | vmaddr = base.vmaddr; |
| 4378 | 4552 | fileoff = base.fileoff; |
| ... | ... | @@ -4740,14 +4914,14 @@ fn initSection( |
| 4740 | 4914 | var sect = macho.section_64{ |
| 4741 | 4915 | .sectname = makeStaticString(sectname), |
| 4742 | 4916 | .segname = seg.inner.segname, |
| 4743 | | .size = if (self.needs_prealloc) @intCast(u32, size) else 0, |
| 4917 | .size = if (self.mode == .incremental) @intCast(u32, size) else 0, |
| 4744 | 4918 | .@"align" = alignment, |
| 4745 | 4919 | .flags = opts.flags, |
| 4746 | 4920 | .reserved1 = opts.reserved1, |
| 4747 | 4921 | .reserved2 = opts.reserved2, |
| 4748 | 4922 | }; |
| 4749 | 4923 | |
| 4750 | | if (self.needs_prealloc) { |
| 4924 | if (self.mode == .incremental) { |
| 4751 | 4925 | const alignment_pow_2 = try math.powi(u32, 2, alignment); |
| 4752 | 4926 | const padding: ?u32 = if (segment_id == self.text_segment_cmd_index.?) |
| 4753 | 4927 | @maximum(self.base.options.headerpad_size orelse 0, default_headerpad_size) |
| ... | ... | @@ -4967,7 +5141,7 @@ fn getSectionMaxAlignment(self: *MachO, segment_id: u16, start_sect_id: u16) !u3 |
| 4967 | 5141 | |
| 4968 | 5142 | fn allocateAtomCommon(self: *MachO, atom: *Atom, match: MatchingSection) !void { |
| 4969 | 5143 | const sym = atom.getSymbolPtr(self); |
| 4970 | | if (self.needs_prealloc) { |
| 5144 | if (self.mode == .incremental) { |
| 4971 | 5145 | const size = atom.size; |
| 4972 | 5146 | const alignment = try math.powi(u32, 2, atom.alignment); |
| 4973 | 5147 | const vaddr = try self.allocateAtom(atom, size, alignment, match); |
| ... | ... | @@ -5108,27 +5282,29 @@ pub fn addAtomToSection(self: *MachO, atom: *Atom, match: MatchingSection) !void |
| 5108 | 5282 | pub fn getGlobalSymbol(self: *MachO, name: []const u8) !u32 { |
| 5109 | 5283 | const gpa = self.base.allocator; |
| 5110 | 5284 | const sym_name = try std.fmt.allocPrint(gpa, "_{s}", .{name}); |
| 5111 | | defer gpa.free(sym_name); |
| 5285 | const global_index = @intCast(u32, self.globals.values().len); |
| 5286 | const gop = try self.globals.getOrPut(gpa, sym_name); |
| 5287 | defer if (gop.found_existing) gpa.free(sym_name); |
| 5112 | 5288 | |
| 5113 | | if (self.globals.getIndex(sym_name)) |global_index| { |
| 5114 | | return @intCast(u32, global_index); |
| 5289 | if (gop.found_existing) { |
| 5290 | return @intCast(u32, self.globals.getIndex(sym_name).?); |
| 5115 | 5291 | } |
| 5116 | 5292 | |
| 5117 | | const n_strx = try self.strtab.insert(gpa, sym_name); |
| 5118 | 5293 | const sym_index = @intCast(u32, self.locals.items.len); |
| 5119 | 5294 | try self.locals.append(gpa, .{ |
| 5120 | | .n_strx = n_strx, |
| 5295 | .n_strx = try self.strtab.insert(gpa, sym_name), |
| 5121 | 5296 | .n_type = macho.N_UNDF, |
| 5122 | 5297 | .n_sect = 0, |
| 5123 | 5298 | .n_desc = 0, |
| 5124 | 5299 | .n_value = 0, |
| 5125 | 5300 | }); |
| 5126 | | try self.globals.putNoClobber(gpa, sym_name, .{ |
| 5301 | gop.value_ptr.* = .{ |
| 5127 | 5302 | .sym_index = sym_index, |
| 5128 | 5303 | .file = null, |
| 5129 | | }); |
| 5130 | | const global_index = self.globals.getIndex(sym_name).?; |
| 5131 | | return @intCast(u32, global_index); |
| 5304 | }; |
| 5305 | try self.unresolved.putNoClobber(gpa, global_index, true); |
| 5306 | |
| 5307 | return global_index; |
| 5132 | 5308 | } |
| 5133 | 5309 | |
| 5134 | 5310 | fn getSegmentAllocBase(self: MachO, indices: []const ?u16) struct { vmaddr: u64, fileoff: u64 } { |
| ... | ... | @@ -5927,7 +6103,7 @@ fn writeDices(self: *MachO) !void { |
| 5927 | 6103 | self.load_commands_dirty = true; |
| 5928 | 6104 | } |
| 5929 | 6105 | |
| 5930 | | fn writeSymbolTable(self: *MachO) !void { |
| 6106 | fn writeSymtab(self: *MachO) !void { |
| 5931 | 6107 | const tracy = trace(@src()); |
| 5932 | 6108 | defer tracy.end(); |
| 5933 | 6109 | |
| ... | ... | @@ -6143,7 +6319,7 @@ fn writeSymbolTable(self: *MachO) !void { |
| 6143 | 6319 | self.load_commands_dirty = true; |
| 6144 | 6320 | } |
| 6145 | 6321 | |
| 6146 | | fn writeStringTable(self: *MachO) !void { |
| 6322 | fn writeStrtab(self: *MachO) !void { |
| 6147 | 6323 | const tracy = trace(@src()); |
| 6148 | 6324 | defer tracy.end(); |
| 6149 | 6325 | |
| ... | ... | @@ -6173,8 +6349,8 @@ fn writeLinkeditSegment(self: *MachO) !void { |
| 6173 | 6349 | try self.writeDyldInfoData(); |
| 6174 | 6350 | try self.writeFunctionStarts(); |
| 6175 | 6351 | try self.writeDices(); |
| 6176 | | try self.writeSymbolTable(); |
| 6177 | | try self.writeStringTable(); |
| 6352 | try self.writeSymtab(); |
| 6353 | try self.writeStrtab(); |
| 6178 | 6354 | |
| 6179 | 6355 | seg.inner.vmsize = mem.alignForwardGeneric(u64, seg.inner.filesize, self.page_size); |
| 6180 | 6356 | } |
| ... | ... | @@ -6391,6 +6567,27 @@ pub fn getAtomForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?*Atom { |
| 6391 | 6567 | } |
| 6392 | 6568 | } |
| 6393 | 6569 | |
| 6570 | /// Returns GOT atom that references `sym_with_loc` if one exists. |
| 6571 | /// Returns null otherwise. |
| 6572 | pub fn getGotAtomForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?*Atom { |
| 6573 | const got_index = self.got_entries_table.get(sym_with_loc) orelse return null; |
| 6574 | return self.got_entries.items[got_index].atom; |
| 6575 | } |
| 6576 | |
| 6577 | /// Returns stubs atom that references `sym_with_loc` if one exists. |
| 6578 | /// Returns null otherwise. |
| 6579 | pub fn getStubsAtomForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?*Atom { |
| 6580 | const stubs_index = self.stubs_table.get(sym_with_loc) orelse return null; |
| 6581 | return self.stubs.items[stubs_index].atom; |
| 6582 | } |
| 6583 | |
| 6584 | /// Returns TLV pointer atom that references `sym_with_loc` if one exists. |
| 6585 | /// Returns null otherwise. |
| 6586 | pub fn getTlvPtrAtomForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?*Atom { |
| 6587 | const tlv_ptr_index = self.tlv_ptr_entries_table.get(sym_with_loc) orelse return null; |
| 6588 | return self.tlv_ptr_entries.items[tlv_ptr_index].atom; |
| 6589 | } |
| 6590 | |
| 6394 | 6591 | pub fn findFirst(comptime T: type, haystack: []const T, start: usize, predicate: anytype) usize { |
| 6395 | 6592 | if (!@hasDecl(@TypeOf(predicate), "predicate")) |
| 6396 | 6593 | @compileError("Predicate is required to define fn predicate(@This(), T) bool"); |
| ... | ... | @@ -6481,6 +6678,8 @@ fn snapshotState(self: *MachO) !void { |
| 6481 | 6678 | .payload = .{ .name = sect_name }, |
| 6482 | 6679 | }); |
| 6483 | 6680 | |
| 6681 | const is_tlv = sect.type_() == macho.S_THREAD_LOCAL_VARIABLES; |
| 6682 | |
| 6484 | 6683 | var atom: *Atom = self.atoms.get(key) orelse { |
| 6485 | 6684 | try nodes.append(.{ |
| 6486 | 6685 | .address = sect.addr + sect.size, |
| ... | ... | @@ -6495,35 +6694,23 @@ fn snapshotState(self: *MachO) !void { |
| 6495 | 6694 | } |
| 6496 | 6695 | |
| 6497 | 6696 | while (true) { |
| 6498 | | const atom_sym = self.locals.items[atom.sym_index]; |
| 6499 | | const should_skip_atom: bool = blk: { |
| 6500 | | if (self.mh_execute_header_index) |index| { |
| 6501 | | if (index == atom.sym_index) break :blk true; |
| 6502 | | } |
| 6503 | | if (mem.eql(u8, self.getString(atom_sym.n_strx), "___dso_handle")) break :blk true; |
| 6504 | | break :blk false; |
| 6505 | | }; |
| 6506 | | |
| 6507 | | if (should_skip_atom) { |
| 6508 | | if (atom.next) |next| { |
| 6509 | | atom = next; |
| 6510 | | } else break; |
| 6511 | | continue; |
| 6512 | | } |
| 6513 | | |
| 6697 | const atom_sym = atom.getSymbol(self); |
| 6514 | 6698 | var node = Snapshot.Node{ |
| 6515 | 6699 | .address = atom_sym.n_value, |
| 6516 | 6700 | .tag = .atom_start, |
| 6517 | 6701 | .payload = .{ |
| 6518 | | .name = self.getString(atom_sym.n_strx), |
| 6519 | | .is_global = self.symbol_resolver.contains(atom_sym.n_strx), |
| 6702 | .name = atom.getName(self), |
| 6703 | .is_global = self.globals.contains(atom.getName(self)), |
| 6520 | 6704 | }, |
| 6521 | 6705 | }; |
| 6522 | 6706 | |
| 6523 | 6707 | var aliases = std.ArrayList([]const u8).init(arena); |
| 6524 | 6708 | for (atom.contained.items) |sym_off| { |
| 6525 | 6709 | if (sym_off.offset == 0) { |
| 6526 | | try aliases.append(self.getString(self.locals.items[sym_off.sym_index].n_strx)); |
| 6710 | try aliases.append(self.getSymbolName(.{ |
| 6711 | .sym_index = sym_off.sym_index, |
| 6712 | .file = atom.file, |
| 6713 | })); |
| 6527 | 6714 | } |
| 6528 | 6715 | } |
| 6529 | 6716 | node.payload.aliases = aliases.toOwnedSlice(); |
| ... | ... | @@ -6531,69 +6718,39 @@ fn snapshotState(self: *MachO) !void { |
| 6531 | 6718 | |
| 6532 | 6719 | var relocs = try std.ArrayList(Snapshot.Node).initCapacity(arena, atom.relocs.items.len); |
| 6533 | 6720 | for (atom.relocs.items) |rel| { |
| 6534 | | const arch = self.base.options.target.cpu.arch; |
| 6535 | 6721 | const source_addr = blk: { |
| 6536 | | const sym = self.locals.items[atom.sym_index]; |
| 6537 | | break :blk sym.n_value + rel.offset; |
| 6722 | const source_sym = atom.getSymbol(self); |
| 6723 | break :blk source_sym.n_value + rel.offset; |
| 6538 | 6724 | }; |
| 6539 | 6725 | const target_addr = blk: { |
| 6540 | | const is_via_got = got: { |
| 6541 | | switch (arch) { |
| 6542 | | .aarch64 => break :got switch (@intToEnum(macho.reloc_type_arm64, rel.@"type")) { |
| 6543 | | .ARM64_RELOC_GOT_LOAD_PAGE21, .ARM64_RELOC_GOT_LOAD_PAGEOFF12 => true, |
| 6544 | | else => false, |
| 6545 | | }, |
| 6546 | | .x86_64 => break :got switch (@intToEnum(macho.reloc_type_x86_64, rel.@"type")) { |
| 6547 | | .X86_64_RELOC_GOT, .X86_64_RELOC_GOT_LOAD => true, |
| 6548 | | else => false, |
| 6549 | | }, |
| 6550 | | else => unreachable, |
| 6726 | const target_atom = (try rel.getTargetAtom(self)) orelse { |
| 6727 | // If there is no atom for target, we still need to check for special, atom-less |
| 6728 | // symbols such as `___dso_handle`. |
| 6729 | const target_name = self.getSymbolName(rel.target); |
| 6730 | if (self.globals.contains(target_name)) { |
| 6731 | const atomless_sym = self.getSymbol(rel.target); |
| 6732 | break :blk atomless_sym.n_value; |
| 6551 | 6733 | } |
| 6734 | break :blk 0; |
| 6552 | 6735 | }; |
| 6553 | | |
| 6554 | | if (is_via_got) { |
| 6555 | | const got_index = self.got_entries_table.get(rel.target) orelse break :blk 0; |
| 6556 | | const got_atom = self.got_entries.items[got_index].atom; |
| 6557 | | break :blk self.locals.items[got_atom.sym_index].n_value; |
| 6558 | | } |
| 6559 | | |
| 6560 | | switch (rel.target) { |
| 6561 | | .local => |sym_index| { |
| 6562 | | const sym = self.locals.items[sym_index]; |
| 6563 | | const is_tlv = is_tlv: { |
| 6564 | | const source_sym = self.locals.items[atom.sym_index]; |
| 6565 | | const match = self.section_ordinals.keys()[source_sym.n_sect - 1]; |
| 6566 | | const match_seg = self.load_commands.items[match.seg].segment; |
| 6567 | | const match_sect = match_seg.sections.items[match.sect]; |
| 6568 | | break :is_tlv match_sect.type_() == macho.S_THREAD_LOCAL_VARIABLES; |
| 6569 | | }; |
| 6570 | | if (is_tlv) { |
| 6571 | | const match_seg = self.load_commands.items[self.data_segment_cmd_index.?].segment; |
| 6572 | | const base_address = inner: { |
| 6573 | | if (self.tlv_data_section_index) |i| { |
| 6574 | | break :inner match_seg.sections.items[i].addr; |
| 6575 | | } else if (self.tlv_bss_section_index) |i| { |
| 6576 | | break :inner match_seg.sections.items[i].addr; |
| 6577 | | } else unreachable; |
| 6578 | | }; |
| 6579 | | break :blk sym.n_value - base_address; |
| 6580 | | } |
| 6581 | | break :blk sym.n_value; |
| 6582 | | }, |
| 6583 | | .global => |n_strx| { |
| 6584 | | const resolv = self.symbol_resolver.get(n_strx).?; |
| 6585 | | switch (resolv.where) { |
| 6586 | | .global => break :blk self.globals.items[resolv.where_index].n_value, |
| 6587 | | .undef => { |
| 6588 | | if (self.stubs_table.get(n_strx)) |stub_index| { |
| 6589 | | const stub_atom = self.stubs.items[stub_index]; |
| 6590 | | break :blk self.locals.items[stub_atom.sym_index].n_value; |
| 6591 | | } |
| 6592 | | break :blk 0; |
| 6593 | | }, |
| 6594 | | } |
| 6595 | | }, |
| 6596 | | } |
| 6736 | const target_sym = if (target_atom.isSymbolContained(rel.target, self)) |
| 6737 | self.getSymbol(rel.target) |
| 6738 | else |
| 6739 | target_atom.getSymbol(self); |
| 6740 | const base_address: u64 = if (is_tlv) base_address: { |
| 6741 | const sect_id: u16 = sect_id: { |
| 6742 | if (self.tlv_data_section_index) |i| { |
| 6743 | break :sect_id i; |
| 6744 | } else if (self.tlv_bss_section_index) |i| { |
| 6745 | break :sect_id i; |
| 6746 | } else unreachable; |
| 6747 | }; |
| 6748 | break :base_address self.getSection(.{ |
| 6749 | .seg = self.data_segment_cmd_index.?, |
| 6750 | .sect = sect_id, |
| 6751 | }).addr; |
| 6752 | } else 0; |
| 6753 | break :blk target_sym.n_value - base_address; |
| 6597 | 6754 | }; |
| 6598 | 6755 | |
| 6599 | 6756 | relocs.appendAssumeCapacity(.{ |
| ... | ... | @@ -6614,15 +6771,18 @@ fn snapshotState(self: *MachO) !void { |
| 6614 | 6771 | var next_i: usize = 0; |
| 6615 | 6772 | var last_rel: usize = 0; |
| 6616 | 6773 | while (next_i < atom.contained.items.len) : (next_i += 1) { |
| 6617 | | const loc = atom.contained.items[next_i]; |
| 6618 | | const cont_sym = self.locals.items[loc.sym_index]; |
| 6619 | | const cont_sym_name = self.getString(cont_sym.n_strx); |
| 6774 | const loc = SymbolWithLoc{ |
| 6775 | .sym_index = atom.contained.items[next_i].sym_index, |
| 6776 | .file = atom.file, |
| 6777 | }; |
| 6778 | const cont_sym = self.getSymbol(loc); |
| 6779 | const cont_sym_name = self.getSymbolName(loc); |
| 6620 | 6780 | var contained_node = Snapshot.Node{ |
| 6621 | 6781 | .address = cont_sym.n_value, |
| 6622 | 6782 | .tag = .atom_start, |
| 6623 | 6783 | .payload = .{ |
| 6624 | 6784 | .name = cont_sym_name, |
| 6625 | | .is_global = self.symbol_resolver.contains(cont_sym.n_strx), |
| 6785 | .is_global = self.globals.contains(cont_sym_name), |
| 6626 | 6786 | }, |
| 6627 | 6787 | }; |
| 6628 | 6788 | |
| ... | ... | @@ -6630,10 +6790,14 @@ fn snapshotState(self: *MachO) !void { |
| 6630 | 6790 | var inner_aliases = std.ArrayList([]const u8).init(arena); |
| 6631 | 6791 | while (true) { |
| 6632 | 6792 | if (next_i + 1 >= atom.contained.items.len) break; |
| 6633 | | const next_sym = self.locals.items[atom.contained.items[next_i + 1].sym_index]; |
| 6793 | const next_sym_loc = SymbolWithLoc{ |
| 6794 | .sym_index = atom.contained.items[next_i + 1].sym_index, |
| 6795 | .file = atom.file, |
| 6796 | }; |
| 6797 | const next_sym = self.getSymbol(next_sym_loc); |
| 6634 | 6798 | if (next_sym.n_value != cont_sym.n_value) break; |
| 6635 | | const next_sym_name = self.getString(next_sym.n_strx); |
| 6636 | | if (self.symbol_resolver.contains(next_sym.n_strx)) { |
| 6799 | const next_sym_name = self.getSymbolName(next_sym_loc); |
| 6800 | if (self.globals.contains(next_sym_name)) { |
| 6637 | 6801 | try inner_aliases.append(contained_node.payload.name); |
| 6638 | 6802 | contained_node.payload.name = next_sym_name; |
| 6639 | 6803 | contained_node.payload.is_global = true; |
| ... | ... | @@ -6642,7 +6806,10 @@ fn snapshotState(self: *MachO) !void { |
| 6642 | 6806 | } |
| 6643 | 6807 | |
| 6644 | 6808 | const cont_size = if (next_i + 1 < atom.contained.items.len) |
| 6645 | | self.locals.items[atom.contained.items[next_i + 1].sym_index].n_value - cont_sym.n_value |
| 6809 | self.getSymbol(.{ |
| 6810 | .sym_index = atom.contained.items[next_i + 1].sym_index, |
| 6811 | .file = atom.file, |
| 6812 | }).n_value - cont_sym.n_value |
| 6646 | 6813 | else |
| 6647 | 6814 | atom_sym.n_value + atom.size - cont_sym.n_value; |
| 6648 | 6815 | |
| ... | ... | @@ -6695,7 +6862,11 @@ pub fn logSymAttributes(sym: macho.nlist_64, buf: *[4]u8) []const u8 { |
| 6695 | 6862 | buf[0] = 's'; |
| 6696 | 6863 | } |
| 6697 | 6864 | if (sym.ext()) { |
| 6698 | | buf[1] = 'e'; |
| 6865 | if (sym.weakDef() or sym.pext()) { |
| 6866 | buf[1] = 'w'; |
| 6867 | } else { |
| 6868 | buf[1] = 'e'; |
| 6869 | } |
| 6699 | 6870 | } |
| 6700 | 6871 | if (sym.tentative()) { |
| 6701 | 6872 | buf[2] = 't'; |