| ... | @@ -70,10 +70,10 @@ d_sym: ?DebugSymbols = null, | ... | @@ -70,10 +70,10 @@ d_sym: ?DebugSymbols = null, |
| 70 | /// For x86_64 that's 4KB, whereas for aarch64, that's 16KB. | 70 | /// For x86_64 that's 4KB, whereas for aarch64, that's 16KB. |
| 71 | page_size: u16, | 71 | page_size: u16, |
| 72 | | 72 | |
| 73 | /// If true, the linker will preallocate several sections and segments before starting the linking | 73 | /// Mode of operation: incremental - will preallocate segments/sections and is compatible with |
| 74 | /// process. This is for example true for stage2 debug builds, however, this is false for stage1 | 74 | /// watch and HCS modes of operation; one_shot - will link relocatables in a traditional, one-shot |
| 75 | /// and potentially stage2 release builds in the future. | 75 | /// fashion (default for LLVM backend). |
| 76 | needs_prealloc: bool = true, | 76 | mode: enum { incremental, one_shot }, |
| 77 | | 77 | |
| 78 | /// The absolute address of the entry point. | 78 | /// The absolute address of the entry point. |
| 79 | entry_addr: ?u64 = null, | 79 | entry_addr: ?u64 = null, |
| ... | @@ -153,7 +153,7 @@ rustc_section_size: u64 = 0, | ... | @@ -153,7 +153,7 @@ rustc_section_size: u64 = 0, |
| 153 | | 153 | |
| 154 | locals: std.ArrayListUnmanaged(macho.nlist_64) = .{}, | 154 | locals: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 155 | globals: std.StringArrayHashMapUnmanaged(SymbolWithLoc) = .{}, | 155 | globals: std.StringArrayHashMapUnmanaged(SymbolWithLoc) = .{}, |
| 156 | unresolved: std.AutoArrayHashMapUnmanaged(u32, void) = .{}, | 156 | unresolved: std.AutoArrayHashMapUnmanaged(u32, bool) = .{}, |
| 157 | | 157 | |
| 158 | locals_free_list: std.ArrayListUnmanaged(u32) = .{}, | 158 | locals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 159 | | 159 | |
| ... | @@ -161,7 +161,7 @@ dyld_stub_binder_index: ?u32 = null, | ... | @@ -161,7 +161,7 @@ dyld_stub_binder_index: ?u32 = null, |
| 161 | dyld_private_atom: ?*Atom = null, | 161 | dyld_private_atom: ?*Atom = null, |
| 162 | stub_helper_preamble_atom: ?*Atom = null, | 162 | stub_helper_preamble_atom: ?*Atom = null, |
| 163 | | 163 | |
| 164 | strtab: StringTable(.link) = .{}, | 164 | strtab: StringTable(.strtab) = .{}, |
| 165 | | 165 | |
| 166 | tlv_ptr_entries: std.ArrayListUnmanaged(Entry) = .{}, | 166 | tlv_ptr_entries: std.ArrayListUnmanaged(Entry) = .{}, |
| 167 | tlv_ptr_entries_free_list: std.ArrayListUnmanaged(u32) = .{}, | 167 | tlv_ptr_entries_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| ... | @@ -182,6 +182,12 @@ sections_order_dirty: bool = false, | ... | @@ -182,6 +182,12 @@ sections_order_dirty: bool = false, |
| 182 | has_dices: bool = false, | 182 | has_dices: bool = false, |
| 183 | has_stabs: bool = false, | 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 | section_ordinals: std.AutoArrayHashMapUnmanaged(MatchingSection, void) = .{}, | 191 | section_ordinals: std.AutoArrayHashMapUnmanaged(MatchingSection, void) = .{}, |
| 186 | | 192 | |
| 187 | /// A list of atoms that have surplus capacity. This list can have false | 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,7 +393,6 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO { |
| 387 | const requires_adhoc_codesig = cpu_arch == .aarch64 and (os_tag == .macos or abi == .simulator); | 393 | const requires_adhoc_codesig = cpu_arch == .aarch64 and (os_tag == .macos or abi == .simulator); |
| 388 | const use_llvm = build_options.have_llvm and options.use_llvm; | 394 | const use_llvm = build_options.have_llvm and options.use_llvm; |
| 389 | const use_stage1 = build_options.is_stage1 and options.use_stage1; | 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 | const self = try gpa.create(MachO); | 397 | const self = try gpa.create(MachO); |
| 393 | errdefer gpa.destroy(self); | 398 | errdefer gpa.destroy(self); |
| ... | @@ -400,8 +405,14 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO { | ... | @@ -400,8 +405,14 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO { |
| 400 | .file = null, | 405 | .file = null, |
| 401 | }, | 406 | }, |
| 402 | .page_size = page_size, | 407 | .page_size = page_size, |
| 403 | .code_signature = if (requires_adhoc_codesig) CodeSignature.init(page_size) else null, | 408 | .code_signature = if (requires_adhoc_codesig) |
| 404 | .needs_prealloc = needs_prealloc, | 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 | if (use_llvm and !use_stage1) { | 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,32 +440,198 @@ pub fn flush(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) !v |
| 429 | return error.TODOImplementWritingStaticLibFiles; | 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 | pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) !void { | 450 | pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) !void { |
| 436 | const tracy = trace(@src()); | 451 | const tracy = trace(@src()); |
| 437 | defer tracy.end(); | 452 | defer tracy.end(); |
| 438 | | 453 | |
| 439 | const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1; | 454 | if (build_options.have_llvm) { |
| 440 | | | |
| 441 | if (build_options.have_llvm and !use_stage1) { | | |
| 442 | if (self.llvm_object) |llvm_object| { | 455 | if (self.llvm_object) |llvm_object| { |
| 443 | try llvm_object.flushModule(comp, prog_node); | 456 | return 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 | } | | |
| 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 | var sub_prog_node = prog_node.start("MachO Flush", 0); | 464 | var sub_prog_node = prog_node.start("MachO Flush", 0); |
| 455 | sub_prog_node.activate(); | 465 | sub_prog_node.activate(); |
| 456 | defer sub_prog_node.end(); | 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 | var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator); | 635 | var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator); |
| 459 | defer arena_allocator.deinit(); | 636 | defer arena_allocator.deinit(); |
| 460 | const arena = arena_allocator.allocator(); | 637 | const arena = arena_allocator.allocator(); |
| ... | @@ -465,7 +642,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -465,7 +642,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 465 | // If there is no Zig code to compile, then we should skip flushing the output file because it | 642 | // If there is no Zig code to compile, then we should skip flushing the output file because it |
| 466 | // will not be part of the linker line anyway. | 643 | // will not be part of the linker line anyway. |
| 467 | const module_obj_path: ?[]const u8 = if (self.base.options.module) |module| blk: { | 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 | const obj_basename = try std.zig.binNameAlloc(arena, .{ | 646 | const obj_basename = try std.zig.binNameAlloc(arena, .{ |
| 470 | .root_name = self.base.options.root_name, | 647 | .root_name = self.base.options.root_name, |
| 471 | .target = self.base.options.target, | 648 | .target = self.base.options.target, |
| ... | @@ -482,20 +659,19 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -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 | if (fs.path.dirname(full_out_path)) |dirname| { | 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 | } else { | 666 | } else { |
| 490 | break :blk obj_basename; | 667 | break :blk self.base.intermediary_basename.?; |
| 491 | } | 668 | } |
| 492 | } else null; | 669 | } else null; |
| 493 | | 670 | |
| 494 | if (self.d_sym) |*d_sym| { | 671 | var sub_prog_node = prog_node.start("MachO Flush", 0); |
| 495 | if (self.base.options.module) |module| { | 672 | sub_prog_node.activate(); |
| 496 | try d_sym.dwarf.flushModule(&self.base, module); | 673 | sub_prog_node.context.refresh(); |
| 497 | } | 674 | defer sub_prog_node.end(); |
| 498 | } | | |
| 499 | | 675 | |
| 500 | const is_lib = self.base.options.output_mode == .Lib; | 676 | const is_lib = self.base.options.output_mode == .Lib; |
| 501 | const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib; | 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,25 +679,13 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 503 | const stack_size = self.base.options.stack_size_override orelse 0; | 679 | const stack_size = self.base.options.stack_size_override orelse 0; |
| 504 | | 680 | |
| 505 | const id_symlink_basename = "zld.id"; | 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 | var man: Cache.Manifest = undefined; | 683 | var man: Cache.Manifest = undefined; |
| 517 | defer if (!self.base.options.disable_lld_caching) man.deinit(); | 684 | defer if (!self.base.options.disable_lld_caching) man.deinit(); |
| 518 | | 685 | |
| 519 | var digest: [Cache.hex_digest_len]u8 = undefined; | 686 | var digest: [Cache.hex_digest_len]u8 = undefined; |
| 520 | | 687 | |
| 521 | cache: { | 688 | if (!self.base.options.disable_lld_caching) { |
| 522 | if ((use_stage1 and self.base.options.disable_lld_caching) or self.base.options.cache_mode == .whole) | | |
| 523 | break :cache; | | |
| 524 | | | |
| 525 | man = comp.cache_parent.obtain(); | 689 | man = comp.cache_parent.obtain(); |
| 526 | | 690 | |
| 527 | // We are about to obtain this lock, so here we give other processes a chance first. | 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,7 +728,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 564 | | 728 | |
| 565 | var prev_digest_buf: [digest.len]u8 = undefined; | 729 | var prev_digest_buf: [digest.len]u8 = undefined; |
| 566 | const prev_digest: []u8 = Cache.readSmallFile( | 730 | const prev_digest: []u8 = Cache.readSmallFile( |
| 567 | cache_dir_handle, | 731 | directory.handle, |
| 568 | id_symlink_basename, | 732 | id_symlink_basename, |
| 569 | &prev_digest_buf, | 733 | &prev_digest_buf, |
| 570 | ) catch |err| blk: { | 734 | ) catch |err| blk: { |
| ... | @@ -577,15 +741,11 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -577,15 +741,11 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 577 | }; | 741 | }; |
| 578 | if (mem.eql(u8, prev_digest, &digest)) { | 742 | if (mem.eql(u8, prev_digest, &digest)) { |
| 579 | // Hot diggity dog! The output binary is already there. | 743 | // Hot diggity dog! The output binary is already there. |
| 580 | | 744 | log.debug("MachO Zld digest={s} match - skipping invocation", .{ |
| 581 | const use_llvm = build_options.have_llvm and self.base.options.use_llvm; | 745 | std.fmt.fmtSliceHexLower(&digest), |
| 582 | if (use_llvm or use_stage1) { | 746 | }); |
| 583 | log.debug("MachO Zld digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)}); | 747 | self.base.lock = man.toOwnedLock(); |
| 584 | self.base.lock = man.toOwnedLock(); | 748 | return; |
| 585 | return; | | |
| 586 | } else { | | |
| 587 | log.debug("MachO Zld digest={s} match", .{std.fmt.fmtSliceHexLower(&digest)}); | | |
| 588 | } | | |
| 589 | } | 749 | } |
| 590 | log.debug("MachO Zld prev_digest={s} new_digest={s}", .{ | 750 | log.debug("MachO Zld prev_digest={s} new_digest={s}", .{ |
| 591 | std.fmt.fmtSliceHexLower(prev_digest), | 751 | std.fmt.fmtSliceHexLower(prev_digest), |
| ... | @@ -593,7 +753,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -593,7 +753,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 593 | }); | 753 | }); |
| 594 | | 754 | |
| 595 | // We are about to change the output file to be different, so we invalidate the build hash now. | 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 | error.FileNotFound => {}, | 757 | error.FileNotFound => {}, |
| 598 | else => |e| return e, | 758 | else => |e| return e, |
| 599 | }; | 759 | }; |
| ... | @@ -624,24 +784,22 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -624,24 +784,22 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 624 | try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{}); | 784 | try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{}); |
| 625 | } | 785 | } |
| 626 | } else { | 786 | } else { |
| 627 | if (use_stage1) { | 787 | const sub_path = self.base.options.emit.?.sub_path; |
| 628 | const sub_path = self.base.options.emit.?.sub_path; | 788 | self.base.file = try directory.handle.createFile(sub_path, .{ |
| 629 | self.base.file = try cache_dir_handle.createFile(sub_path, .{ | 789 | .truncate = true, |
| 630 | .truncate = true, | 790 | .read = true, |
| 631 | .read = true, | 791 | .mode = link.determineMode(self.base.options), |
| 632 | .mode = link.determineMode(self.base.options), | 792 | }); |
| 633 | }); | 793 | // Index 0 is always a null symbol. |
| 634 | // Index 0 is always a null symbol. | 794 | try self.locals.append(self.base.allocator, .{ |
| 635 | try self.locals.append(self.base.allocator, .{ | 795 | .n_strx = 0, |
| 636 | .n_strx = 0, | 796 | .n_type = 0, |
| 637 | .n_type = 0, | 797 | .n_sect = 0, |
| 638 | .n_sect = 0, | 798 | .n_desc = 0, |
| 639 | .n_desc = 0, | 799 | .n_value = 0, |
| 640 | .n_value = 0, | 800 | }); |
| 641 | }); | 801 | try self.strtab.buffer.append(self.base.allocator, 0); |
| 642 | try self.strtab.buffer.append(self.base.allocator, 0); | 802 | try self.populateMissingMetadata(); |
| 643 | try self.populateMissingMetadata(); | | |
| 644 | } | | |
| 645 | | 803 | |
| 646 | var lib_not_found = false; | 804 | var lib_not_found = false; |
| 647 | var framework_not_found = false; | 805 | var framework_not_found = false; |
| ... | @@ -757,40 +915,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -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}. | 918 | try self.resolveLibSystem(arena, comp, lib_dirs.items, &libs); |
| 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 | } | | |
| 794 | | 919 | |
| 795 | // frameworks | 920 | // frameworks |
| 796 | var framework_dirs = std.ArrayList([]const u8).init(arena); | 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,7 +1128,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 1003 | try self.parseLibs(libs.keys(), libs.values(), self.base.options.sysroot, &dependent_libs); | 1128 | try self.parseLibs(libs.keys(), libs.values(), self.base.options.sysroot, &dependent_libs); |
| 1004 | try self.parseDependentLibs(self.base.options.sysroot, &dependent_libs); | 1129 | try self.parseDependentLibs(self.base.options.sysroot, &dependent_libs); |
| 1005 | | 1130 | |
| 1006 | try self.createMhExecuteHeaderSymbol(); | | |
| 1007 | for (self.objects.items) |*object, object_id| { | 1131 | for (self.objects.items) |*object, object_id| { |
| 1008 | try self.resolveSymbolsInObject(object, @intCast(u16, object_id)); | 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,6 +1137,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 1013 | try self.createDyldPrivateAtom(); | 1137 | try self.createDyldPrivateAtom(); |
| 1014 | try self.createStubHelperPreambleAtom(); | 1138 | try self.createStubHelperPreambleAtom(); |
| 1015 | try self.resolveSymbolsInDylibs(); | 1139 | try self.resolveSymbolsInDylibs(); |
| | 1140 | try self.createMhExecuteHeaderSymbol(); |
| 1016 | try self.createDsoHandleSymbol(); | 1141 | try self.createDsoHandleSymbol(); |
| 1017 | try self.addCodeSignatureLC(); | 1142 | try self.addCodeSignatureLC(); |
| 1018 | try self.resolveSymbolsAtLoading(); | 1143 | try self.resolveSymbolsAtLoading(); |
| ... | @@ -1029,20 +1154,15 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -1029,20 +1154,15 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 1029 | | 1154 | |
| 1030 | try self.createTentativeDefAtoms(); | 1155 | try self.createTentativeDefAtoms(); |
| 1031 | | 1156 | |
| 1032 | const use_llvm = build_options.have_llvm and self.base.options.use_llvm; | 1157 | for (self.objects.items) |*object, object_id| { |
| 1033 | if (use_llvm or use_stage1) { | 1158 | try object.splitIntoAtomsOneShot(self, @intCast(u32, object_id)); |
| 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 | | |
| 1044 | } | 1159 | } |
| 1045 | | 1160 | |
| | 1161 | try self.gcAtoms(); |
| | 1162 | try self.pruneAndSortSections(); |
| | 1163 | try self.allocateSegments(); |
| | 1164 | try self.allocateSymbols(); |
| | 1165 | |
| 1046 | try self.allocateSpecialSymbols(); | 1166 | try self.allocateSpecialSymbols(); |
| 1047 | | 1167 | |
| 1048 | if (build_options.enable_logging) { | 1168 | if (build_options.enable_logging) { |
| ... | @@ -1051,11 +1171,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -1051,11 +1171,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 1051 | self.logAtoms(); | 1171 | self.logAtoms(); |
| 1052 | } | 1172 | } |
| 1053 | | 1173 | |
| 1054 | if (use_llvm or use_stage1) { | 1174 | try self.writeAtomsOneShot(); |
| 1055 | try self.writeAtomsWhole(); | | |
| 1056 | } else { | | |
| 1057 | // try self.writeAtoms(); | | |
| 1058 | } | | |
| 1059 | | 1175 | |
| 1060 | if (self.rustc_section_index) |id| { | 1176 | if (self.rustc_section_index) |id| { |
| 1061 | const sect = self.getSectionPtr(.{ | 1177 | const sect = self.getSectionPtr(.{ |
| ... | @@ -1066,14 +1182,8 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -1066,14 +1182,8 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 1066 | } | 1182 | } |
| 1067 | | 1183 | |
| 1068 | try self.setEntryPoint(); | 1184 | try self.setEntryPoint(); |
| 1069 | try self.updateSectionOrdinals(); | | |
| 1070 | try self.writeLinkeditSegment(); | 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 | if (self.code_signature) |*csig| { | 1187 | if (self.code_signature) |*csig| { |
| 1078 | csig.clear(self.base.allocator); | 1188 | csig.clear(self.base.allocator); |
| 1079 | csig.code_directory.ident = self.base.options.emit.?.sub_path; | 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,32 +1198,17 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 1088 | try self.writeLoadCommands(); | 1198 | try self.writeLoadCommands(); |
| 1089 | try self.writeHeader(); | 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 | assert(!self.load_commands_dirty); | 1201 | assert(!self.load_commands_dirty); |
| 1100 | | 1202 | |
| 1101 | if (self.code_signature) |*csig| { | 1203 | if (self.code_signature) |*csig| { |
| 1102 | try self.writeCodeSignature(csig); // code signing always comes last | 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: { | 1208 | if (!self.base.options.disable_lld_caching) { |
| 1112 | if ((use_stage1 and self.base.options.disable_lld_caching) or self.base.options.cache_mode == .whole) | | |
| 1113 | break :cache; | | |
| 1114 | // Update the file with the digest. If it fails we can continue; it only | 1209 | // Update the file with the digest. If it fails we can continue; it only |
| 1115 | // means that the next invocation will have an unnecessary cache miss. | 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 | log.debug("failed to save linking hash digest file: {s}", .{@errorName(err)}); | 1212 | log.debug("failed to save linking hash digest file: {s}", .{@errorName(err)}); |
| 1118 | }; | 1213 | }; |
| 1119 | // Again failure here only means an unnecessary cache miss. | 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,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 | fn resolveSearchDir( | 1267 | fn resolveSearchDir( |
| 1130 | arena: Allocator, | 1268 | arena: Allocator, |
| 1131 | dir: []const u8, | 1269 | dir: []const u8, |
| ... | @@ -1168,6 +1306,16 @@ fn resolveSearchDir( | ... | @@ -1168,6 +1306,16 @@ fn resolveSearchDir( |
| 1168 | return null; | 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 | fn resolveLib( | 1319 | fn resolveLib( |
| 1172 | arena: Allocator, | 1320 | arena: Allocator, |
| 1173 | search_dir: []const u8, | 1321 | search_dir: []const u8, |
| ... | @@ -2128,6 +2276,7 @@ fn allocateSpecialSymbols(self: *MachO) !void { | ... | @@ -2128,6 +2276,7 @@ fn allocateSpecialSymbols(self: *MachO) !void { |
| 2128 | "__mh_execute_header", | 2276 | "__mh_execute_header", |
| 2129 | }) |name| { | 2277 | }) |name| { |
| 2130 | const global = self.globals.get(name) orelse continue; | 2278 | const global = self.globals.get(name) orelse continue; |
| | 2279 | if (global.file != null) continue; |
| 2131 | const sym = self.getSymbolPtr(global); | 2280 | const sym = self.getSymbolPtr(global); |
| 2132 | const seg = self.load_commands.items[self.text_segment_cmd_index.?].segment; | 2281 | const seg = self.load_commands.items[self.text_segment_cmd_index.?].segment; |
| 2133 | sym.n_sect = self.getSectionOrdinal(.{ | 2282 | sym.n_sect = self.getSectionOrdinal(.{ |
| ... | @@ -2143,7 +2292,9 @@ fn allocateSpecialSymbols(self: *MachO) !void { | ... | @@ -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 | var it = self.atoms.iterator(); | 2298 | var it = self.atoms.iterator(); |
| 2148 | while (it.next()) |entry| { | 2299 | while (it.next()) |entry| { |
| 2149 | const sect = self.getSection(entry.key_ptr.*); | 2300 | const sect = self.getSection(entry.key_ptr.*); |
| ... | @@ -2227,7 +2378,9 @@ fn writePadding(self: *MachO, match: MatchingSection, size: usize, writer: anyty | ... | @@ -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 | var it = self.atoms.iterator(); | 2384 | var it = self.atoms.iterator(); |
| 2232 | while (it.next()) |entry| { | 2385 | while (it.next()) |entry| { |
| 2233 | const match = entry.key_ptr.*; | 2386 | const match = entry.key_ptr.*; |
| ... | @@ -2240,7 +2393,7 @@ fn writeAtoms(self: *MachO) !void { | ... | @@ -2240,7 +2393,7 @@ fn writeAtoms(self: *MachO) !void { |
| 2240 | log.debug("writing atoms in {s},{s}", .{ sect.segName(), sect.sectName() }); | 2393 | log.debug("writing atoms in {s},{s}", .{ sect.segName(), sect.sectName() }); |
| 2241 | | 2394 | |
| 2242 | while (true) { | 2395 | while (true) { |
| 2243 | if (atom.dirty or self.invalidate_relocs) { | 2396 | if (atom.dirty) { |
| 2244 | try self.writeAtom(atom, match); | 2397 | try self.writeAtom(atom, match); |
| 2245 | atom.dirty = false; | 2398 | atom.dirty = false; |
| 2246 | } | 2399 | } |
| ... | @@ -2746,11 +2899,13 @@ fn createTentativeDefAtoms(self: *MachO) !void { | ... | @@ -2746,11 +2899,13 @@ fn createTentativeDefAtoms(self: *MachO) !void { |
| 2746 | | 2899 | |
| 2747 | fn createMhExecuteHeaderSymbol(self: *MachO) !void { | 2900 | fn createMhExecuteHeaderSymbol(self: *MachO) !void { |
| 2748 | if (self.base.options.output_mode != .Exe) return; | 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 | const gpa = self.base.allocator; | 2907 | const gpa = self.base.allocator; |
| 2752 | const name = try gpa.dupe(u8, "__mh_execute_header"); | 2908 | const n_strx = try self.strtab.insert(gpa, "__mh_execute_header"); |
| 2753 | const n_strx = try self.strtab.insert(gpa, name); | | |
| 2754 | const sym_index = @intCast(u32, self.locals.items.len); | 2909 | const sym_index = @intCast(u32, self.locals.items.len); |
| 2755 | try self.locals.append(gpa, .{ | 2910 | try self.locals.append(gpa, .{ |
| 2756 | .n_strx = n_strx, | 2911 | .n_strx = n_strx, |
| ... | @@ -2759,10 +2914,14 @@ fn createMhExecuteHeaderSymbol(self: *MachO) !void { | ... | @@ -2759,10 +2914,14 @@ fn createMhExecuteHeaderSymbol(self: *MachO) !void { |
| 2759 | .n_desc = 0, | 2914 | .n_desc = 0, |
| 2760 | .n_value = 0, | 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 | .sym_index = sym_index, | 2922 | .sym_index = sym_index, |
| 2764 | .file = null, | 2923 | .file = null, |
| 2765 | }); | 2924 | }; |
| 2766 | } | 2925 | } |
| 2767 | | 2926 | |
| 2768 | fn createDsoHandleSymbol(self: *MachO) !void { | 2927 | fn createDsoHandleSymbol(self: *MachO) !void { |
| ... | @@ -2787,9 +2946,68 @@ fn createDsoHandleSymbol(self: *MachO) !void { | ... | @@ -2787,9 +2946,68 @@ fn createDsoHandleSymbol(self: *MachO) !void { |
| 2787 | _ = self.unresolved.swapRemove(@intCast(u32, self.globals.getIndex("___dso_handle").?)); | 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 | const gpa = self.base.allocator; | 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 | log.debug("resolving symbols in '{s}'", .{object.name}); | 3011 | log.debug("resolving symbols in '{s}'", .{object.name}); |
| 2794 | | 3012 | |
| 2795 | for (object.symtab.items) |sym, index| { | 3013 | for (object.symtab.items) |sym, index| { |
| ... | @@ -2825,72 +3043,18 @@ fn resolveSymbolsInObject(self: *MachO, object: *Object, object_id: u16) !void { | ... | @@ -2825,72 +3043,18 @@ fn resolveSymbolsInObject(self: *MachO, object: *Object, object_id: u16) !void { |
| 2825 | continue; | 3043 | continue; |
| 2826 | } | 3044 | } |
| 2827 | | 3045 | |
| 2828 | const name = try gpa.dupe(u8, sym_name); | 3046 | const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = object_id }; |
| 2829 | const global_index = @intCast(u32, self.globals.values().len); | 3047 | self.resolveGlobalSymbol(sym_loc) catch |err| switch (err) { |
| 2830 | const gop = try self.globals.getOrPut(gpa, name); | 3048 | error.MultipleSymbolDefinitions => { |
| 2831 | defer if (gop.found_existing) gpa.free(name); | 3049 | const global = self.globals.get(sym_name).?; |
| 2832 | | 3050 | log.err("symbol '{s}' defined multiple times", .{sym_name}); |
| 2833 | if (!gop.found_existing) { | 3051 | if (global.file) |file| { |
| 2834 | gop.value_ptr.* = .{ | 3052 | log.err(" first definition in '{s}'", .{self.objects.items[file].name}); |
| 2835 | .sym_index = sym_index, | 3053 | } |
| 2836 | .file = object_id, | 3054 | log.err(" next definition in '{s}'", .{self.objects.items[object_id].name}); |
| 2837 | }; | 3055 | return error.MultipleSymbolDefinitions; |
| 2838 | if (sym.undf() and !sym.tentative()) { | 3056 | }, |
| 2839 | try self.unresolved.putNoClobber(gpa, global_index, {}); | 3057 | else => |e| return e, |
| 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, | | |
| 2894 | }; | 3058 | }; |
| 2895 | } | 3059 | } |
| 2896 | } | 3060 | } |
| ... | @@ -2950,7 +3114,18 @@ fn resolveSymbolsInDylibs(self: *MachO) !void { | ... | @@ -2950,7 +3114,18 @@ fn resolveSymbolsInDylibs(self: *MachO) !void { |
| 2950 | sym.n_desc |= macho.N_WEAK_REF; | 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 | continue :loop; | 3130 | continue :loop; |
| 2956 | } | 3131 | } |
| ... | @@ -3272,7 +3447,7 @@ fn growAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, match | ... | @@ -3272,7 +3447,7 @@ fn growAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, match |
| 3272 | return self.allocateAtom(atom, new_atom_size, alignment, match); | 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 | try self.locals.ensureUnusedCapacity(self.base.allocator, 1); | 3451 | try self.locals.ensureUnusedCapacity(self.base.allocator, 1); |
| 3277 | | 3452 | |
| 3278 | const index = blk: { | 3453 | const index = blk: { |
| ... | @@ -3366,12 +3541,9 @@ pub fn allocateDeclIndexes(self: *MachO, decl_index: Module.Decl.Index) !void { | ... | @@ -3366,12 +3541,9 @@ pub fn allocateDeclIndexes(self: *MachO, decl_index: Module.Decl.Index) !void { |
| 3366 | const decl = self.base.options.module.?.declPtr(decl_index); | 3541 | const decl = self.base.options.module.?.declPtr(decl_index); |
| 3367 | if (decl.link.macho.sym_index != 0) return; | 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 | try self.atom_by_index_table.putNoClobber(self.base.allocator, decl.link.macho.sym_index, &decl.link.macho); | 3545 | try self.atom_by_index_table.putNoClobber(self.base.allocator, decl.link.macho.sym_index, &decl.link.macho); |
| 3371 | try self.decls.putNoClobber(self.base.allocator, decl_index, null); | 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 | pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { | 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,7 +3640,7 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu |
| 3468 | log.debug("allocating symbol indexes for {s}", .{name}); | 3640 | log.debug("allocating symbol indexes for {s}", .{name}); |
| 3469 | | 3641 | |
| 3470 | const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); | 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 | const atom = try MachO.createEmptyAtom( | 3644 | const atom = try MachO.createEmptyAtom( |
| 3473 | gpa, | 3645 | gpa, |
| 3474 | sym_index, | 3646 | sym_index, |
| ... | @@ -3787,6 +3959,12 @@ fn placeDecl(self: *MachO, decl_index: Module.Decl.Index, code_len: usize) !*mac | ... | @@ -3787,6 +3959,12 @@ fn placeDecl(self: *MachO, decl_index: Module.Decl.Index, code_len: usize) !*mac |
| 3787 | log.debug("growing {s} and moving from 0x{x} to 0x{x}", .{ sym_name, symbol.n_value, vaddr }); | 3959 | log.debug("growing {s} and moving from 0x{x} to 0x{x}", .{ sym_name, symbol.n_value, vaddr }); |
| 3788 | log.debug(" (required alignment 0x{x})", .{required_alignment}); | 3960 | log.debug(" (required alignment 0x{x})", .{required_alignment}); |
| 3789 | symbol.n_value = vaddr; | 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 | } else if (code_len < decl.link.macho.size) { | 3968 | } else if (code_len < decl.link.macho.size) { |
| 3791 | self.shrinkAtom(&decl.link.macho, code_len, match); | 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,11 +3992,8 @@ fn placeDecl(self: *MachO, decl_index: Module.Decl.Index, code_len: usize) !*mac |
| 3814 | .n_value = addr, | 3992 | .n_value = addr, |
| 3815 | }; | 3993 | }; |
| 3816 | | 3994 | |
| 3817 | const got_target = SymbolWithLoc{ | 3995 | const got_target = SymbolWithLoc{ .sym_index = decl.link.macho.sym_index, .file = null }; |
| 3818 | .sym_index = decl.link.macho.sym_index, | 3996 | const got_index = try self.allocateGotEntry(got_target); |
| 3819 | .file = null, | | |
| 3820 | }; | | |
| 3821 | const got_index = self.got_entries_table.get(got_target).?; | | |
| 3822 | const got_atom = try self.createGotAtom(got_target); | 3997 | const got_atom = try self.createGotAtom(got_target); |
| 3823 | self.got_entries.items[got_index].atom = got_atom; | 3998 | self.got_entries.items[got_index].atom = got_atom; |
| 3824 | } | 3999 | } |
| ... | @@ -3843,19 +4018,23 @@ pub fn updateDeclExports( | ... | @@ -3843,19 +4018,23 @@ pub fn updateDeclExports( |
| 3843 | @panic("Attempted to compile for object format that was disabled by build configuration"); | 4018 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 3844 | } | 4019 | } |
| 3845 | if (build_options.have_llvm) { | 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 | const tracy = trace(@src()); | 4024 | const tracy = trace(@src()); |
| 3849 | defer tracy.end(); | 4025 | defer tracy.end(); |
| 3850 | | 4026 | |
| 3851 | try self.globals.ensureUnusedCapacity(self.base.allocator, exports.len); | 4027 | const gpa = self.base.allocator; |
| | 4028 | |
| 3852 | const decl = module.declPtr(decl_index); | 4029 | const decl = module.declPtr(decl_index); |
| 3853 | if (decl.link.macho.sym_index == 0) return; | 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 | for (exports) |exp| { | 4033 | for (exports) |exp| { |
| 3857 | const exp_name = try std.fmt.allocPrint(self.base.allocator, "_{s}", .{exp.options.name}); | 4034 | const exp_name = try std.fmt.allocPrint(gpa, "_{s}", .{exp.options.name}); |
| 3858 | defer self.base.allocator.free(exp_name); | 4035 | defer gpa.free(exp_name); |
| | 4036 | |
| | 4037 | log.debug("adding new export '{s}'", .{exp_name}); |
| 3859 | | 4038 | |
| 3860 | if (exp.options.section) |section_name| { | 4039 | if (exp.options.section) |section_name| { |
| 3861 | if (!mem.eql(u8, section_name, "__text")) { | 4040 | if (!mem.eql(u8, section_name, "__text")) { |
| ... | @@ -3863,7 +4042,7 @@ pub fn updateDeclExports( | ... | @@ -3863,7 +4042,7 @@ pub fn updateDeclExports( |
| 3863 | module.gpa, | 4042 | module.gpa, |
| 3864 | exp, | 4043 | exp, |
| 3865 | try Module.ErrorMsg.create( | 4044 | try Module.ErrorMsg.create( |
| 3866 | self.base.allocator, | 4045 | gpa, |
| 3867 | decl.srcLoc(), | 4046 | decl.srcLoc(), |
| 3868 | "Unimplemented: ExportOptions.section", | 4047 | "Unimplemented: ExportOptions.section", |
| 3869 | .{}, | 4048 | .{}, |
| ... | @@ -3878,7 +4057,7 @@ pub fn updateDeclExports( | ... | @@ -3878,7 +4057,7 @@ pub fn updateDeclExports( |
| 3878 | module.gpa, | 4057 | module.gpa, |
| 3879 | exp, | 4058 | exp, |
| 3880 | try Module.ErrorMsg.create( | 4059 | try Module.ErrorMsg.create( |
| 3881 | self.base.allocator, | 4060 | gpa, |
| 3882 | decl.srcLoc(), | 4061 | decl.srcLoc(), |
| 3883 | "Unimplemented: GlobalLinkage.LinkOnce", | 4062 | "Unimplemented: GlobalLinkage.LinkOnce", |
| 3884 | .{}, | 4063 | .{}, |
| ... | @@ -3887,107 +4066,84 @@ pub fn updateDeclExports( | ... | @@ -3887,107 +4066,84 @@ pub fn updateDeclExports( |
| 3887 | continue; | 4066 | continue; |
| 3888 | } | 4067 | } |
| 3889 | | 4068 | |
| 3890 | const is_weak = exp.options.linkage == .Internal or exp.options.linkage == .Weak; | 4069 | const sym_index = exp.link.macho.sym_index orelse blk: { |
| 3891 | _ = is_weak; | 4070 | const sym_index = try self.allocateSymbol(); |
| 3892 | const n_strx = try self.strtab.insert(self.base.allocator, exp_name); | 4071 | exp.link.macho.sym_index = sym_index; |
| 3893 | // if (self.symbol_resolver.getPtr(n_strx)) |resolv| { | 4072 | break :blk sym_index; |
| 3894 | // switch (resolv.where) { | 4073 | }; |
| 3895 | // .global => { | 4074 | const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null }; |
| 3896 | // if (resolv.sym_index == decl.link.macho.sym_index) continue; | 4075 | const sym = self.getSymbolPtr(sym_loc); |
| 3897 | | 4076 | sym.* = .{ |
| 3898 | // const sym = &self.globals.items[resolv.where_index]; | 4077 | .n_strx = try self.strtab.insert(gpa, exp_name), |
| 3899 | | 4078 | .n_type = macho.N_SECT | macho.N_EXT, |
| 3900 | // if (sym.tentative()) { | 4079 | .n_sect = self.getSectionOrdinal(.{ |
| 3901 | // assert(self.tentatives.swapRemove(resolv.where_index)); | 4080 | .seg = self.text_segment_cmd_index.?, |
| 3902 | // } else if (!is_weak and !(sym.weakDef() or sym.pext())) { | 4081 | .sect = self.text_section_index.?, // TODO what if we export a variable? |
| 3903 | // _ = try module.failed_exports.put( | 4082 | }), |
| 3904 | // module.gpa, | 4083 | .n_desc = 0, |
| 3905 | // exp, | 4084 | .n_value = decl_sym.n_value, |
| 3906 | // try Module.ErrorMsg.create( | 4085 | }; |
| 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; | | |
| 3935 | | 4086 | |
| 3936 | switch (exp.options.linkage) { | 4087 | switch (exp.options.linkage) { |
| 3937 | .Internal => { | 4088 | .Internal => { |
| 3938 | // Symbol should be hidden, or in MachO lingo, private extern. | 4089 | // Symbol should be hidden, or in MachO lingo, private extern. |
| 3939 | // We should also mark the symbol as Weak: n_desc == N_WEAK_DEF. | 4090 | // We should also mark the symbol as Weak: n_desc == N_WEAK_DEF. |
| 3940 | // TODO work out when to add N_WEAK_REF. | 4091 | sym.n_type |= macho.N_PEXT; |
| 3941 | n_type |= macho.N_PEXT; | 4092 | sym.n_desc |= macho.N_WEAK_DEF; |
| 3942 | n_desc |= macho.N_WEAK_DEF; | | |
| 3943 | }, | 4093 | }, |
| 3944 | .Strong => {}, | 4094 | .Strong => {}, |
| 3945 | .Weak => { | 4095 | .Weak => { |
| 3946 | // Weak linkage is specified as part of n_desc field. | 4096 | // Weak linkage is specified as part of n_desc field. |
| 3947 | // Symbol's n_type is like for a symbol with strong linkage. | 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 | else => unreachable, | 4100 | else => unreachable, |
| 3951 | } | 4101 | } |
| 3952 | | 4102 | |
| 3953 | const global_sym_index: u32 = 0; | 4103 | self.resolveGlobalSymbol(sym_loc) catch |err| switch (err) { |
| 3954 | // const global_sym_index = if (exp.link.macho.sym_index) |i| i else blk: { | 4104 | error.MultipleSymbolDefinitions => { |
| 3955 | // const i = if (self.globals_free_list.popOrNull()) |i| i else inner: { | 4105 | const global = self.globals.get(exp_name).?; |
| 3956 | // _ = self.globals.addOneAssumeCapacity(); | 4106 | if (sym_loc.sym_index != global.sym_index and global.file != null) { |
| 3957 | // break :inner @intCast(u32, self.globals.items.len - 1); | 4107 | _ = try module.failed_exports.put(module.gpa, exp, try Module.ErrorMsg.create( |
| 3958 | // }; | 4108 | gpa, |
| 3959 | // break :blk i; | 4109 | decl.srcLoc(), |
| 3960 | // }; | 4110 | \\LinkError: symbol '{s}' defined multiple times |
| 3961 | const sym = &self.locals.items[global_sym_index]; | 4111 | \\ first definition in '{s}' |
| 3962 | sym.* = .{ | 4112 | , |
| 3963 | .n_strx = try self.strtab.insert(self.base.allocator, exp_name), | 4113 | .{ exp_name, self.objects.items[global.file.?].name }, |
| 3964 | .n_type = n_type, | 4114 | )); |
| 3965 | .n_sect = @intCast(u8, self.text_section_index.?) + 1, | 4115 | } |
| 3966 | .n_desc = n_desc, | 4116 | }, |
| 3967 | .n_value = decl_sym.n_value, | 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 | pub fn deleteExport(self: *MachO, exp: Export) void { | 4122 | pub fn deleteExport(self: *MachO, exp: Export) void { |
| 3981 | if (self.llvm_object) |_| return; | 4123 | if (self.llvm_object) |_| return; |
| 3982 | const sym_index = exp.sym_index orelse return; | 4124 | const sym_index = exp.sym_index orelse return; |
| 3983 | _ = sym_index; | 4125 | |
| 3984 | // self.globals_free_list.append(self.base.allocator, sym_index) catch {}; | 4126 | const gpa = self.base.allocator; |
| 3985 | // const global = &self.globals.items[sym_index]; | 4127 | |
| 3986 | // log.warn("deleting export '{s}': {}", .{ self.getString(global.n_strx), global }); | 4128 | const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null }; |
| 3987 | // assert(self.symbol_resolver.remove(global.n_strx)); | 4129 | const sym = self.getSymbolPtr(sym_loc); |
| 3988 | // global.n_type = 0; | 4130 | const sym_name = self.getSymbolName(sym_loc); |
| 3989 | // global.n_strx = 0; | 4131 | log.debug("deleting export '{s}'", .{sym_name}); |
| 3990 | // global.n_value = 0; | 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 | fn freeUnnamedConsts(self: *MachO, decl_index: Module.Decl.Index) void { | 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,7 +4182,10 @@ pub fn freeDecl(self: *MachO, decl_index: Module.Decl.Index) void { |
| 4026 | const got_target = SymbolWithLoc{ .sym_index = decl.link.macho.sym_index, .file = null }; | 4182 | const got_target = SymbolWithLoc{ .sym_index = decl.link.macho.sym_index, .file = null }; |
| 4027 | if (self.got_entries_table.get(got_target)) |got_index| { | 4183 | if (self.got_entries_table.get(got_target)) |got_index| { |
| 4028 | self.got_entries_free_list.append(self.base.allocator, @intCast(u32, got_index)) catch {}; | 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 | _ = self.got_entries_table.swapRemove(got_target); | 4189 | _ = self.got_entries_table.swapRemove(got_target); |
| 4031 | | 4190 | |
| 4032 | if (self.d_sym) |*d_sym| { | 4191 | if (self.d_sym) |*d_sym| { |
| ... | @@ -4102,7 +4261,7 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4102,7 +4261,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4102 | | 4261 | |
| 4103 | if (self.text_segment_cmd_index == null) { | 4262 | if (self.text_segment_cmd_index == null) { |
| 4104 | self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len); | 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 | const headerpad_size = @maximum(self.base.options.headerpad_size orelse 0, default_headerpad_size); | 4265 | const headerpad_size = @maximum(self.base.options.headerpad_size orelse 0, default_headerpad_size); |
| 4107 | const program_code_size_hint = self.base.options.program_code_size_hint; | 4266 | const program_code_size_hint = self.base.options.program_code_size_hint; |
| 4108 | const got_size_hint = @sizeOf(u64) * self.base.options.symbol_count_hint; | 4267 | const got_size_hint = @sizeOf(u64) * self.base.options.symbol_count_hint; |
| ... | @@ -4133,7 +4292,7 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4133,7 +4292,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4133 | .aarch64 => 2, | 4292 | .aarch64 => 2, |
| 4134 | else => unreachable, // unhandled architecture type | 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 | self.text_section_index = try self.initSection( | 4296 | self.text_section_index = try self.initSection( |
| 4138 | self.text_segment_cmd_index.?, | 4297 | self.text_segment_cmd_index.?, |
| 4139 | "__text", | 4298 | "__text", |
| ... | @@ -4156,7 +4315,7 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4156,7 +4315,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4156 | .aarch64 => 3 * @sizeOf(u32), | 4315 | .aarch64 => 3 * @sizeOf(u32), |
| 4157 | else => unreachable, // unhandled architecture type | 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 | self.stubs_section_index = try self.initSection( | 4319 | self.stubs_section_index = try self.initSection( |
| 4161 | self.text_segment_cmd_index.?, | 4320 | self.text_segment_cmd_index.?, |
| 4162 | "__stubs", | 4321 | "__stubs", |
| ... | @@ -4185,7 +4344,7 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4185,7 +4344,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4185 | .aarch64 => 3 * @sizeOf(u32), | 4344 | .aarch64 => 3 * @sizeOf(u32), |
| 4186 | else => unreachable, | 4345 | else => unreachable, |
| 4187 | }; | 4346 | }; |
| 4188 | const needed_size = if (self.needs_prealloc) | 4347 | const needed_size = if (self.mode == .incremental) |
| 4189 | stub_size * self.base.options.symbol_count_hint + preamble_size | 4348 | stub_size * self.base.options.symbol_count_hint + preamble_size |
| 4190 | else | 4349 | else |
| 4191 | 0; | 4350 | 0; |
| ... | @@ -4205,7 +4364,7 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4205,7 +4364,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4205 | var vmaddr: u64 = 0; | 4364 | var vmaddr: u64 = 0; |
| 4206 | var fileoff: u64 = 0; | 4365 | var fileoff: u64 = 0; |
| 4207 | var needed_size: u64 = 0; | 4366 | var needed_size: u64 = 0; |
| 4208 | if (self.needs_prealloc) { | 4367 | if (self.mode == .incremental) { |
| 4209 | const base = self.getSegmentAllocBase(&.{self.text_segment_cmd_index.?}); | 4368 | const base = self.getSegmentAllocBase(&.{self.text_segment_cmd_index.?}); |
| 4210 | vmaddr = base.vmaddr; | 4369 | vmaddr = base.vmaddr; |
| 4211 | fileoff = base.fileoff; | 4370 | fileoff = base.fileoff; |
| ... | @@ -4234,7 +4393,7 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4234,7 +4393,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4234 | } | 4393 | } |
| 4235 | | 4394 | |
| 4236 | if (self.got_section_index == null) { | 4395 | if (self.got_section_index == null) { |
| 4237 | const needed_size = if (self.needs_prealloc) | 4396 | const needed_size = if (self.mode == .incremental) |
| 4238 | @sizeOf(u64) * self.base.options.symbol_count_hint | 4397 | @sizeOf(u64) * self.base.options.symbol_count_hint |
| 4239 | else | 4398 | else |
| 4240 | 0; | 4399 | 0; |
| ... | @@ -4255,7 +4414,7 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4255,7 +4414,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4255 | var vmaddr: u64 = 0; | 4414 | var vmaddr: u64 = 0; |
| 4256 | var fileoff: u64 = 0; | 4415 | var fileoff: u64 = 0; |
| 4257 | var needed_size: u64 = 0; | 4416 | var needed_size: u64 = 0; |
| 4258 | if (self.needs_prealloc) { | 4417 | if (self.mode == .incremental) { |
| 4259 | const base = self.getSegmentAllocBase(&.{self.data_const_segment_cmd_index.?}); | 4418 | const base = self.getSegmentAllocBase(&.{self.data_const_segment_cmd_index.?}); |
| 4260 | vmaddr = base.vmaddr; | 4419 | vmaddr = base.vmaddr; |
| 4261 | fileoff = base.fileoff; | 4420 | fileoff = base.fileoff; |
| ... | @@ -4284,7 +4443,7 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4284,7 +4443,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4284 | } | 4443 | } |
| 4285 | | 4444 | |
| 4286 | if (self.la_symbol_ptr_section_index == null) { | 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 | @sizeOf(u64) * self.base.options.symbol_count_hint | 4447 | @sizeOf(u64) * self.base.options.symbol_count_hint |
| 4289 | else | 4448 | else |
| 4290 | 0; | 4449 | 0; |
| ... | @@ -4301,7 +4460,10 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4301,7 +4460,10 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4301 | } | 4460 | } |
| 4302 | | 4461 | |
| 4303 | if (self.data_section_index == null) { | 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 | const alignment: u16 = 3; // 2^3 = @sizeOf(u64) | 4467 | const alignment: u16 = 3; // 2^3 = @sizeOf(u64) |
| 4306 | self.data_section_index = try self.initSection( | 4468 | self.data_section_index = try self.initSection( |
| 4307 | self.data_segment_cmd_index.?, | 4469 | self.data_segment_cmd_index.?, |
| ... | @@ -4313,7 +4475,10 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4313,7 +4475,10 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4313 | } | 4475 | } |
| 4314 | | 4476 | |
| 4315 | if (self.tlv_section_index == null) { | 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 | const alignment: u16 = 3; // 2^3 = @sizeOf(u64) | 4482 | const alignment: u16 = 3; // 2^3 = @sizeOf(u64) |
| 4318 | self.tlv_section_index = try self.initSection( | 4483 | self.tlv_section_index = try self.initSection( |
| 4319 | self.data_segment_cmd_index.?, | 4484 | self.data_segment_cmd_index.?, |
| ... | @@ -4327,7 +4492,10 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4327,7 +4492,10 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4327 | } | 4492 | } |
| 4328 | | 4493 | |
| 4329 | if (self.tlv_data_section_index == null) { | 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 | const alignment: u16 = 3; // 2^3 = @sizeOf(u64) | 4499 | const alignment: u16 = 3; // 2^3 = @sizeOf(u64) |
| 4332 | self.tlv_data_section_index = try self.initSection( | 4500 | self.tlv_data_section_index = try self.initSection( |
| 4333 | self.data_segment_cmd_index.?, | 4501 | self.data_segment_cmd_index.?, |
| ... | @@ -4341,7 +4509,10 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4341,7 +4509,10 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4341 | } | 4509 | } |
| 4342 | | 4510 | |
| 4343 | if (self.tlv_bss_section_index == null) { | 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 | const alignment: u16 = 3; // 2^3 = @sizeOf(u64) | 4516 | const alignment: u16 = 3; // 2^3 = @sizeOf(u64) |
| 4346 | self.tlv_bss_section_index = try self.initSection( | 4517 | self.tlv_bss_section_index = try self.initSection( |
| 4347 | self.data_segment_cmd_index.?, | 4518 | self.data_segment_cmd_index.?, |
| ... | @@ -4355,7 +4526,10 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4355,7 +4526,10 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4355 | } | 4526 | } |
| 4356 | | 4527 | |
| 4357 | if (self.bss_section_index == null) { | 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 | const alignment: u16 = 3; // 2^3 = @sizeOf(u64) | 4533 | const alignment: u16 = 3; // 2^3 = @sizeOf(u64) |
| 4360 | self.bss_section_index = try self.initSection( | 4534 | self.bss_section_index = try self.initSection( |
| 4361 | self.data_segment_cmd_index.?, | 4535 | self.data_segment_cmd_index.?, |
| ... | @@ -4372,7 +4546,7 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4372,7 +4546,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4372 | self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len); | 4546 | self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 4373 | var vmaddr: u64 = 0; | 4547 | var vmaddr: u64 = 0; |
| 4374 | var fileoff: u64 = 0; | 4548 | var fileoff: u64 = 0; |
| 4375 | if (self.needs_prealloc) { | 4549 | if (self.mode == .incremental) { |
| 4376 | const base = self.getSegmentAllocBase(&.{self.data_segment_cmd_index.?}); | 4550 | const base = self.getSegmentAllocBase(&.{self.data_segment_cmd_index.?}); |
| 4377 | vmaddr = base.vmaddr; | 4551 | vmaddr = base.vmaddr; |
| 4378 | fileoff = base.fileoff; | 4552 | fileoff = base.fileoff; |
| ... | @@ -4740,14 +4914,14 @@ fn initSection( | ... | @@ -4740,14 +4914,14 @@ fn initSection( |
| 4740 | var sect = macho.section_64{ | 4914 | var sect = macho.section_64{ |
| 4741 | .sectname = makeStaticString(sectname), | 4915 | .sectname = makeStaticString(sectname), |
| 4742 | .segname = seg.inner.segname, | 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 | .@"align" = alignment, | 4918 | .@"align" = alignment, |
| 4745 | .flags = opts.flags, | 4919 | .flags = opts.flags, |
| 4746 | .reserved1 = opts.reserved1, | 4920 | .reserved1 = opts.reserved1, |
| 4747 | .reserved2 = opts.reserved2, | 4921 | .reserved2 = opts.reserved2, |
| 4748 | }; | 4922 | }; |
| 4749 | | 4923 | |
| 4750 | if (self.needs_prealloc) { | 4924 | if (self.mode == .incremental) { |
| 4751 | const alignment_pow_2 = try math.powi(u32, 2, alignment); | 4925 | const alignment_pow_2 = try math.powi(u32, 2, alignment); |
| 4752 | const padding: ?u32 = if (segment_id == self.text_segment_cmd_index.?) | 4926 | const padding: ?u32 = if (segment_id == self.text_segment_cmd_index.?) |
| 4753 | @maximum(self.base.options.headerpad_size orelse 0, default_headerpad_size) | 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,7 +5141,7 @@ fn getSectionMaxAlignment(self: *MachO, segment_id: u16, start_sect_id: u16) !u3 |
| 4967 | | 5141 | |
| 4968 | fn allocateAtomCommon(self: *MachO, atom: *Atom, match: MatchingSection) !void { | 5142 | fn allocateAtomCommon(self: *MachO, atom: *Atom, match: MatchingSection) !void { |
| 4969 | const sym = atom.getSymbolPtr(self); | 5143 | const sym = atom.getSymbolPtr(self); |
| 4970 | if (self.needs_prealloc) { | 5144 | if (self.mode == .incremental) { |
| 4971 | const size = atom.size; | 5145 | const size = atom.size; |
| 4972 | const alignment = try math.powi(u32, 2, atom.alignment); | 5146 | const alignment = try math.powi(u32, 2, atom.alignment); |
| 4973 | const vaddr = try self.allocateAtom(atom, size, alignment, match); | 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,27 +5282,29 @@ pub fn addAtomToSection(self: *MachO, atom: *Atom, match: MatchingSection) !void |
| 5108 | pub fn getGlobalSymbol(self: *MachO, name: []const u8) !u32 { | 5282 | pub fn getGlobalSymbol(self: *MachO, name: []const u8) !u32 { |
| 5109 | const gpa = self.base.allocator; | 5283 | const gpa = self.base.allocator; |
| 5110 | const sym_name = try std.fmt.allocPrint(gpa, "_{s}", .{name}); | 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| { | 5289 | if (gop.found_existing) { |
| 5114 | return @intCast(u32, global_index); | 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 | const sym_index = @intCast(u32, self.locals.items.len); | 5293 | const sym_index = @intCast(u32, self.locals.items.len); |
| 5119 | try self.locals.append(gpa, .{ | 5294 | try self.locals.append(gpa, .{ |
| 5120 | .n_strx = n_strx, | 5295 | .n_strx = try self.strtab.insert(gpa, sym_name), |
| 5121 | .n_type = macho.N_UNDF, | 5296 | .n_type = macho.N_UNDF, |
| 5122 | .n_sect = 0, | 5297 | .n_sect = 0, |
| 5123 | .n_desc = 0, | 5298 | .n_desc = 0, |
| 5124 | .n_value = 0, | 5299 | .n_value = 0, |
| 5125 | }); | 5300 | }); |
| 5126 | try self.globals.putNoClobber(gpa, sym_name, .{ | 5301 | gop.value_ptr.* = .{ |
| 5127 | .sym_index = sym_index, | 5302 | .sym_index = sym_index, |
| 5128 | .file = null, | 5303 | .file = null, |
| 5129 | }); | 5304 | }; |
| 5130 | const global_index = self.globals.getIndex(sym_name).?; | 5305 | try self.unresolved.putNoClobber(gpa, global_index, true); |
| 5131 | return @intCast(u32, global_index); | 5306 | |
| | 5307 | return global_index; |
| 5132 | } | 5308 | } |
| 5133 | | 5309 | |
| 5134 | fn getSegmentAllocBase(self: MachO, indices: []const ?u16) struct { vmaddr: u64, fileoff: u64 } { | 5310 | fn getSegmentAllocBase(self: MachO, indices: []const ?u16) struct { vmaddr: u64, fileoff: u64 } { |
| ... | @@ -5927,7 +6103,7 @@ fn writeDices(self: *MachO) !void { | ... | @@ -5927,7 +6103,7 @@ fn writeDices(self: *MachO) !void { |
| 5927 | self.load_commands_dirty = true; | 6103 | self.load_commands_dirty = true; |
| 5928 | } | 6104 | } |
| 5929 | | 6105 | |
| 5930 | fn writeSymbolTable(self: *MachO) !void { | 6106 | fn writeSymtab(self: *MachO) !void { |
| 5931 | const tracy = trace(@src()); | 6107 | const tracy = trace(@src()); |
| 5932 | defer tracy.end(); | 6108 | defer tracy.end(); |
| 5933 | | 6109 | |
| ... | @@ -6143,7 +6319,7 @@ fn writeSymbolTable(self: *MachO) !void { | ... | @@ -6143,7 +6319,7 @@ fn writeSymbolTable(self: *MachO) !void { |
| 6143 | self.load_commands_dirty = true; | 6319 | self.load_commands_dirty = true; |
| 6144 | } | 6320 | } |
| 6145 | | 6321 | |
| 6146 | fn writeStringTable(self: *MachO) !void { | 6322 | fn writeStrtab(self: *MachO) !void { |
| 6147 | const tracy = trace(@src()); | 6323 | const tracy = trace(@src()); |
| 6148 | defer tracy.end(); | 6324 | defer tracy.end(); |
| 6149 | | 6325 | |
| ... | @@ -6173,8 +6349,8 @@ fn writeLinkeditSegment(self: *MachO) !void { | ... | @@ -6173,8 +6349,8 @@ fn writeLinkeditSegment(self: *MachO) !void { |
| 6173 | try self.writeDyldInfoData(); | 6349 | try self.writeDyldInfoData(); |
| 6174 | try self.writeFunctionStarts(); | 6350 | try self.writeFunctionStarts(); |
| 6175 | try self.writeDices(); | 6351 | try self.writeDices(); |
| 6176 | try self.writeSymbolTable(); | 6352 | try self.writeSymtab(); |
| 6177 | try self.writeStringTable(); | 6353 | try self.writeStrtab(); |
| 6178 | | 6354 | |
| 6179 | seg.inner.vmsize = mem.alignForwardGeneric(u64, seg.inner.filesize, self.page_size); | 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,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 | pub fn findFirst(comptime T: type, haystack: []const T, start: usize, predicate: anytype) usize { | 6591 | pub fn findFirst(comptime T: type, haystack: []const T, start: usize, predicate: anytype) usize { |
| 6395 | if (!@hasDecl(@TypeOf(predicate), "predicate")) | 6592 | if (!@hasDecl(@TypeOf(predicate), "predicate")) |
| 6396 | @compileError("Predicate is required to define fn predicate(@This(), T) bool"); | 6593 | @compileError("Predicate is required to define fn predicate(@This(), T) bool"); |
| ... | @@ -6481,6 +6678,8 @@ fn snapshotState(self: *MachO) !void { | ... | @@ -6481,6 +6678,8 @@ fn snapshotState(self: *MachO) !void { |
| 6481 | .payload = .{ .name = sect_name }, | 6678 | .payload = .{ .name = sect_name }, |
| 6482 | }); | 6679 | }); |
| 6483 | | 6680 | |
| | 6681 | const is_tlv = sect.type_() == macho.S_THREAD_LOCAL_VARIABLES; |
| | 6682 | |
| 6484 | var atom: *Atom = self.atoms.get(key) orelse { | 6683 | var atom: *Atom = self.atoms.get(key) orelse { |
| 6485 | try nodes.append(.{ | 6684 | try nodes.append(.{ |
| 6486 | .address = sect.addr + sect.size, | 6685 | .address = sect.addr + sect.size, |
| ... | @@ -6495,35 +6694,23 @@ fn snapshotState(self: *MachO) !void { | ... | @@ -6495,35 +6694,23 @@ fn snapshotState(self: *MachO) !void { |
| 6495 | } | 6694 | } |
| 6496 | | 6695 | |
| 6497 | while (true) { | 6696 | while (true) { |
| 6498 | const atom_sym = self.locals.items[atom.sym_index]; | 6697 | const atom_sym = atom.getSymbol(self); |
| 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 | | | |
| 6514 | var node = Snapshot.Node{ | 6698 | var node = Snapshot.Node{ |
| 6515 | .address = atom_sym.n_value, | 6699 | .address = atom_sym.n_value, |
| 6516 | .tag = .atom_start, | 6700 | .tag = .atom_start, |
| 6517 | .payload = .{ | 6701 | .payload = .{ |
| 6518 | .name = self.getString(atom_sym.n_strx), | 6702 | .name = atom.getName(self), |
| 6519 | .is_global = self.symbol_resolver.contains(atom_sym.n_strx), | 6703 | .is_global = self.globals.contains(atom.getName(self)), |
| 6520 | }, | 6704 | }, |
| 6521 | }; | 6705 | }; |
| 6522 | | 6706 | |
| 6523 | var aliases = std.ArrayList([]const u8).init(arena); | 6707 | var aliases = std.ArrayList([]const u8).init(arena); |
| 6524 | for (atom.contained.items) |sym_off| { | 6708 | for (atom.contained.items) |sym_off| { |
| 6525 | if (sym_off.offset == 0) { | 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 | node.payload.aliases = aliases.toOwnedSlice(); | 6716 | node.payload.aliases = aliases.toOwnedSlice(); |
| ... | @@ -6531,69 +6718,39 @@ fn snapshotState(self: *MachO) !void { | ... | @@ -6531,69 +6718,39 @@ fn snapshotState(self: *MachO) !void { |
| 6531 | | 6718 | |
| 6532 | var relocs = try std.ArrayList(Snapshot.Node).initCapacity(arena, atom.relocs.items.len); | 6719 | var relocs = try std.ArrayList(Snapshot.Node).initCapacity(arena, atom.relocs.items.len); |
| 6533 | for (atom.relocs.items) |rel| { | 6720 | for (atom.relocs.items) |rel| { |
| 6534 | const arch = self.base.options.target.cpu.arch; | | |
| 6535 | const source_addr = blk: { | 6721 | const source_addr = blk: { |
| 6536 | const sym = self.locals.items[atom.sym_index]; | 6722 | const source_sym = atom.getSymbol(self); |
| 6537 | break :blk sym.n_value + rel.offset; | 6723 | break :blk source_sym.n_value + rel.offset; |
| 6538 | }; | 6724 | }; |
| 6539 | const target_addr = blk: { | 6725 | const target_addr = blk: { |
| 6540 | const is_via_got = got: { | 6726 | const target_atom = (try rel.getTargetAtom(self)) orelse { |
| 6541 | switch (arch) { | 6727 | // If there is no atom for target, we still need to check for special, atom-less |
| 6542 | .aarch64 => break :got switch (@intToEnum(macho.reloc_type_arm64, rel.@"type")) { | 6728 | // symbols such as `___dso_handle`. |
| 6543 | .ARM64_RELOC_GOT_LOAD_PAGE21, .ARM64_RELOC_GOT_LOAD_PAGEOFF12 => true, | 6729 | const target_name = self.getSymbolName(rel.target); |
| 6544 | else => false, | 6730 | if (self.globals.contains(target_name)) { |
| 6545 | }, | 6731 | const atomless_sym = self.getSymbol(rel.target); |
| 6546 | .x86_64 => break :got switch (@intToEnum(macho.reloc_type_x86_64, rel.@"type")) { | 6732 | break :blk atomless_sym.n_value; |
| 6547 | .X86_64_RELOC_GOT, .X86_64_RELOC_GOT_LOAD => true, | | |
| 6548 | else => false, | | |
| 6549 | }, | | |
| 6550 | else => unreachable, | | |
| 6551 | } | 6733 | } |
| | 6734 | break :blk 0; |
| 6552 | }; | 6735 | }; |
| 6553 | | 6736 | const target_sym = if (target_atom.isSymbolContained(rel.target, self)) |
| 6554 | if (is_via_got) { | 6737 | self.getSymbol(rel.target) |
| 6555 | const got_index = self.got_entries_table.get(rel.target) orelse break :blk 0; | 6738 | else |
| 6556 | const got_atom = self.got_entries.items[got_index].atom; | 6739 | target_atom.getSymbol(self); |
| 6557 | break :blk self.locals.items[got_atom.sym_index].n_value; | 6740 | const base_address: u64 = if (is_tlv) base_address: { |
| 6558 | } | 6741 | const sect_id: u16 = sect_id: { |
| 6559 | | 6742 | if (self.tlv_data_section_index) |i| { |
| 6560 | switch (rel.target) { | 6743 | break :sect_id i; |
| 6561 | .local => |sym_index| { | 6744 | } else if (self.tlv_bss_section_index) |i| { |
| 6562 | const sym = self.locals.items[sym_index]; | 6745 | break :sect_id i; |
| 6563 | const is_tlv = is_tlv: { | 6746 | } else unreachable; |
| 6564 | const source_sym = self.locals.items[atom.sym_index]; | 6747 | }; |
| 6565 | const match = self.section_ordinals.keys()[source_sym.n_sect - 1]; | 6748 | break :base_address self.getSection(.{ |
| 6566 | const match_seg = self.load_commands.items[match.seg].segment; | 6749 | .seg = self.data_segment_cmd_index.?, |
| 6567 | const match_sect = match_seg.sections.items[match.sect]; | 6750 | .sect = sect_id, |
| 6568 | break :is_tlv match_sect.type_() == macho.S_THREAD_LOCAL_VARIABLES; | 6751 | }).addr; |
| 6569 | }; | 6752 | } else 0; |
| 6570 | if (is_tlv) { | 6753 | break :blk target_sym.n_value - base_address; |
| 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 | } | | |
| 6597 | }; | 6754 | }; |
| 6598 | | 6755 | |
| 6599 | relocs.appendAssumeCapacity(.{ | 6756 | relocs.appendAssumeCapacity(.{ |
| ... | @@ -6614,15 +6771,18 @@ fn snapshotState(self: *MachO) !void { | ... | @@ -6614,15 +6771,18 @@ fn snapshotState(self: *MachO) !void { |
| 6614 | var next_i: usize = 0; | 6771 | var next_i: usize = 0; |
| 6615 | var last_rel: usize = 0; | 6772 | var last_rel: usize = 0; |
| 6616 | while (next_i < atom.contained.items.len) : (next_i += 1) { | 6773 | while (next_i < atom.contained.items.len) : (next_i += 1) { |
| 6617 | const loc = atom.contained.items[next_i]; | 6774 | const loc = SymbolWithLoc{ |
| 6618 | const cont_sym = self.locals.items[loc.sym_index]; | 6775 | .sym_index = atom.contained.items[next_i].sym_index, |
| 6619 | const cont_sym_name = self.getString(cont_sym.n_strx); | 6776 | .file = atom.file, |
| | 6777 | }; |
| | 6778 | const cont_sym = self.getSymbol(loc); |
| | 6779 | const cont_sym_name = self.getSymbolName(loc); |
| 6620 | var contained_node = Snapshot.Node{ | 6780 | var contained_node = Snapshot.Node{ |
| 6621 | .address = cont_sym.n_value, | 6781 | .address = cont_sym.n_value, |
| 6622 | .tag = .atom_start, | 6782 | .tag = .atom_start, |
| 6623 | .payload = .{ | 6783 | .payload = .{ |
| 6624 | .name = cont_sym_name, | 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,10 +6790,14 @@ fn snapshotState(self: *MachO) !void { |
| 6630 | var inner_aliases = std.ArrayList([]const u8).init(arena); | 6790 | var inner_aliases = std.ArrayList([]const u8).init(arena); |
| 6631 | while (true) { | 6791 | while (true) { |
| 6632 | if (next_i + 1 >= atom.contained.items.len) break; | 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 | if (next_sym.n_value != cont_sym.n_value) break; | 6798 | if (next_sym.n_value != cont_sym.n_value) break; |
| 6635 | const next_sym_name = self.getString(next_sym.n_strx); | 6799 | const next_sym_name = self.getSymbolName(next_sym_loc); |
| 6636 | if (self.symbol_resolver.contains(next_sym.n_strx)) { | 6800 | if (self.globals.contains(next_sym_name)) { |
| 6637 | try inner_aliases.append(contained_node.payload.name); | 6801 | try inner_aliases.append(contained_node.payload.name); |
| 6638 | contained_node.payload.name = next_sym_name; | 6802 | contained_node.payload.name = next_sym_name; |
| 6639 | contained_node.payload.is_global = true; | 6803 | contained_node.payload.is_global = true; |
| ... | @@ -6642,7 +6806,10 @@ fn snapshotState(self: *MachO) !void { | ... | @@ -6642,7 +6806,10 @@ fn snapshotState(self: *MachO) !void { |
| 6642 | } | 6806 | } |
| 6643 | | 6807 | |
| 6644 | const cont_size = if (next_i + 1 < atom.contained.items.len) | 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 | else | 6813 | else |
| 6647 | atom_sym.n_value + atom.size - cont_sym.n_value; | 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,7 +6862,11 @@ pub fn logSymAttributes(sym: macho.nlist_64, buf: *[4]u8) []const u8 { |
| 6695 | buf[0] = 's'; | 6862 | buf[0] = 's'; |
| 6696 | } | 6863 | } |
| 6697 | if (sym.ext()) { | 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 | if (sym.tentative()) { | 6871 | if (sym.tentative()) { |
| 6701 | buf[2] = 't'; | 6872 | buf[2] = 't'; |