| ... | ... | @@ -66,6 +66,8 @@ shndx: struct { |
| 66 | 66 | debug_rnglists: Section.Index, |
| 67 | 67 | debug_str: Section.Index, |
| 68 | 68 | debug_str_offsets: Section.Index, |
| 69 | bss: Section.Index, |
| 70 | tbss: Section.Index, |
| 69 | 71 | // These sections are created only as needed, and are initially `.UNDEF`. |
| 70 | 72 | init_array: Section.Index, |
| 71 | 73 | fini_array: Section.Index, |
| ... | ... | @@ -135,6 +137,25 @@ node_global_symbols: std.array_hash_map.Auto(MappedFile.Node.Index, Symbol.Globa |
| 135 | 137 | /// See the definition of `DsoGlobals`. |
| 136 | 138 | dso_globals: DsoGlobals, |
| 137 | 139 | |
| 140 | /// Contains all global symbols defined relative to `.bss`. These globals are not associated with |
| 141 | /// any `MappedFile.Node`, but they need to be updated when the address of `.bss` changes. |
| 142 | bss_globals: std.array_hash_map.Auto(Symbol.Global.Index, void), |
| 143 | /// Contains all global symbols defined relative to `.tbss`. These globals are not associated with |
| 144 | /// any `MappedFile.Node`, but they need to be updated when the address of `.tbss` changes. |
| 145 | tbss_globals: std.array_hash_map.Auto(Symbol.Global.Index, void), |
| 146 | |
| 147 | /// Contains all inputs which have added input sections to `.bss`, so that we can update local |
| 148 | /// symbols when the address of `.bss` changes. |
| 149 | bss_inputs: std.ArrayList(Node.InputIndex), |
| 150 | /// Contains all inputs which have added input sections to `.tbss`, so that we can update local |
| 151 | /// symbols when the address of `.tbss` changes. |
| 152 | tbss_inputs: std.ArrayList(Node.InputIndex), |
| 153 | |
| 154 | /// Indicates that the address of the `.bss` section needs to be updated. |
| 155 | /// |
| 156 | /// Equivalent to a `PROGBITS` section's `MappedFile.Node` being marked as "moved". |
| 157 | bss_moved: bool, |
| 158 | |
| 138 | 159 | shstrtab: StringTable, |
| 139 | 160 | strtab: StringTable, |
| 140 | 161 | dynstr: StringTable, |
| ... | ... | @@ -491,8 +512,9 @@ const Archive = struct { |
| 491 | 512 | }; |
| 492 | 513 | |
| 493 | 514 | const Section = struct { |
| 494 | | /// The node corresponding to this section. |
| 495 | | ni: MappedFile.Node.Index, |
| 515 | /// File-backed node corresponding to this section. |
| 516 | /// This is `.none` for `SHT_NOBITS` sections. |
| 517 | ni: MappedFile.Node.Index.Optional, |
| 496 | 518 | /// A symbol which is exactly at the start of this section. |
| 497 | 519 | /// |
| 498 | 520 | /// When not emitting a relocatable, or for special section types, this is `.null`. |
| ... | ... | @@ -596,6 +618,13 @@ const Section = struct { |
| 596 | 618 | return &elf.shdrs.items[@backingInt(shndx) - 1]; // overflow means you tried to get the `.UNDEF` section |
| 597 | 619 | } |
| 598 | 620 | |
| 621 | /// Convenience function for accessing a section's `MappedFile` node. |
| 622 | /// |
| 623 | /// Asserts that the section's `ni` is not `.none` (so, the section type is not `SHT_NOBITS`). |
| 624 | fn node(shndx: Index, elf: *Elf) MappedFile.Node.Index { |
| 625 | return shndx.get(elf).ni.unwrap().?; |
| 626 | } |
| 627 | |
| 599 | 628 | fn name(shndx: Index, elf: *Elf) String(.shstrtab) { |
| 600 | 629 | return switch (elf.shdrPtr(shndx)) { |
| 601 | 630 | inline else => |shdr| @fromBackingInt(elf.targetLoad(&shdr.name)), |
| ... | ... | @@ -648,21 +677,39 @@ const Section = struct { |
| 648 | 677 | elf.targetStore(&shdr.addralign, @intCast(min_align.toByteUnits())); |
| 649 | 678 | }, |
| 650 | 679 | } |
| 651 | | const ni = shndx.get(elf).ni; |
| 652 | | if (min_align.compare(.gt, ni.alignment(&elf.mf))) { |
| 653 | | try ni.realign(elf.base.comp.gpa, &elf.mf, min_align); |
| 654 | | } |
| 655 | | switch (elf.getNode(ni.parent(&elf.mf).unwrap().?)) { |
| 656 | | .elf => {}, |
| 657 | | .segment => |phndx| try elf.ensureSegmentAligned(phndx, min_align), |
| 658 | | else => unreachable, |
| 680 | |
| 681 | if (shndx.get(elf).ni.unwrap()) |ni| { |
| 682 | if (min_align.compare(.gt, ni.alignment(&elf.mf))) { |
| 683 | try ni.realign(elf.base.comp.gpa, &elf.mf, min_align); |
| 684 | } |
| 685 | switch (elf.getNode(ni.parent(&elf.mf).unwrap().?)) { |
| 686 | .elf => {}, |
| 687 | .segment => |phndx| try elf.ensureSegmentAligned(phndx, min_align), |
| 688 | else => unreachable, |
| 689 | } |
| 690 | } else { |
| 691 | // For sections without nodes (NOBITS), propagate alignment to the parent. |
| 692 | switch (elf.shdrPtr(shndx)) { |
| 693 | inline else => |shdr| assert(elf.targetLoad(&shdr.type) == .NOBITS), |
| 694 | } |
| 695 | |
| 696 | if (elf.ehdrType() == .REL) return; |
| 697 | |
| 698 | const segment_ni: MappedFile.Node.Index = seg: { |
| 699 | if (shndx == elf.shndx.bss) break :seg elf.ni.data; |
| 700 | if (shndx == elf.shndx.tbss) break :seg elf.ni.tls.unwrap().?; |
| 701 | // NOBITS sections other than `.bss` and `.tbss` are only emitted in `ET_REL`s. |
| 702 | unreachable; |
| 703 | }; |
| 704 | |
| 705 | try elf.ensureSegmentAligned(elf.getNode(segment_ni).segment, min_align); |
| 659 | 706 | } |
| 660 | 707 | } |
| 661 | 708 | |
| 662 | 709 | /// Asserts that `rela_shndx` is a `SHT_RELA` section and ensures that its node has enough |
| 663 | 710 | /// unused space to hold `n` additional `ElfN.Rela` entries. |
| 664 | 711 | fn relaEnsureAdditionalCapacity(rela_shndx: Index, elf: *Elf, n: usize) Error!void { |
| 665 | | const node = rela_shndx.get(elf).ni; |
| 712 | const ni = rela_shndx.node(elf); |
| 666 | 713 | const need_size: u64 = switch (elf.shdrPtr(rela_shndx)) { |
| 667 | 714 | inline else => |shdr, class| need_size: { |
| 668 | 715 | assert(elf.targetLoad(&shdr.type) == .RELA); |
| ... | ... | @@ -673,7 +720,7 @@ const Section = struct { |
| 673 | 720 | const opt_free_head = rela_shndx.get(elf).rela.free_head; |
| 674 | 721 | const free_head = opt_free_head.unwrap() orelse break :free_len 0; |
| 675 | 722 | const relas: []const class.ElfN().Rela = @ptrCast(@alignCast( |
| 676 | | node.slice(&elf.mf)[0..@intCast(cur_size)], |
| 723 | ni.slice(&elf.mf)[0..@intCast(cur_size)], |
| 677 | 724 | )); |
| 678 | 725 | const free_len = elf.targetLoad(&relas[@backingInt(free_head)].addend); |
| 679 | 726 | assert(free_len > 0); |
| ... | ... | @@ -683,7 +730,7 @@ const Section = struct { |
| 683 | 730 | break :need_size cur_size + need_additional * ent_size; |
| 684 | 731 | }, |
| 685 | 732 | }; |
| 686 | | try node.ensureMinimumSize(elf.base.comp.gpa, &elf.mf, need_size); |
| 733 | try ni.ensureMinimumSize(elf.base.comp.gpa, &elf.mf, need_size); |
| 687 | 734 | } |
| 688 | 735 | |
| 689 | 736 | /// Asserts that `rela_shndx` is a `SHT_RELA` section and deletes the `ElfN.Rela` entry at |
| ... | ... | @@ -695,7 +742,7 @@ const Section = struct { |
| 695 | 742 | assert(elf.targetLoad(&shdr.type) == .RELA); |
| 696 | 743 | assert(elf.targetLoad(&shdr.entsize) == @sizeOf(class.ElfN().Rela)); |
| 697 | 744 | const relas: []class.ElfN().Rela = @ptrCast(@alignCast( |
| 698 | | rela_shndx.get(elf).ni.slice(&elf.mf)[0..@intCast(elf.targetLoad(&shdr.size))], |
| 745 | rela_shndx.node(elf).slice(&elf.mf)[0..@intCast(elf.targetLoad(&shdr.size))], |
| 699 | 746 | )); |
| 700 | 747 | const opt_free_head = rela_shndx.get(elf).rela.free_head; |
| 701 | 748 | const old_free_len: u32 = free_len: { |
| ... | ... | @@ -743,7 +790,7 @@ const Section = struct { |
| 743 | 790 | assert(elf.targetLoad(&shdr.entsize) == ent_size); |
| 744 | 791 | const new_index: RelaIndex = if (rela_shndx.get(elf).rela.free_head.unwrap()) |free_head| new_index: { |
| 745 | 792 | const relas: []class.ElfN().Rela = @ptrCast(@alignCast( |
| 746 | | rela_shndx.get(elf).ni.slice(&elf.mf)[0..@intCast(elf.targetLoad(&shdr.size))], |
| 793 | rela_shndx.node(elf).slice(&elf.mf)[0..@intCast(elf.targetLoad(&shdr.size))], |
| 747 | 794 | )); |
| 748 | 795 | const next: RelaIndex.Optional = @fromBackingInt(@intCast(elf.targetLoad( |
| 749 | 796 | &relas[@backingInt(free_head)].offset, |
| ... | ... | @@ -766,7 +813,7 @@ const Section = struct { |
| 766 | 813 | break :new_index @fromBackingInt(@intCast(@divExact(old_size, ent_size))); |
| 767 | 814 | }; |
| 768 | 815 | const relas: []class.ElfN().Rela = @ptrCast(@alignCast( |
| 769 | | rela_shndx.get(elf).ni.slice(&elf.mf)[0..@intCast(elf.targetLoad(&shdr.size))], |
| 816 | rela_shndx.node(elf).slice(&elf.mf)[0..@intCast(elf.targetLoad(&shdr.size))], |
| 770 | 817 | )); |
| 771 | 818 | relas[@backingInt(new_index)] = .{ |
| 772 | 819 | .offset = @intCast(opts.offset), |
| ... | ... | @@ -794,7 +841,7 @@ const Section = struct { |
| 794 | 841 | assert(elf.targetLoad(&shdr.type) == .RELA); |
| 795 | 842 | assert(elf.targetLoad(&shdr.entsize) == @sizeOf(class.ElfN().Rela)); |
| 796 | 843 | const relas: []class.ElfN().Rela = @ptrCast(@alignCast( |
| 797 | | rela_shndx.get(elf).ni.slice(&elf.mf)[0..@intCast(elf.targetLoad(&shdr.size))], |
| 844 | rela_shndx.node(elf).slice(&elf.mf)[0..@intCast(elf.targetLoad(&shdr.size))], |
| 798 | 845 | )); |
| 799 | 846 | const rela_info = elf.targetLoad(&relas[@backingInt(index)].info); |
| 800 | 847 | { |
| ... | ... | @@ -818,7 +865,7 @@ const Section = struct { |
| 818 | 865 | assert(elf.targetLoad(&shdr.type) == .RELA); |
| 819 | 866 | assert(elf.targetLoad(&shdr.entsize) == @sizeOf(class.ElfN().Rela)); |
| 820 | 867 | const relas: []class.ElfN().Rela = @ptrCast(@alignCast( |
| 821 | | rela_shndx.get(elf).ni.slice(&elf.mf)[0..@intCast(elf.targetLoad(&shdr.size))], |
| 868 | rela_shndx.node(elf).slice(&elf.mf)[0..@intCast(elf.targetLoad(&shdr.size))], |
| 822 | 869 | )); |
| 823 | 870 | { |
| 824 | 871 | const rela_info = elf.targetLoad(&relas[@backingInt(index)].info); |
| ... | ... | @@ -839,7 +886,7 @@ const Section = struct { |
| 839 | 886 | assert(elf.targetLoad(&shdr.type) == .RELA); |
| 840 | 887 | assert(elf.targetLoad(&shdr.entsize) == @sizeOf(class.ElfN().Rela)); |
| 841 | 888 | const relas: []class.ElfN().Rela = @ptrCast(@alignCast( |
| 842 | | rela_shndx.get(elf).ni.slice(&elf.mf)[0..@intCast(elf.targetLoad(&shdr.size))], |
| 889 | rela_shndx.node(elf).slice(&elf.mf)[0..@intCast(elf.targetLoad(&shdr.size))], |
| 843 | 890 | )); |
| 844 | 891 | { |
| 845 | 892 | const rela_info = elf.targetLoad(&relas[@backingInt(index)].info); |
| ... | ... | @@ -863,7 +910,7 @@ const Section = struct { |
| 863 | 910 | assert(elf.targetLoad(&shdr.type) == .RELA); |
| 864 | 911 | assert(elf.targetLoad(&shdr.entsize) == @sizeOf(class.ElfN().Rela)); |
| 865 | 912 | const relas: []class.ElfN().Rela = @ptrCast(@alignCast( |
| 866 | | rela_shndx.get(elf).ni.slice(&elf.mf)[0..@intCast(elf.targetLoad(&shdr.size))], |
| 913 | rela_shndx.node(elf).slice(&elf.mf)[0..@intCast(elf.targetLoad(&shdr.size))], |
| 867 | 914 | )); |
| 868 | 915 | { |
| 869 | 916 | const rela_info = elf.targetLoad(&relas[@backingInt(index)].info); |
| ... | ... | @@ -2220,7 +2267,7 @@ const GotReloc = struct { |
| 2220 | 2267 | fn apply(reloc: *GotReloc, elf: *Elf) void { |
| 2221 | 2268 | assert(elf.ehdrType() != .REL); |
| 2222 | 2269 | const node = reloc.node.unwrap() orelse return; // deleted |
| 2223 | | if (node.hasMoved(&elf.mf) or elf.shndx.got.get(elf).ni.hasMoved(&elf.mf)) { |
| 2270 | if (node.hasMoved(&elf.mf) or elf.shndx.got.node(elf).hasMoved(&elf.mf)) { |
| 2224 | 2271 | // There's no point applying the relocation now, because it will be re-applied by |
| 2225 | 2272 | // `flushMoved` at some point anyway. |
| 2226 | 2273 | return; |
| ... | ... | @@ -2452,7 +2499,7 @@ fn ensureDynsymHashCapacity(elf: *Elf, max_dynsym_count: u32) Error!void { |
| 2452 | 2499 | switch (elf.targetDynsymHashInfo()) { |
| 2453 | 2500 | inline else => |info| { |
| 2454 | 2501 | { |
| 2455 | | const section_slice: []align(@sizeOf(info.Int())) u8 = @alignCast(elf.shndx.hash.get(elf).ni.slice(&elf.mf)); |
| 2502 | const section_slice: []align(@sizeOf(info.Int())) u8 = @alignCast(elf.shndx.hash.node(elf).slice(&elf.mf)); |
| 2456 | 2503 | const header: *info.Header() = @ptrCast(section_slice[0..@sizeOf(info.Header())]); |
| 2457 | 2504 | assert(elf.targetLoad(&header.nchain) == cur_dynsym_count); |
| 2458 | 2505 | const nbucket = elf.targetLoad(&header.nbucket); |
| ... | ... | @@ -2460,7 +2507,7 @@ fn ensureDynsymHashCapacity(elf: *Elf, max_dynsym_count: u32) Error!void { |
| 2460 | 2507 | // We don't need to add any buckets, but we still need to make sure the section is large |
| 2461 | 2508 | // enough to fit `max_dynsym_count` chains. |
| 2462 | 2509 | const need_size = @sizeOf(info.Header()) + (nbucket + max_dynsym_count) * 4; |
| 2463 | | try elf.shndx.hash.get(elf).ni.ensureMinimumSize(gpa, &elf.mf, need_size); |
| 2510 | try elf.shndx.hash.node(elf).ensureMinimumSize(gpa, &elf.mf, need_size); |
| 2464 | 2511 | return; |
| 2465 | 2512 | } |
| 2466 | 2513 | // We need more buckets, so we'll have to rebuild the hash table. |
| ... | ... | @@ -2472,13 +2519,13 @@ fn ensureDynsymHashCapacity(elf: *Elf, max_dynsym_count: u32) Error!void { |
| 2472 | 2519 | |
| 2473 | 2520 | { |
| 2474 | 2521 | const need_size = @sizeOf(info.Header()) + (new_nbucket + max_dynsym_count) * 4; |
| 2475 | | try elf.shndx.hash.get(elf).ni.ensureMinimumSize(gpa, &elf.mf, need_size); |
| 2522 | try elf.shndx.hash.node(elf).ensureMinimumSize(gpa, &elf.mf, need_size); |
| 2476 | 2523 | } |
| 2477 | 2524 | |
| 2478 | 2525 | elf.mf.nodes_lock.lock(); |
| 2479 | 2526 | defer elf.mf.nodes_lock.unlock(); |
| 2480 | 2527 | |
| 2481 | | const section_slice: []align(@sizeOf(info.Int())) u8 = @alignCast(elf.shndx.hash.get(elf).ni.slice(&elf.mf)); |
| 2528 | const section_slice: []align(@sizeOf(info.Int())) u8 = @alignCast(elf.shndx.hash.node(elf).slice(&elf.mf)); |
| 2482 | 2529 | const header: *info.Header() = @ptrCast(section_slice[0..@sizeOf(info.Header())]); |
| 2483 | 2530 | const trailing: []info.Int() = @ptrCast(section_slice[@sizeOf(info.Header())..]); |
| 2484 | 2531 | |
| ... | ... | @@ -2508,7 +2555,7 @@ fn ensureDynsymHashCapacity(elf: *Elf, max_dynsym_count: u32) Error!void { |
| 2508 | 2555 | fn appendDynsymHashEntry(elf: *Elf, dynsym_index: u32) void { |
| 2509 | 2556 | switch (elf.targetDynsymHashInfo()) { |
| 2510 | 2557 | inline else => |info| { |
| 2511 | | const section_slice: []align(@sizeOf(info.Int())) u8 = @alignCast(elf.shndx.hash.get(elf).ni.slice(&elf.mf)); |
| 2558 | const section_slice: []align(@sizeOf(info.Int())) u8 = @alignCast(elf.shndx.hash.node(elf).slice(&elf.mf)); |
| 2512 | 2559 | const header: *info.Header() = @ptrCast(section_slice[0..@sizeOf(info.Header())]); |
| 2513 | 2560 | assert(elf.targetLoad(&header.nchain) == dynsym_index); |
| 2514 | 2561 | elf.targetStore(&header.nchain, dynsym_index + 1); |
| ... | ... | @@ -2529,7 +2576,7 @@ fn populateDynsymHashEntry(elf: *Elf, dynsym_index: u32) void { |
| 2529 | 2576 | |
| 2530 | 2577 | switch (elf.targetDynsymHashInfo()) { |
| 2531 | 2578 | inline else => |info| { |
| 2532 | | const section_slice: []align(@sizeOf(info.Int())) u8 = @alignCast(elf.shndx.hash.get(elf).ni.slice(&elf.mf)); |
| 2579 | const section_slice: []align(@sizeOf(info.Int())) u8 = @alignCast(elf.shndx.hash.node(elf).slice(&elf.mf)); |
| 2533 | 2580 | const header: *info.Header() = @ptrCast(section_slice[0..@sizeOf(info.Header())]); |
| 2534 | 2581 | const trailing: []info.Int() = @ptrCast(section_slice[@sizeOf(info.Header())..]); |
| 2535 | 2582 | |
| ... | ... | @@ -2551,7 +2598,7 @@ fn popDynsymHashEntry(elf: *Elf, dynsym_index: u32) void { |
| 2551 | 2598 | |
| 2552 | 2599 | switch (elf.targetDynsymHashInfo()) { |
| 2553 | 2600 | inline else => |info| { |
| 2554 | | const section_slice: []align(@sizeOf(info.Int())) u8 = @alignCast(elf.shndx.hash.get(elf).ni.slice(&elf.mf)); |
| 2601 | const section_slice: []align(@sizeOf(info.Int())) u8 = @alignCast(elf.shndx.hash.node(elf).slice(&elf.mf)); |
| 2555 | 2602 | const header: *info.Header() = @ptrCast(section_slice[0..@sizeOf(info.Header())]); |
| 2556 | 2603 | assert(elf.targetLoad(&header.nchain) == dynsym_index + 1); |
| 2557 | 2604 | elf.targetStore(&header.nchain, dynsym_index); |
| ... | ... | @@ -2570,7 +2617,7 @@ fn clearDynsymHashEntry(elf: *Elf, dynsym_index: u32) void { |
| 2570 | 2617 | |
| 2571 | 2618 | switch (elf.targetDynsymHashInfo()) { |
| 2572 | 2619 | inline else => |info| { |
| 2573 | | const section_slice: []align(@sizeOf(info.Int())) u8 = @alignCast(elf.shndx.hash.get(elf).ni.slice(&elf.mf)); |
| 2620 | const section_slice: []align(@sizeOf(info.Int())) u8 = @alignCast(elf.shndx.hash.node(elf).slice(&elf.mf)); |
| 2574 | 2621 | const header: *info.Header() = @ptrCast(section_slice[0..@sizeOf(info.Header())]); |
| 2575 | 2622 | const trailing: []info.Int() = @ptrCast(section_slice[@sizeOf(info.Header())..]); |
| 2576 | 2623 | |
| ... | ... | @@ -2615,7 +2662,7 @@ fn pltEntryIsDead(elf: *Elf, plt_index: usize) bool { |
| 2615 | 2662 | inline else => |rela_shdr, class| { |
| 2616 | 2663 | const size = elf.targetLoad(&rela_shdr.size); |
| 2617 | 2664 | const relas: []class.ElfN().Rela = @ptrCast(@alignCast( |
| 2618 | | elf.shndx.rela_plt.get(elf).ni.slice(&elf.mf)[0..@intCast(size)], |
| 2665 | elf.shndx.rela_plt.node(elf).slice(&elf.mf)[0..@intCast(size)], |
| 2619 | 2666 | )); |
| 2620 | 2667 | const rel_type = elf.targetLoad(&relas[plt_index].info).type; |
| 2621 | 2668 | return rel_type == MachineRelocType.none(elf).unwrap(elf); |
| ... | ... | @@ -2636,7 +2683,7 @@ fn addLocalSymbol(elf: *Elf, opts: AddLocalSymbolOptions) Error!Symbol.LocalInde |
| 2636 | 2683 | |
| 2637 | 2684 | try elf.symtab.ensureUnusedCapacity(gpa, 1); |
| 2638 | 2685 | try elf.changed_symtab_index.ensureUnusedCapacity(gpa, 1); |
| 2639 | | try Section.Index.symtab.get(elf).ni.ensureMinimumSize(gpa, &elf.mf, switch (elf.shdrPtr(.symtab)) { |
| 2686 | try Section.Index.symtab.node(elf).ensureMinimumSize(gpa, &elf.mf, switch (elf.shdrPtr(.symtab)) { |
| 2640 | 2687 | inline else => |shdr, class| elf.targetLoad(&shdr.size) + @sizeOf(class.ElfN().Sym), |
| 2641 | 2688 | }); |
| 2642 | 2689 | |
| ... | ... | @@ -2715,7 +2762,7 @@ fn addGlobalSymbol(elf: *Elf, opts: Symbol.Global.AddOptions) (error{ |
| 2715 | 2762 | try elf.globals_by_name.ensureUnusedCapacity(gpa, 1); |
| 2716 | 2763 | try elf.node_global_symbols.ensureUnusedCapacity(gpa, 1); |
| 2717 | 2764 | |
| 2718 | | try Section.Index.symtab.get(elf).ni.ensureMinimumSize(gpa, &elf.mf, switch (elf.shdrPtr(.symtab)) { |
| 2765 | try Section.Index.symtab.node(elf).ensureMinimumSize(gpa, &elf.mf, switch (elf.shdrPtr(.symtab)) { |
| 2719 | 2766 | inline else => |shdr, class| elf.targetLoad(&shdr.size) + @sizeOf(class.ElfN().Sym), |
| 2720 | 2767 | }); |
| 2721 | 2768 | |
| ... | ... | @@ -2881,6 +2928,18 @@ fn addGlobalSymbol(elf: *Elf, opts: Symbol.Global.AddOptions) (error{ |
| 2881 | 2928 | old_head_ptr.prev_in_node = .wrap(gsi); |
| 2882 | 2929 | } |
| 2883 | 2930 | |
| 2931 | if (elf.ehdrType() != .REL) { |
| 2932 | if (opts.shndx == elf.shndx.bss) { |
| 2933 | assert(opts.node == .none); |
| 2934 | try elf.bss_globals.put(gpa, gsi, {}); |
| 2935 | } else if (elf.ni.tls != .none and opts.shndx == elf.shndx.tbss) { |
| 2936 | assert(opts.node == .none); |
| 2937 | try elf.tbss_globals.put(gpa, gsi, {}); |
| 2938 | } else if (opts.shndx != .UNDEF and opts.shndx != .ABS) { |
| 2939 | assert(opts.node != .none); |
| 2940 | } |
| 2941 | } |
| 2942 | |
| 2884 | 2943 | if (force_local_bind) { |
| 2885 | 2944 | elf.moveDemotedGlobal(gsi); |
| 2886 | 2945 | } |
| ... | ... | @@ -3059,8 +3118,8 @@ fn updateGlobalDynamic(elf: *Elf, orig_gsi: Symbol.Global.Index, force_apply_rel |
| 3059 | 3118 | }; |
| 3060 | 3119 | const need_dynsym_len: u32 = @intCast(@divExact(dynsym_size, dynsym_ent_size) + 1); |
| 3061 | 3120 | |
| 3062 | | try elf.shndx.dynsym.get(elf).ni.ensureMinimumSize(gpa, &elf.mf, need_dynsym_len * dynsym_ent_size); |
| 3063 | | try elf.shndx.gnu_version.get(elf).ni.ensureMinimumSize(gpa, &elf.mf, need_dynsym_len * 2); |
| 3121 | try elf.shndx.dynsym.node(elf).ensureMinimumSize(gpa, &elf.mf, need_dynsym_len * dynsym_ent_size); |
| 3122 | try elf.shndx.gnu_version.node(elf).ensureMinimumSize(gpa, &elf.mf, need_dynsym_len * 2); |
| 3064 | 3123 | try elf.ensureDynsymHashCapacity(need_dynsym_len); |
| 3065 | 3124 | |
| 3066 | 3125 | const dynstr_name: String(.dynstr) = name: { |
| ... | ... | @@ -3246,7 +3305,7 @@ fn updateGlobalDynamic(elf: *Elf, orig_gsi: Symbol.Global.Index, force_apply_rel |
| 3246 | 3305 | errdefer assert(elf.copied_globals.pop().?.key == gsi); |
| 3247 | 3306 | try elf.nodes.ensureUnusedCapacity(gpa, 1); |
| 3248 | 3307 | const node = elf.addNodeAssumeCapacity( |
| 3249 | | try shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{ |
| 3308 | try shndx.node(elf).addFloatingChild(gpa, &elf.mf, .{ |
| 3250 | 3309 | .size = dso_global.alignment.forward(dso_global.size), |
| 3251 | 3310 | .alignment = dso_global.alignment, |
| 3252 | 3311 | }), |
| ... | ... | @@ -3318,8 +3377,9 @@ fn setGlobalSymbolValue(elf: *Elf, gsi: Symbol.Global.Index, new: struct { |
| 3318 | 3377 | type: std.elf.STT, |
| 3319 | 3378 | shndx: Section.Index, |
| 3320 | 3379 | }) Error!void { |
| 3321 | | assert(new.shndx != .UNDEF); |
| 3380 | const gpa = elf.base.comp.gpa; |
| 3322 | 3381 | |
| 3382 | assert(new.shndx != .UNDEF); |
| 3323 | 3383 | const global_ptr = gsi.ptr(elf); |
| 3324 | 3384 | |
| 3325 | 3385 | if (global_ptr.symtab_index.ptr(elf).node.unwrap()) |old_node| { |
| ... | ... | @@ -3341,6 +3401,21 @@ fn setGlobalSymbolValue(elf: *Elf, gsi: Symbol.Global.Index, new: struct { |
| 3341 | 3401 | } else { |
| 3342 | 3402 | assert(global_ptr.next_in_node == .none); |
| 3343 | 3403 | assert(global_ptr.prev_in_node == .none); |
| 3404 | // If the symbol didn't have a node, it may have been in `.bss` or `.tbss`. |
| 3405 | _ = elf.bss_globals.swapRemove(gsi); |
| 3406 | _ = elf.tbss_globals.swapRemove(gsi); |
| 3407 | } |
| 3408 | |
| 3409 | if (elf.ehdrType() != .REL) { |
| 3410 | if (new.shndx == elf.shndx.bss) { |
| 3411 | assert(new.node == .none); |
| 3412 | try elf.bss_globals.put(gpa, gsi, {}); |
| 3413 | } else if (elf.ni.tls != .none and new.shndx == elf.shndx.tbss) { |
| 3414 | assert(new.node == .none); |
| 3415 | try elf.tbss_globals.put(gpa, gsi, {}); |
| 3416 | } else if (new.shndx != .UNDEF) { |
| 3417 | assert(new.node != .none); |
| 3418 | } |
| 3344 | 3419 | } |
| 3345 | 3420 | |
| 3346 | 3421 | global_ptr.symtab_index.ptr(elf).node = new.node; |
| ... | ... | @@ -3624,7 +3699,8 @@ fn deleteOwnedDynsym(elf: *Elf, gsi: Symbol.Global.Index) std.mem.Allocator.Erro |
| 3624 | 3699 | |
| 3625 | 3700 | const Symbol = struct { |
| 3626 | 3701 | /// The node which this symbol's value is defined relative to. Possible values are: |
| 3627 | | /// * `.none` for a SHN_ABS or SHN_UNDEF symbol |
| 3702 | /// * `.none` for a SHN_ABS or SHN_UNDEF symbol, *or* a symbol in `.bss`/`.tbss` |
| 3703 | /// (see `Elf.bss_globals` and `Elf.tbss_globals`) |
| 3628 | 3704 | /// * A section (the symbol's value is some vaddr in that section) |
| 3629 | 3705 | /// * An input section (the symbol's value is some vaddr in that input section) |
| 3630 | 3706 | /// * A NAV, UAV, or lazy code/data (the symbol's value is exactly the vaddr of that node) |
| ... | ... | @@ -4295,7 +4371,7 @@ fn lazySymbolInner(elf: *Elf, lazy: link.File.LazySymbol) Error!link.File.Symbol |
| 4295 | 4371 | .const_data => .{ .rodata, .OBJECT }, |
| 4296 | 4372 | }; |
| 4297 | 4373 | const node = elf.addNodeAssumeCapacity( |
| 4298 | | try shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{}), |
| 4374 | try shndx.node(elf).addFloatingChild(gpa, &elf.mf, .{}), |
| 4299 | 4375 | switch (lazy.kind) { |
| 4300 | 4376 | .code => .{ .lazy_code = @fromBackingInt(@intCast(gop.index)) }, |
| 4301 | 4377 | .const_data => .{ .lazy_const_data = @fromBackingInt(@intCast(gop.index)) }, |
| ... | ... | @@ -4472,7 +4548,7 @@ fn String(section: StringSection) type { |
| 4472 | 4548 | _, |
| 4473 | 4549 | |
| 4474 | 4550 | fn slice(str: @This(), elf: *Elf) [:0]const u8 { |
| 4475 | | const section_node = section.shndx(elf).get(elf).ni; |
| 4551 | const section_node = section.shndx(elf).node(elf); |
| 4476 | 4552 | const overlong = section_node.sliceConst(&elf.mf)[@backingInt(str)..]; |
| 4477 | 4553 | return overlong[0..std.mem.findScalar(u8, overlong, 0).? :0]; |
| 4478 | 4554 | } |
| ... | ... | @@ -4532,14 +4608,14 @@ const StringTable = struct { |
| 4532 | 4608 | |
| 4533 | 4609 | fn getExisting(st: *StringTable, elf: *Elf, shndx: Section.Index, key: []const u8) u32 { |
| 4534 | 4610 | if (key.len == 0) return 0; |
| 4535 | | const slice_const = shndx.get(elf).ni.sliceConst(&elf.mf); |
| 4611 | const slice_const = shndx.node(elf).sliceConst(&elf.mf); |
| 4536 | 4612 | const adapter: StringTable.Adapter = .{ .slice = slice_const }; |
| 4537 | 4613 | return st.map.getKeyAdapted(key, adapter).?; |
| 4538 | 4614 | } |
| 4539 | 4615 | |
| 4540 | 4616 | fn ensureAdditionalCapacity(st: *StringTable, elf: *Elf, shndx: Section.Index, string_len: usize) Error!void { |
| 4541 | 4617 | const gpa = elf.base.comp.gpa; |
| 4542 | | const ni = shndx.get(elf).ni; |
| 4618 | const ni = shndx.node(elf); |
| 4543 | 4619 | const slice_const = ni.sliceConst(&elf.mf); |
| 4544 | 4620 | try st.map.ensureUnusedCapacityContext(gpa, 1, .{ .slice = slice_const }); |
| 4545 | 4621 | const size: u64 = switch (elf.shdrPtr(shndx)) { |
| ... | ... | @@ -4553,7 +4629,7 @@ const StringTable = struct { |
| 4553 | 4629 | // case the empty string. |
| 4554 | 4630 | if (key.len == 0) return 0; |
| 4555 | 4631 | |
| 4556 | | const ni = shndx.get(elf).ni; |
| 4632 | const ni = shndx.node(elf); |
| 4557 | 4633 | const slice_const = ni.sliceConst(&elf.mf); |
| 4558 | 4634 | const gop = st.map.getOrPutAssumeCapacityAdapted( |
| 4559 | 4635 | key, |
| ... | ... | @@ -4711,6 +4787,8 @@ fn create( |
| 4711 | 4787 | .init_array = .UNDEF, |
| 4712 | 4788 | .fini_array = .UNDEF, |
| 4713 | 4789 | .preinit_array = .UNDEF, |
| 4790 | .bss = .UNDEF, |
| 4791 | .tbss = .UNDEF, |
| 4714 | 4792 | }, |
| 4715 | 4793 | .dynamic = .{ |
| 4716 | 4794 | .flags = 0, |
| ... | ... | @@ -4738,6 +4816,11 @@ fn create( |
| 4738 | 4816 | .symbols = .empty, |
| 4739 | 4817 | .default_sym_vers = .empty, |
| 4740 | 4818 | }, |
| 4819 | .bss_globals = .empty, |
| 4820 | .tbss_globals = .empty, |
| 4821 | .bss_inputs = .empty, |
| 4822 | .tbss_inputs = .empty, |
| 4823 | .bss_moved = false, |
| 4741 | 4824 | .shstrtab = .{ .map = .empty }, |
| 4742 | 4825 | .strtab = .{ .map = .empty }, |
| 4743 | 4826 | .dynstr = .{ .map = .empty }, |
| ... | ... | @@ -4820,6 +4903,10 @@ pub fn deinit(elf: *Elf) void { |
| 4820 | 4903 | elf.dso_globals.string_bytes.deinit(gpa); |
| 4821 | 4904 | elf.dso_globals.symbols.deinit(gpa); |
| 4822 | 4905 | elf.dso_globals.default_sym_vers.deinit(gpa); |
| 4906 | elf.bss_globals.deinit(gpa); |
| 4907 | elf.tbss_globals.deinit(gpa); |
| 4908 | elf.bss_inputs.deinit(gpa); |
| 4909 | elf.tbss_inputs.deinit(gpa); |
| 4823 | 4910 | elf.shstrtab.map.deinit(gpa); |
| 4824 | 4911 | elf.strtab.map.deinit(gpa); |
| 4825 | 4912 | elf.dynstr.map.deinit(gpa); |
| ... | ... | @@ -4905,7 +4992,9 @@ fn initHeaders( |
| 4905 | 4992 | shnum += 1; // .rodata |
| 4906 | 4993 | shnum += 1; // .text |
| 4907 | 4994 | shnum += 1; // .data |
| 4995 | shnum += 1; // .bss |
| 4908 | 4996 | shnum += @intFromBool(comp.config.any_non_single_threaded); // .tdata |
| 4997 | shnum += @intFromBool(comp.config.any_non_single_threaded); // .tbss |
| 4909 | 4998 | shnum += 1; // .data.rel.ro |
| 4910 | 4999 | if (have_dynamic) { |
| 4911 | 5000 | shnum += 1; // .dynamic |
| ... | ... | @@ -5022,9 +5111,13 @@ fn initHeaders( |
| 5022 | 5111 | }; |
| 5023 | 5112 | }; |
| 5024 | 5113 | |
| 5114 | // NOBITS sections don't contribute nodes. |
| 5115 | const nobits_shnum: u32 = |
| 5116 | @as(u32, 1) + @intFromBool(comp.config.any_non_single_threaded); |
| 5117 | |
| 5025 | 5118 | const expected_nodes_len = @as(usize, if (is_archive) 3 else 0) + // .archive, .archive_header, .archive_elf_member_header |
| 5026 | 5119 | 3 + // `.elf`, `.ehdr`, and `.shdr` nodes |
| 5027 | | (shnum - 1) + // -1 because the SHN_UNDEF shdr does not have a `.section` node |
| 5120 | (shnum - 1 - nobits_shnum) + // -1 because the SHN_UNDEF shdr does not have a `.section` node |
| 5028 | 5121 | (phnum -| 1) + // -1 because the GNU_STACK phdr does not have a `.segment` node |
| 5029 | 5122 | @intFromBool(have_eh_frame and @"type" != .REL); // eh_frame_footer |
| 5030 | 5123 | |
| ... | ... | @@ -5476,7 +5569,7 @@ fn initHeaders( |
| 5476 | 5569 | .node_align = node_block_align, |
| 5477 | 5570 | .manual_size = true, |
| 5478 | 5571 | })); |
| 5479 | | Section.Index.get(.shstrtab, elf).ni.slice(&elf.mf)[0] = 0; |
| 5572 | Section.Index.shstrtab.node(elf).slice(&elf.mf)[0] = 0; |
| 5480 | 5573 | |
| 5481 | 5574 | try Section.Index.symtab.rename(elf, ".symtab"); |
| 5482 | 5575 | try Section.Index.shstrtab.rename(elf, ".shstrtab"); |
| ... | ... | @@ -5489,7 +5582,7 @@ fn initHeaders( |
| 5489 | 5582 | .node_align = node_block_align, |
| 5490 | 5583 | .manual_size = true, |
| 5491 | 5584 | })); |
| 5492 | | Section.Index.get(.strtab, elf).ni.slice(&elf.mf)[0] = 0; |
| 5585 | Section.Index.strtab.node(elf).slice(&elf.mf)[0] = 0; |
| 5493 | 5586 | switch (elf.shdrPtr(.symtab)) { |
| 5494 | 5587 | inline else => |shdr| elf.targetStore(&shdr.link, @backingInt(Section.Index.strtab)), |
| 5495 | 5588 | } |
| ... | ... | @@ -5514,6 +5607,13 @@ fn initHeaders( |
| 5514 | 5607 | .flags = .{ .WRITE = true, .ALLOC = true }, |
| 5515 | 5608 | .node_align = node_block_align, |
| 5516 | 5609 | })); |
| 5610 | |
| 5611 | elf.shndx.bss = try elf.addSection(elf.ni.data, .{ |
| 5612 | .name = ".bss", |
| 5613 | .type = .NOBITS, |
| 5614 | .flags = .{ .WRITE = true, .ALLOC = true }, |
| 5615 | }); |
| 5616 | |
| 5517 | 5617 | if (@"type" != .REL) { |
| 5518 | 5618 | elf.shndx.got = try elf.addSection(elf.ni.data_rel_ro, .{ |
| 5519 | 5619 | .name = ".got", |
| ... | ... | @@ -5595,7 +5695,7 @@ fn initHeaders( |
| 5595 | 5695 | .flags = .{ .ALLOC = true }, |
| 5596 | 5696 | .size = @intCast(interp.len + 1), |
| 5597 | 5697 | }); |
| 5598 | | const sec_interp = sec_interp_shndx.get(elf).ni.slice(&elf.mf); |
| 5698 | const sec_interp = sec_interp_shndx.node(elf).slice(&elf.mf); |
| 5599 | 5699 | @memcpy(sec_interp[0..interp.len], interp); |
| 5600 | 5700 | sec_interp[interp.len] = 0; |
| 5601 | 5701 | } |
| ... | ... | @@ -5620,7 +5720,7 @@ fn initHeaders( |
| 5620 | 5720 | .node_align = node_block_align, |
| 5621 | 5721 | .manual_size = true, |
| 5622 | 5722 | }); |
| 5623 | | dynstr_shndx.get(elf).ni.slice(&elf.mf)[0] = 0; |
| 5723 | dynstr_shndx.node(elf).slice(&elf.mf)[0] = 0; |
| 5624 | 5724 | elf.shndx.dynstr = dynstr_shndx; |
| 5625 | 5725 | |
| 5626 | 5726 | switch (class) { |
| ... | ... | @@ -5765,7 +5865,7 @@ fn initHeaders( |
| 5765 | 5865 | .size = @sizeOf(info.Header()) + @sizeOf(info.Int()) * (8 + 1), |
| 5766 | 5866 | .manual_size = true, |
| 5767 | 5867 | }); |
| 5768 | | const hash_slice: []align(@sizeOf(info.Int())) u8 = @alignCast(elf.shndx.hash.get(elf).ni.slice(&elf.mf)); |
| 5868 | const hash_slice: []align(@sizeOf(info.Int())) u8 = @alignCast(elf.shndx.hash.node(elf).slice(&elf.mf)); |
| 5769 | 5869 | const header: *info.Header() = @ptrCast(hash_slice[0..@sizeOf(info.Header())]); |
| 5770 | 5870 | header.* = .{ .nbucket = 8, .nchain = 1 }; |
| 5771 | 5871 | if (elf.targetEndian() != std.lang.Endian.native) { |
| ... | ... | @@ -5779,7 +5879,7 @@ fn initHeaders( |
| 5779 | 5879 | switch (machine) { |
| 5780 | 5880 | .AARCH64, .PPC64, .RISCV => @panic(@tagName(machine)), |
| 5781 | 5881 | .X86_64 => { |
| 5782 | | const plt_ni = elf.shndx.plt.get(elf).ni; |
| 5882 | const plt_ni = elf.shndx.plt.node(elf); |
| 5783 | 5883 | const got_plt_sym: Symbol.Id = .local(elf.shndx.got_plt.get(elf).lsi); |
| 5784 | 5884 | @memcpy(plt_ni.slice(&elf.mf)[0..16], &[16]u8{ |
| 5785 | 5885 | 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // push 0x0(%rip) |
| ... | ... | @@ -5804,7 +5904,7 @@ fn initHeaders( |
| 5804 | 5904 | ); |
| 5805 | 5905 | }, |
| 5806 | 5906 | .LOONGARCH => { |
| 5807 | | const plt_ni = elf.shndx.plt.get(elf).ni; |
| 5907 | const plt_ni = elf.shndx.plt.node(elf); |
| 5808 | 5908 | const got_plt_sym: Symbol.Id = .local(elf.shndx.got_plt.get(elf).lsi); |
| 5809 | 5909 | @memcpy(plt_ni.slice(&elf.mf)[0..32], switch (class) { |
| 5810 | 5910 | .NONE, _ => unreachable, |
| ... | ... | @@ -5881,7 +5981,7 @@ fn initHeaders( |
| 5881 | 5981 | .manual_size = true, |
| 5882 | 5982 | }); |
| 5883 | 5983 | |
| 5884 | | const eh_frame_hdr_ni = elf.shndx.eh_frame_hdr.get(elf).ni; |
| 5984 | const eh_frame_hdr_ni = elf.shndx.eh_frame_hdr.node(elf); |
| 5885 | 5985 | elf.eh_frame_hdr_first_symbol_reloc = |
| 5886 | 5986 | @fromBackingInt(@intCast(elf.symbol_relocs.items.len)); |
| 5887 | 5987 | try elf.dwarf.genEhFrameHdr( |
| ... | ... | @@ -5890,7 +5990,7 @@ fn initHeaders( |
| 5890 | 5990 | Symbol.Id.local(elf.shndx.eh_frame.get(elf).lsi).toTypeErased(), |
| 5891 | 5991 | ); |
| 5892 | 5992 | _ = elf.addNodeAssumeCapacity( |
| 5893 | | try elf.shndx.eh_frame.get(elf).ni.addOnlyFooterChild(gpa, &elf.mf, .{ |
| 5993 | try elf.shndx.eh_frame.node(elf).addOnlyFooterChild(gpa, &elf.mf, .{ |
| 5894 | 5994 | .size = addr_align.forward(4), |
| 5895 | 5995 | .alignment = addr_align, |
| 5896 | 5996 | }), |
| ... | ... | @@ -5937,7 +6037,7 @@ fn initHeaders( |
| 5937 | 6037 | |
| 5938 | 6038 | // Despite the name, `__dso_handle` is necessary even in static binaries. |
| 5939 | 6039 | _ = elf.addGlobalSymbol(.{ |
| 5940 | | .node = .wrap(Section.Index.text.get(elf).ni), |
| 6040 | .node = .wrap(Section.Index.text.node(elf)), |
| 5941 | 6041 | .name = "__dso_handle", |
| 5942 | 6042 | .value = Section.Index.text.vaddr(elf), |
| 5943 | 6043 | .size = 0, |
| ... | ... | @@ -5952,7 +6052,7 @@ fn initHeaders( |
| 5952 | 6052 | else => |e| return e, |
| 5953 | 6053 | }; |
| 5954 | 6054 | _ = elf.addGlobalSymbol(.{ |
| 5955 | | .node = .wrap(elf.shndx.plt.get(elf).ni), |
| 6055 | .node = .wrap(elf.shndx.plt.node(elf)), |
| 5956 | 6056 | .name = "_PROCEDURE_LINKAGE_TABLE_", |
| 5957 | 6057 | .value = elf.shndx.plt.vaddr(elf), |
| 5958 | 6058 | .size = 0, |
| ... | ... | @@ -5967,7 +6067,7 @@ fn initHeaders( |
| 5967 | 6067 | else => |e| return e, |
| 5968 | 6068 | }; |
| 5969 | 6069 | _ = elf.addGlobalSymbol(.{ |
| 5970 | | .node = .wrap(elf.shndx.got.get(elf).ni), |
| 6070 | .node = .wrap(elf.shndx.got.node(elf)), |
| 5971 | 6071 | .name = "_GLOBAL_OFFSET_TABLE_", |
| 5972 | 6072 | .value = switch (machine) { |
| 5973 | 6073 | .AARCH64, |
| ... | ... | @@ -6085,7 +6185,7 @@ fn initHeaders( |
| 6085 | 6185 | }; |
| 6086 | 6186 | if (have_dynamic) { |
| 6087 | 6187 | _ = elf.addGlobalSymbol(.{ |
| 6088 | | .node = .wrap(elf.shndx.dynamic.get(elf).ni), |
| 6188 | .node = .wrap(elf.shndx.dynamic.node(elf)), |
| 6089 | 6189 | .name = "_DYNAMIC", |
| 6090 | 6190 | .value = elf.shndx.dynamic.vaddr(elf), |
| 6091 | 6191 | .size = 0, |
| ... | ... | @@ -6112,11 +6212,19 @@ fn initHeaders( |
| 6112 | 6212 | .manual_size = true, |
| 6113 | 6213 | }); |
| 6114 | 6214 | } |
| 6115 | | if (elf.ni.tls.unwrap()) |tls_segment_ni| elf.shndx.tdata = try elf.addSection(tls_segment_ni, .{ |
| 6116 | | .name = ".tdata", |
| 6117 | | .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true }, |
| 6118 | | .node_align = node_block_align, |
| 6119 | | }); |
| 6215 | if (elf.ni.tls.unwrap()) |tls_segment_ni| { |
| 6216 | elf.shndx.tdata = try elf.addSection(tls_segment_ni, .{ |
| 6217 | .name = ".tdata", |
| 6218 | .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true }, |
| 6219 | .node_align = node_block_align, |
| 6220 | }); |
| 6221 | |
| 6222 | elf.shndx.tbss = try elf.addSection(tls_segment_ni, .{ |
| 6223 | .name = ".tbss", |
| 6224 | .type = .NOBITS, |
| 6225 | .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true }, |
| 6226 | }); |
| 6227 | } |
| 6120 | 6228 | switch (comp.config.debug_format) { |
| 6121 | 6229 | .strip => {}, |
| 6122 | 6230 | .dwarf => { |
| ... | ... | @@ -6323,6 +6431,15 @@ fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { |
| 6323 | 6431 | => elf.computeNodeVAddr(ni), |
| 6324 | 6432 | }; |
| 6325 | 6433 | } |
| 6434 | |
| 6435 | fn tbssOffset(elf: *Elf) u64 { |
| 6436 | // The `.tbss` section is placed exactly at the end of the TLS segment. |
| 6437 | const tls_phndx = elf.getNode(elf.ni.tls.unwrap().?).segment; |
| 6438 | return switch (elf.phdrSlice()) { |
| 6439 | inline else => |phdr| elf.targetLoad(&phdr[tls_phndx].filesz), |
| 6440 | }; |
| 6441 | } |
| 6442 | |
| 6326 | 6443 | fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { |
| 6327 | 6444 | const parent_ni = ni.parent(&elf.mf).unwrap().?; |
| 6328 | 6445 | const parent_vaddr = parent_vaddr: switch (elf.getNode(parent_ni)) { |
| ... | ... | @@ -6868,7 +6985,7 @@ const SymPtr = union(std.elf.CLASS) { |
| 6868 | 6985 | @"64": *std.elf.Elf64.Sym, |
| 6869 | 6986 | }; |
| 6870 | 6987 | fn symPtr(elf: *Elf, index: Symbol.Index) SymPtr { |
| 6871 | | const raw_slice = Section.Index.symtab.get(elf).ni.slice(&elf.mf); |
| 6988 | const raw_slice = Section.Index.symtab.node(elf).slice(&elf.mf); |
| 6872 | 6989 | switch (elf.shdrPtr(.symtab)) { |
| 6873 | 6990 | inline else => |shdr, class| { |
| 6874 | 6991 | const size = elf.targetLoad(&shdr.size); |
| ... | ... | @@ -6878,7 +6995,7 @@ fn symPtr(elf: *Elf, index: Symbol.Index) SymPtr { |
| 6878 | 6995 | } |
| 6879 | 6996 | } |
| 6880 | 6997 | fn dynsymPtr(elf: *Elf, index: u32) SymPtr { |
| 6881 | | const raw_slice = elf.shndx.dynsym.get(elf).ni.slice(&elf.mf); |
| 6998 | const raw_slice = elf.shndx.dynsym.node(elf).slice(&elf.mf); |
| 6882 | 6999 | switch (elf.shdrPtr(elf.shndx.dynsym)) { |
| 6883 | 7000 | inline else => |shdr, class| { |
| 6884 | 7001 | const size = elf.targetLoad(&shdr.size); |
| ... | ... | @@ -6889,7 +7006,7 @@ fn dynsymPtr(elf: *Elf, index: u32) SymPtr { |
| 6889 | 7006 | } |
| 6890 | 7007 | |
| 6891 | 7008 | fn versymSlice(elf: *Elf) []std.elf.Versym { |
| 6892 | | const raw_slice = elf.shndx.gnu_version.get(elf).ni.slice(&elf.mf); |
| 7009 | const raw_slice = elf.shndx.gnu_version.node(elf).slice(&elf.mf); |
| 6893 | 7010 | const size = elf.shndx.gnu_version.size(elf); |
| 6894 | 7011 | return @ptrCast(@alignCast(raw_slice[0..@intCast(size)])); |
| 6895 | 7012 | } |
| ... | ... | @@ -6903,7 +7020,7 @@ const VerdefEntry = extern struct { |
| 6903 | 7020 | aux: std.elf.Verdaux, |
| 6904 | 7021 | }; |
| 6905 | 7022 | fn verdefSlice(elf: *Elf) []VerdefEntry { |
| 6906 | | const raw_slice = elf.shndx.gnu_version_d.get(elf).ni.slice(&elf.mf); |
| 7023 | const raw_slice = elf.shndx.gnu_version_d.node(elf).slice(&elf.mf); |
| 6907 | 7024 | const size = elf.shndx.gnu_version_d.size(elf); |
| 6908 | 7025 | return @ptrCast(@alignCast(raw_slice[0..@intCast(size)])); |
| 6909 | 7026 | } |
| ... | ... | @@ -6916,7 +7033,7 @@ const VerneedEntry = extern union { |
| 6916 | 7033 | } |
| 6917 | 7034 | }; |
| 6918 | 7035 | fn verneedSlice(elf: *Elf) []VerneedEntry { |
| 6919 | | const raw_slice = elf.shndx.gnu_version_r.get(elf).ni.slice(&elf.mf); |
| 7036 | const raw_slice = elf.shndx.gnu_version_r.node(elf).slice(&elf.mf); |
| 6920 | 7037 | const size = elf.shndx.gnu_version_r.size(elf); |
| 6921 | 7038 | return @ptrCast(@alignCast(raw_slice[0..@intCast(size)])); |
| 6922 | 7039 | } |
| ... | ... | @@ -6935,12 +7052,18 @@ fn mapInputSection(elf: *Elf, opts: struct { |
| 6935 | 7052 | name: []const u8, |
| 6936 | 7053 | flags: std.elf.SHF, |
| 6937 | 7054 | entsize: std.elf.Xword, |
| 7055 | /// Must be one of: |
| 7056 | /// * `.PROGBITS` |
| 7057 | /// * `.NOBITS` |
| 7058 | /// * `.X86_64_UNWIND` |
| 7059 | type: std.elf.SHT, |
| 6938 | 7060 | }) (Error || error{ |
| 6939 | 7061 | UnsupportedSectionFlags, |
| 6940 | 7062 | TlsSectionUnavailable, |
| 6941 | 7063 | StripSection, |
| 6942 | 7064 | SectionFlagsConflict, |
| 6943 | 7065 | SectionTypeConflict, |
| 7066 | UnsupportedNobitsSection, |
| 6944 | 7067 | })!Section.Index { |
| 6945 | 7068 | const gpa = elf.base.comp.gpa; |
| 6946 | 7069 | if (opts.flags.INFO_LINK or |
| ... | ... | @@ -6972,12 +7095,10 @@ fn mapInputSection(elf: *Elf, opts: struct { |
| 6972 | 7095 | if (std.mem.startsWith(u8, opts.name, ".data.")) break :name ".data"; |
| 6973 | 7096 | if (std.mem.startsWith(u8, opts.name, ".tdata.")) break :name ".tdata"; |
| 6974 | 7097 | if (std.mem.startsWith(u8, opts.name, ".gcc_except_table.")) break :name ".gcc_except_table"; |
| 6975 | | // TODO: actually generate a bss section! |
| 6976 | | if (std.mem.eql(u8, opts.name, ".bss")) break :name ".data"; |
| 6977 | | if (std.mem.startsWith(u8, opts.name, ".bss.")) break :name ".data"; |
| 6978 | | // TODO: actually generate a tbss section! |
| 6979 | | if (std.mem.eql(u8, opts.name, ".tbss")) break :name ".tdata"; |
| 6980 | | if (std.mem.startsWith(u8, opts.name, ".tbss.")) break :name ".tdata"; |
| 7098 | if (std.mem.eql(u8, opts.name, ".bss")) break :name ".bss"; |
| 7099 | if (std.mem.startsWith(u8, opts.name, ".bss.")) break :name ".bss"; |
| 7100 | if (std.mem.eql(u8, opts.name, ".tbss")) break :name ".tbss"; |
| 7101 | if (std.mem.startsWith(u8, opts.name, ".tbss.")) break :name ".tbss"; |
| 6981 | 7102 | break :name opts.name; |
| 6982 | 7103 | }, |
| 6983 | 7104 | }; |
| ... | ... | @@ -6998,7 +7119,12 @@ fn mapInputSection(elf: *Elf, opts: struct { |
| 6998 | 7119 | assert(gop.index == elf.shdrs.items.len); |
| 6999 | 7120 | return elf.addSection(parent_node, .{ |
| 7000 | 7121 | .name = name, |
| 7001 | | .type = .NULL, // because initial size is 0 |
| 7122 | .type = switch (opts.type) { |
| 7123 | .PROGBITS => .NULL, // size is 0 |
| 7124 | .X86_64_UNWIND => .X86_64_UNWIND, |
| 7125 | .NOBITS => if (elf.ehdrType() == .REL) .NOBITS else return error.UnsupportedNobitsSection, |
| 7126 | else => unreachable, |
| 7127 | }, |
| 7002 | 7128 | .flags = flags: { |
| 7003 | 7129 | // We need to decompress the section for linking. |
| 7004 | 7130 | var flags = opts.flags; |
| ... | ... | @@ -7019,9 +7145,20 @@ fn mapInputSection(elf: *Elf, opts: struct { |
| 7019 | 7145 | return error.SectionFlagsConflict; |
| 7020 | 7146 | } |
| 7021 | 7147 | |
| 7022 | | switch (elf.targetLoad(&shdr.type)) { |
| 7023 | | .NULL, .PROGBITS, .X86_64_UNWIND => {}, |
| 7024 | | else => return error.SectionTypeConflict, |
| 7148 | const existing_type = elf.targetLoad(&shdr.type); |
| 7149 | |
| 7150 | switch (opts.type) { |
| 7151 | .PROGBITS, .X86_64_UNWIND => switch (existing_type) { |
| 7152 | .NULL, .PROGBITS, .X86_64_UNWIND => {}, |
| 7153 | else => return error.SectionTypeConflict, |
| 7154 | }, |
| 7155 | |
| 7156 | .NOBITS => switch (existing_type) { |
| 7157 | .NOBITS => {}, |
| 7158 | else => return error.SectionTypeConflict, |
| 7159 | }, |
| 7160 | |
| 7161 | else => unreachable, |
| 7025 | 7162 | } |
| 7026 | 7163 | |
| 7027 | 7164 | // All okay, combine the section flags |
| ... | ... | @@ -7060,6 +7197,7 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node |
| 7060 | 7197 | nav.resolved.?.@"threadlocal", |
| 7061 | 7198 | }, |
| 7062 | 7199 | .entsize = 0, |
| 7200 | .type = .PROGBITS, |
| 7063 | 7201 | })) |shndx| { |
| 7064 | 7202 | break :section shndx; |
| 7065 | 7203 | } else |err| switch (err) { |
| ... | ... | @@ -7069,6 +7207,7 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node |
| 7069 | 7207 | error.UnsupportedSectionFlags, |
| 7070 | 7208 | error.SectionTypeConflict, |
| 7071 | 7209 | error.SectionFlagsConflict, |
| 7210 | error.UnsupportedNobitsSection, |
| 7072 | 7211 | => {}, // fall back to default behavior below |
| 7073 | 7212 | |
| 7074 | 7213 | } |
| ... | ... | @@ -7101,7 +7240,7 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node |
| 7101 | 7240 | }, |
| 7102 | 7241 | }; |
| 7103 | 7242 | try shndx.ensureAligned(elf, alignment); |
| 7104 | | const node = elf.addNodeAssumeCapacity(try shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{ |
| 7243 | const node = elf.addNodeAssumeCapacity(try shndx.node(elf).addFloatingChild(gpa, &elf.mf, .{ |
| 7105 | 7244 | .alignment = alignment, |
| 7106 | 7245 | }), .{ .nav = nmi }); |
| 7107 | 7246 | nav_gop.value_ptr.* = .{ |
| ... | ... | @@ -7143,7 +7282,7 @@ fn uavMapIndex( |
| 7143 | 7282 | if (!uav_gop.found_existing) { |
| 7144 | 7283 | const shndx: Section.Index = .data_rel_ro; // TODO: it would be better to use `.rodata` if the UAV value doesn't have relocs |
| 7145 | 7284 | try shndx.ensureAligned(elf, resolved_align); |
| 7146 | | const node = elf.addNodeAssumeCapacity(try shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{ |
| 7285 | const node = elf.addNodeAssumeCapacity(try shndx.node(elf).addFloatingChild(gpa, &elf.mf, .{ |
| 7147 | 7286 | .moved = true, // see assert at end of `genUav` |
| 7148 | 7287 | .alignment = resolved_align, |
| 7149 | 7288 | }), .{ .uav = umi }); |
| ... | ... | @@ -7440,6 +7579,9 @@ fn loadObject( |
| 7440 | 7579 | .type = .FILE, |
| 7441 | 7580 | .shndx = .ABS, |
| 7442 | 7581 | }) }; |
| 7582 | |
| 7583 | var input_has_bss = false; |
| 7584 | var input_has_tbss = false; |
| 7443 | 7585 | const target_endian = elf.targetEndian(); |
| 7444 | 7586 | switch (elf.identClass()) { |
| 7445 | 7587 | .NONE, _ => unreachable, |
| ... | ... | @@ -7454,13 +7596,25 @@ fn loadObject( |
| 7454 | 7596 | return diags.failParse(path, "bad section header location", .{}); |
| 7455 | 7597 | if (ehdr.shentsize < @sizeOf(ElfN.Shdr)) |
| 7456 | 7598 | return diags.failParse(path, "unsupported shentsize", .{}); |
| 7457 | | const sections = try gpa.alloc(struct { shdr: ElfN.Shdr, isi: ?InputSection.Index }, ehdr.shnum); |
| 7599 | |
| 7600 | const sections = try gpa.alloc(struct { |
| 7601 | shdr: ElfN.Shdr, |
| 7602 | placement: union(enum) { |
| 7603 | progbits: InputSection.Index, |
| 7604 | nobits: struct { |
| 7605 | shndx: Section.Index, |
| 7606 | offset: u64, |
| 7607 | }, |
| 7608 | none, |
| 7609 | }, |
| 7610 | }, ehdr.shnum); |
| 7611 | |
| 7458 | 7612 | defer gpa.free(sections); |
| 7459 | 7613 | try fr.seekTo(fl.offset + ehdr.shoff); |
| 7460 | 7614 | for (sections) |*section| { |
| 7461 | 7615 | section.* = .{ |
| 7462 | 7616 | .shdr = try r.peekStruct(ElfN.Shdr, target_endian), |
| 7463 | | .isi = null, |
| 7617 | .placement = .none, |
| 7464 | 7618 | }; |
| 7465 | 7619 | try r.discardAll(ehdr.shentsize); |
| 7466 | 7620 | switch (section.shdr.type) { |
| ... | ... | @@ -7487,24 +7641,30 @@ fn loadObject( |
| 7487 | 7641 | if (section.shdr.name >= shstrtab.len) continue; |
| 7488 | 7642 | const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0); |
| 7489 | 7643 | if (!comp.config.any_unwind_tables and std.mem.eql(u8, name, ".eh_frame")) continue; |
| 7644 | const sect_type = section.shdr.type; |
| 7490 | 7645 | const opts: struct { |
| 7491 | 7646 | shndx: Section.Index, |
| 7492 | 7647 | node_fixed: bool, |
| 7493 | | } = switch (section.shdr.type) { |
| 7648 | } = switch (sect_type) { |
| 7494 | 7649 | else => continue, |
| 7495 | 7650 | .PROGBITS, .NOBITS, .X86_64_UNWIND => opts: { |
| 7496 | 7651 | const shndx = elf.mapInputSection(.{ |
| 7497 | 7652 | .name = name, |
| 7498 | 7653 | .flags = section.shdr.flags.shf, |
| 7499 | 7654 | .entsize = section.shdr.entsize, |
| 7655 | .type = section.shdr.type, |
| 7500 | 7656 | }) catch |err| switch (err) { |
| 7501 | 7657 | else => |e| return e, |
| 7502 | 7658 | error.StripSection => continue, |
| 7503 | | error.TlsSectionUnavailable => return diags.failParse( |
| 7504 | | path, |
| 7505 | | "thread-local storage section '{s}' is incompatible with '-fsingle-threaded'", |
| 7506 | | .{name}, |
| 7507 | | ), |
| 7659 | error.TlsSectionUnavailable => { |
| 7660 | if (section.shdr.size == 0) continue; |
| 7661 | |
| 7662 | return diags.failParse( |
| 7663 | path, |
| 7664 | "thread-local storage section '{s}' is incompatible with '-fsingle-threaded'", |
| 7665 | .{name}, |
| 7666 | ); |
| 7667 | }, |
| 7508 | 7668 | error.UnsupportedSectionFlags => if (!section.shdr.flags.shf.ALLOC) { |
| 7509 | 7669 | // It probably doesn't matter, just skip this section. |
| 7510 | 7670 | continue; |
| ... | ... | @@ -7529,6 +7689,11 @@ fn loadObject( |
| 7529 | 7689 | "flags of section '{s}' conflict with other inputs", |
| 7530 | 7690 | .{name}, |
| 7531 | 7691 | ), |
| 7692 | error.UnsupportedNobitsSection => return diags.failParse( |
| 7693 | path, |
| 7694 | "unsupported section type SHT_NOBITS for non-bss section '{s}'", |
| 7695 | .{name}, |
| 7696 | ), |
| 7532 | 7697 | }; |
| 7533 | 7698 | if (section.shdr.flags.shf.COMPRESSED) { |
| 7534 | 7699 | // SHF_COMPRESSED is only allowed on non-alloc sections. |
| ... | ... | @@ -7595,7 +7760,35 @@ fn loadObject( |
| 7595 | 7760 | const need_align: Alignment = .fromByteUnits( |
| 7596 | 7761 | std.math.ceilPowerOfTwoAssert(usize, @intCast(@max(section.shdr.addralign, 1))), |
| 7597 | 7762 | ); |
| 7763 | |
| 7598 | 7764 | try opts.shndx.ensureAligned(elf, need_align); |
| 7765 | |
| 7766 | if (sect_type == .NOBITS) { |
| 7767 | const offset: u64 = switch (elf.shdrPtr(opts.shndx)) { |
| 7768 | inline else => |shdr| offset: { |
| 7769 | // Bump our BSS output section size |
| 7770 | const old_size: u64 = elf.targetLoad(&shdr.size); |
| 7771 | const offset = need_align.forward(old_size); |
| 7772 | elf.targetStore(&shdr.size, @intCast(offset + section.shdr.size)); |
| 7773 | break :offset offset; |
| 7774 | }, |
| 7775 | }; |
| 7776 | |
| 7777 | section.placement = .{ .nobits = .{ |
| 7778 | .shndx = opts.shndx, |
| 7779 | .offset = offset, |
| 7780 | } }; |
| 7781 | if (opts.shndx == elf.shndx.bss) { |
| 7782 | input_has_bss = true; |
| 7783 | } else if (opts.shndx == elf.shndx.tbss) { |
| 7784 | input_has_tbss = true; |
| 7785 | } else { |
| 7786 | assert(elf.ehdrType() == .REL); |
| 7787 | } |
| 7788 | |
| 7789 | continue; |
| 7790 | } |
| 7791 | |
| 7599 | 7792 | const add_node_opts: MappedFile.Node.AddOptions = .{ |
| 7600 | 7793 | .size = need_align.forward(section.shdr.size), |
| 7601 | 7794 | .alignment = need_align, |
| ... | ... | @@ -7603,7 +7796,7 @@ fn loadObject( |
| 7603 | 7796 | }; |
| 7604 | 7797 | const ni = elf.addNodeAssumeCapacity( |
| 7605 | 7798 | if (opts.node_fixed) ni: { |
| 7606 | | const shndx_ni = opts.shndx.get(elf).ni; |
| 7799 | const shndx_ni = opts.shndx.node(elf); |
| 7607 | 7800 | const after_oni: MappedFile.Node.Index.Optional = after: { |
| 7608 | 7801 | const last_ni = shndx_ni.last(&elf.mf).unwrap() orelse break :after .none; |
| 7609 | 7802 | break :after switch (last_ni.position(&elf.mf)) { |
| ... | ... | @@ -7612,10 +7805,10 @@ fn loadObject( |
| 7612 | 7805 | }; |
| 7613 | 7806 | }; |
| 7614 | 7807 | break :ni try shndx_ni.addHeaderChildAfter(gpa, &elf.mf, after_oni, add_node_opts); |
| 7615 | | } else try opts.shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, add_node_opts), |
| 7808 | } else try opts.shndx.node(elf).addFloatingChild(gpa, &elf.mf, add_node_opts), |
| 7616 | 7809 | .{ .input_section = @fromBackingInt(@intCast(elf.input_sections.items.len)) }, |
| 7617 | 7810 | ); |
| 7618 | | section.isi = @fromBackingInt(@intCast(elf.input_sections.items.len)); |
| 7811 | section.placement = .{ .progbits = @fromBackingInt(@intCast(elf.input_sections.items.len)) }; |
| 7619 | 7812 | elf.input_sections.addOneAssumeCapacity().* = .{ |
| 7620 | 7813 | .input = input_index, |
| 7621 | 7814 | .file_location = .{ |
| ... | ... | @@ -7712,7 +7905,33 @@ fn loadObject( |
| 7712 | 7905 | }, |
| 7713 | 7906 | }; |
| 7714 | 7907 | |
| 7715 | | const input_section_node = (sections[input_sym.shndx].isi orelse continue).node(elf); |
| 7908 | const symbol_oni: MappedFile.Node.Index.Optional, const output_shndx: Section.Index, const symbol_value: u64 = switch (sections[input_sym.shndx].placement) { |
| 7909 | .none => continue, |
| 7910 | .progbits => |isi| .{ |
| 7911 | .wrap(isi.node(elf)), |
| 7912 | elf.getNodeShndx(isi.node(elf)), |
| 7913 | input_sym.value, |
| 7914 | }, |
| 7915 | .nobits => |nobits| sym: { |
| 7916 | const section_base: u64 = switch (elf.ehdrType()) { |
| 7917 | .REL => 0, |
| 7918 | .EXEC, .DYN => base: { |
| 7919 | if (elf.ni.tls != .none and |
| 7920 | nobits.shndx == elf.shndx.tbss) |
| 7921 | { |
| 7922 | break :base elf.tbssOffset(); |
| 7923 | } |
| 7924 | assert(nobits.shndx == elf.shndx.bss); |
| 7925 | break :base nobits.shndx.vaddr(elf); |
| 7926 | }, |
| 7927 | }; |
| 7928 | break :sym .{ |
| 7929 | .none, |
| 7930 | nobits.shndx, |
| 7931 | section_base + nobits.offset + input_sym.value, |
| 7932 | }; |
| 7933 | }, |
| 7934 | }; |
| 7716 | 7935 | |
| 7717 | 7936 | switch (input_sym.info.bind) { |
| 7718 | 7937 | else => |bind| return diags.failParse( |
| ... | ... | @@ -7722,20 +7941,20 @@ fn loadObject( |
| 7722 | 7941 | ), |
| 7723 | 7942 | .LOCAL => { |
| 7724 | 7943 | const lsi = try elf.addLocalSymbol(.{ |
| 7725 | | .node = .wrap(input_section_node), |
| 7944 | .node = symbol_oni, |
| 7726 | 7945 | .name = name, |
| 7727 | | .value = input_sym.value, |
| 7946 | .value = symbol_value, |
| 7728 | 7947 | .size = input_sym.size, |
| 7729 | 7948 | .type = sym_type, |
| 7730 | | .shndx = elf.getNodeShndx(input_section_node), |
| 7949 | .shndx = output_shndx, |
| 7731 | 7950 | }); |
| 7732 | 7951 | si.* = .local(lsi); |
| 7733 | 7952 | }, |
| 7734 | 7953 | .GLOBAL, .WEAK, .GNU_UNIQUE => |bind| { |
| 7735 | 7954 | si.* = .global(elf.addGlobalSymbol(.{ |
| 7736 | | .node = .wrap(input_section_node), |
| 7955 | .node = symbol_oni, |
| 7737 | 7956 | .name = name, |
| 7738 | | .value = input_sym.value, |
| 7957 | .value = symbol_value, |
| 7739 | 7958 | .size = input_sym.size, |
| 7740 | 7959 | .type = sym_type, |
| 7741 | 7960 | .bind = switch (bind) { |
| ... | ... | @@ -7744,7 +7963,7 @@ fn loadObject( |
| 7744 | 7963 | else => unreachable, |
| 7745 | 7964 | }, |
| 7746 | 7965 | .visibility = input_sym.other.visibility, |
| 7747 | | .shndx = elf.getNodeShndx(input_section_node), |
| 7966 | .shndx = output_shndx, |
| 7748 | 7967 | }) catch |err| switch (err) { |
| 7749 | 7968 | error.MultipleDefinitions => return diags.failParse( |
| 7750 | 7969 | path, |
| ... | ... | @@ -7776,7 +7995,16 @@ fn loadObject( |
| 7776 | 7995 | return diags.failParse(path, "unsupported rel entsize", .{}); |
| 7777 | 7996 | |
| 7778 | 7997 | const loc_sec = &sections[rel_sec.shdr.info]; |
| 7779 | | const loc_node = (loc_sec.isi orelse continue).node(elf); |
| 7998 | const loc_node = switch (loc_sec.placement) { |
| 7999 | .none => continue, |
| 8000 | .progbits => |isi| isi.node(elf), |
| 8001 | .nobits => return diags.failParse( |
| 8002 | path, |
| 8003 | "cannot apply relocation to SHT_NOBITS section '{s}'", |
| 8004 | .{std.mem.sliceTo(shstrtab[loc_sec.shdr.name..], 0)}, |
| 8005 | ), |
| 8006 | }; |
| 8007 | |
| 7780 | 8008 | elf.resetNodeRelocs(loc_node); |
| 7781 | 8009 | |
| 7782 | 8010 | const relnum = std.math.divExact( |
| ... | ... | @@ -7843,6 +8071,16 @@ fn loadObject( |
| 7843 | 8071 | }; |
| 7844 | 8072 | }, |
| 7845 | 8073 | }; |
| 8074 | |
| 8075 | if (input_has_bss) { |
| 8076 | try elf.bss_inputs.append(gpa, input_index); |
| 8077 | try elf.ni.data.resized(gpa, &elf.mf); |
| 8078 | } |
| 8079 | |
| 8080 | if (input_has_tbss) { |
| 8081 | try elf.tbss_inputs.append(gpa, input_index); |
| 8082 | try elf.ni.tls.unwrap().?.resized(gpa, &elf.mf); |
| 8083 | } |
| 7846 | 8084 | }, |
| 7847 | 8085 | } |
| 7848 | 8086 | } |
| ... | ... | @@ -8327,7 +8565,7 @@ fn createInitFiniArraySection( |
| 8327 | 8565 | .version = null, |
| 8328 | 8566 | }).?; |
| 8329 | 8567 | try elf.setGlobalSymbolValue(start_gsi, .{ |
| 8330 | | .node = .wrap(shndx.get(elf).ni), |
| 8568 | .node = .wrap(shndx.node(elf)), |
| 8331 | 8569 | .value = shndx.vaddr(elf), |
| 8332 | 8570 | .size = 0, |
| 8333 | 8571 | .type = .NOTYPE, |
| ... | ... | @@ -8335,7 +8573,7 @@ fn createInitFiniArraySection( |
| 8335 | 8573 | }); |
| 8336 | 8574 | try elf.updateGlobalDynamic(start_gsi, true); |
| 8337 | 8575 | try elf.setGlobalSymbolValue(end_gsi, .{ |
| 8338 | | .node = .wrap(shndx.get(elf).ni), |
| 8576 | .node = .wrap(shndx.node(elf)), |
| 8339 | 8577 | .value = shndx.vaddr(elf), |
| 8340 | 8578 | .size = 0, |
| 8341 | 8579 | .type = .NOTYPE, |
| ... | ... | @@ -8388,7 +8626,7 @@ fn prelinkInner(elf: *Elf) Error!void { |
| 8388 | 8626 | elf.shndx.debug_str_offsets, |
| 8389 | 8627 | }) |debug_shndx| { |
| 8390 | 8628 | if (debug_shndx == .UNDEF) continue; |
| 8391 | | const debug_ni = debug_shndx.get(elf).ni; |
| 8629 | const debug_ni = debug_shndx.node(elf); |
| 8392 | 8630 | const frame_format = debug_shndx.debugFrameFormat(elf); |
| 8393 | 8631 | const unit_padding_ni = elf.addNodeAssumeCapacity( |
| 8394 | 8632 | try debug_ni.addHeaderChildAfter(gpa, &elf.mf, last_header_oni: { |
| ... | ... | @@ -8444,7 +8682,7 @@ fn prelinkInner(elf: *Elf) Error!void { |
| 8444 | 8682 | .UNDEF => {}, |
| 8445 | 8683 | else => |debug_addr_shndx| { |
| 8446 | 8684 | const debug_addr_ni = elf.addNodeAssumeCapacity( |
| 8447 | | try debug_addr_shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{ |
| 8685 | try debug_addr_shndx.node(elf).addFloatingChild(gpa, &elf.mf, .{ |
| 8448 | 8686 | .alignment = addr_align, |
| 8449 | 8687 | .next_moved = true, |
| 8450 | 8688 | .enable_next_moved = true, |
| ... | ... | @@ -8465,7 +8703,7 @@ fn prelinkInner(elf: *Elf) Error!void { |
| 8465 | 8703 | switch (elf.shndx.debug_abbrev) { |
| 8466 | 8704 | .UNDEF => {}, |
| 8467 | 8705 | else => |debug_abbrev_shndx| elf.dwarf.debug_abbrev.ni = .wrap(elf.addNodeAssumeCapacity( |
| 8468 | | try debug_abbrev_shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{}), |
| 8706 | try debug_abbrev_shndx.node(elf).addFloatingChild(gpa, &elf.mf, .{}), |
| 8469 | 8707 | .{ .debug_shared = .debug_abbrev }, |
| 8470 | 8708 | )), |
| 8471 | 8709 | } |
| ... | ... | @@ -8473,14 +8711,14 @@ fn prelinkInner(elf: *Elf) Error!void { |
| 8473 | 8711 | .UNDEF => {}, |
| 8474 | 8712 | else => |debug_line_str_shndx| elf.dwarf.debug_line_str.ni = |
| 8475 | 8713 | .wrap(elf.addNodeAssumeCapacity( |
| 8476 | | try debug_line_str_shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{}), |
| 8714 | try debug_line_str_shndx.node(elf).addFloatingChild(gpa, &elf.mf, .{}), |
| 8477 | 8715 | .{ .debug_shared = .debug_line_str }, |
| 8478 | 8716 | )), |
| 8479 | 8717 | } |
| 8480 | 8718 | switch (elf.shndx.debug_str) { |
| 8481 | 8719 | .UNDEF => {}, |
| 8482 | 8720 | else => |debug_str_shndx| elf.dwarf.debug_str.ni = .wrap(elf.addNodeAssumeCapacity( |
| 8483 | | try debug_str_shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{}), |
| 8721 | try debug_str_shndx.node(elf).addFloatingChild(gpa, &elf.mf, .{}), |
| 8484 | 8722 | .{ .debug_shared = .debug_str }, |
| 8485 | 8723 | )), |
| 8486 | 8724 | } |
| ... | ... | @@ -8488,7 +8726,7 @@ fn prelinkInner(elf: *Elf) Error!void { |
| 8488 | 8726 | .UNDEF => {}, |
| 8489 | 8727 | else => |debug_str_offsets_shndx| { |
| 8490 | 8728 | const debug_str_offsets_ni = elf.addNodeAssumeCapacity( |
| 8491 | | try debug_str_offsets_shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{ |
| 8729 | try debug_str_offsets_shndx.node(elf).addFloatingChild(gpa, &elf.mf, .{ |
| 8492 | 8730 | .alignment = switch (elf.dwarf.format) { |
| 8493 | 8731 | .@"32" => .@"4", |
| 8494 | 8732 | .@"64" => .@"8", |
| ... | ... | @@ -8549,7 +8787,7 @@ fn zcuFilesReadyInner(elf: *Elf, zcu: *Zcu) Error!void { |
| 8549 | 8787 | else => |debug_info_shndx| { |
| 8550 | 8788 | const debug_info_ni = unit.debug_info_ni.unwrap() orelse debug_info_ni: { |
| 8551 | 8789 | const debug_info_ni = elf.addNodeAssumeCapacity( |
| 8552 | | try debug_info_shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{ |
| 8790 | try debug_info_shndx.node(elf).addFloatingChild(gpa, &elf.mf, .{ |
| 8553 | 8791 | .alignment = elf.mf.flags.block_size, |
| 8554 | 8792 | .enable_next_moved = true, |
| 8555 | 8793 | }), |
| ... | ... | @@ -8576,7 +8814,7 @@ fn zcuFilesReadyInner(elf: *Elf, zcu: *Zcu) Error!void { |
| 8576 | 8814 | else => |debug_line_shndx| { |
| 8577 | 8815 | const debug_line_ni = unit.debug_line_ni.unwrap() orelse debug_line_ni: { |
| 8578 | 8816 | const debug_line_ni = elf.addNodeAssumeCapacity( |
| 8579 | | try debug_line_shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{ |
| 8817 | try debug_line_shndx.node(elf).addFloatingChild(gpa, &elf.mf, .{ |
| 8580 | 8818 | .alignment = elf.mf.flags.block_size, |
| 8581 | 8819 | .enable_next_moved = true, |
| 8582 | 8820 | }), |
| ... | ... | @@ -8600,7 +8838,7 @@ fn zcuFilesReadyInner(elf: *Elf, zcu: *Zcu) Error!void { |
| 8600 | 8838 | else => |debug_rnglists_shndx| { |
| 8601 | 8839 | const debug_rnglists_ni = unit.debug_rnglists_ni.unwrap() orelse debug_rnglists_ni: { |
| 8602 | 8840 | const debug_rnglists_ni = elf.addNodeAssumeCapacity( |
| 8603 | | try debug_rnglists_shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{ |
| 8841 | try debug_rnglists_shndx.node(elf).addFloatingChild(gpa, &elf.mf, .{ |
| 8604 | 8842 | .next_moved = true, |
| 8605 | 8843 | .enable_next_moved = true, |
| 8606 | 8844 | }), |
| ... | ... | @@ -8680,7 +8918,7 @@ fn prepareDynamic(elf: *Elf) Error!void { |
| 8680 | 8918 | |
| 8681 | 8919 | const dynamic_size = dynamic_len * 2 * elf.targetPtrSize(); |
| 8682 | 8920 | |
| 8683 | | try elf.shndx.dynamic.get(elf).ni.resizeLeaf(comp.gpa, &elf.mf, dynamic_size); |
| 8921 | try elf.shndx.dynamic.node(elf).resizeLeaf(comp.gpa, &elf.mf, dynamic_size); |
| 8684 | 8922 | switch (elf.shdrPtr(elf.shndx.dynamic)) { |
| 8685 | 8923 | inline else => |shdr| elf.targetStore(&shdr.size, @intCast(dynamic_size)), |
| 8686 | 8924 | } |
| ... | ... | @@ -8702,7 +8940,7 @@ fn flushDynamic(elf: *Elf) void { |
| 8702 | 8940 | comp.config.pie); |
| 8703 | 8941 | |
| 8704 | 8942 | const dynamic_size = elf.targetLoad(&@field(elf.shdrPtr(elf.shndx.dynamic), @tagName(class)).size); |
| 8705 | | const dynamic_slice = elf.shndx.dynamic.get(elf).ni.slice(&elf.mf)[0..@intCast(dynamic_size)]; |
| 8943 | const dynamic_slice = elf.shndx.dynamic.node(elf).slice(&elf.mf)[0..@intCast(dynamic_size)]; |
| 8706 | 8944 | const dynamic_entries: [][2]ElfN.Addr = @ptrCast(@alignCast(dynamic_slice)); |
| 8707 | 8945 | |
| 8708 | 8946 | var dynamic_index: usize = 0; |
| ... | ... | @@ -8816,6 +9054,8 @@ fn flushDynamic(elf: *Elf) void { |
| 8816 | 9054 | |
| 8817 | 9055 | fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 8818 | 9056 | name: []const u8 = "", |
| 9057 | /// If this is `.NOBITS`, then the section's address is initialized to 0, and it is the caller's |
| 9058 | /// responsibility to populate it. |
| 8819 | 9059 | type: std.elf.SHT = .NULL, |
| 8820 | 9060 | flags: std.elf.SHF = .{}, |
| 8821 | 9061 | size: std.elf.Xword = 0, |
| ... | ... | @@ -8836,7 +9076,9 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 8836 | 9076 | try elf.ensureSegmentAligned(phndx, opts.addralign); |
| 8837 | 9077 | } |
| 8838 | 9078 | const gpa = elf.base.comp.gpa; |
| 8839 | | try elf.nodes.ensureUnusedCapacity(gpa, 1); |
| 9079 | if (opts.type != .NOBITS) { |
| 9080 | try elf.nodes.ensureUnusedCapacity(gpa, 1); |
| 9081 | } |
| 8840 | 9082 | try elf.shdrs.ensureUnusedCapacity(gpa, 1); |
| 8841 | 9083 | const want_symbol = opts.flags.ALLOC or switch (opts.type) { |
| 8842 | 9084 | .NULL, .PROGBITS, .NOBITS, .X86_64_UNWIND => elf.ehdrType() == .REL, |
| ... | ... | @@ -8877,26 +9119,29 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 8877 | 9119 | .EXEC, .DYN => segment_ni, |
| 8878 | 9120 | }; |
| 8879 | 9121 | assert(opts.addralign.check(opts.size)); |
| 8880 | | const ni = elf.addNodeAssumeCapacity(try parent_ni.addFloatingChild(gpa, &elf.mf, .{ |
| 8881 | | .size = opts.node_align.forward(opts.size), |
| 8882 | | .alignment = opts.addralign.max(opts.node_align), |
| 8883 | | .resized = opts.size > 0, |
| 8884 | | .bubbles_moved = opts.flags.ALLOC, |
| 8885 | | }), switch (opts.manual_size) { |
| 8886 | | false => .{ .section = shndx }, |
| 8887 | | true => .{ .section_manual_size = shndx }, |
| 8888 | | }); |
| 8889 | | const addr = elf.computeNodeVAddr(ni); |
| 9122 | const oni: MappedFile.Node.Index.Optional = switch (opts.type) { |
| 9123 | .NOBITS => .none, |
| 9124 | else => .wrap(elf.addNodeAssumeCapacity( |
| 9125 | try parent_ni.addFloatingChild(gpa, &elf.mf, .{ |
| 9126 | .size = opts.node_align.forward(opts.size), |
| 9127 | .alignment = opts.addralign.max(opts.node_align), |
| 9128 | .resized = opts.size > 0, |
| 9129 | .bubbles_moved = opts.flags.ALLOC, |
| 9130 | }), |
| 9131 | if (opts.manual_size) .{ .section_manual_size = shndx } else .{ .section = shndx }, |
| 9132 | )), |
| 9133 | }; |
| 9134 | const addr = if (oni.unwrap()) |ni| elf.computeNodeVAddr(ni) else 0; |
| 8890 | 9135 | elf.shdrs.appendAssumeCapacity(.{ |
| 8891 | 9136 | .lsi = if (want_symbol) try elf.addLocalSymbol(.{ |
| 8892 | | .node = ni.toOptional(), |
| 9137 | .node = oni, |
| 8893 | 9138 | .name = "", |
| 8894 | 9139 | .value = addr, |
| 8895 | 9140 | .size = 0, |
| 8896 | 9141 | .type = .SECTION, |
| 8897 | 9142 | .shndx = shndx, |
| 8898 | 9143 | }) else .null, |
| 8899 | | .ni = ni, |
| 9144 | .ni = oni, |
| 8900 | 9145 | .rela = switch (opts.type) { |
| 8901 | 9146 | .REL => unreachable, |
| 8902 | 9147 | .RELA => .{ .free_head = .none }, |
| ... | ... | @@ -8910,7 +9155,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 8910 | 9155 | .type = opts.type, |
| 8911 | 9156 | .flags = .{ .shf = opts.flags }, |
| 8912 | 9157 | .addr = @intCast(addr), |
| 8913 | | .offset = @intCast(elf.computeNodeElfOffset(ni)), |
| 9158 | .offset = if (oni.unwrap()) |ni| @intCast(elf.computeNodeElfOffset(ni)) else 0, |
| 8914 | 9159 | .size = @intCast(opts.size), |
| 8915 | 9160 | .link = opts.link, |
| 8916 | 9161 | .info = opts.info, |
| ... | ... | @@ -8973,7 +9218,7 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize) |
| 8973 | 9218 | .NONE, _ => unreachable, |
| 8974 | 9219 | inline else => |ct_class| (elf.got.count() + new_got_entries) * @sizeOf(ct_class.ElfN().Addr), |
| 8975 | 9220 | }; |
| 8976 | | try elf.shndx.got.get(elf).ni.ensureMinimumSize(gpa, &elf.mf, need_got_size); |
| 9221 | try elf.shndx.got.node(elf).ensureMinimumSize(gpa, &elf.mf, need_got_size); |
| 8977 | 9222 | |
| 8978 | 9223 | if (elf.shndx.dynamic != .UNDEF) { |
| 8979 | 9224 | try elf.shndx.rela_dyn.relaEnsureAdditionalCapacity(elf, new_got_entries); |
| ... | ... | @@ -9816,7 +10061,7 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void { |
| 9816 | 10061 | const addr_size = @sizeOf(class.ElfN().Addr); |
| 9817 | 10062 | const offset = got_index * addr_size; |
| 9818 | 10063 | const entry_ptr: *class.ElfN().Addr = @ptrCast(@alignCast( |
| 9819 | | elf.shndx.got.get(elf).ni.slice(&elf.mf)[offset..][0..addr_size], |
| 10064 | elf.shndx.got.node(elf).slice(&elf.mf)[offset..][0..addr_size], |
| 9820 | 10065 | )); |
| 9821 | 10066 | elf.targetStore(entry_ptr, switch (entry_value) { |
| 9822 | 10067 | .unsigned => |x| @intCast(x), |
| ... | ... | @@ -10179,7 +10424,7 @@ fn updateFuncInner( |
| 10179 | 10424 | const frame_ni = elf.addNodeAssumeCapacity(try switch (wip_func.frame_format) { |
| 10180 | 10425 | .debug_frame => elf.shndx.debug_frame, |
| 10181 | 10426 | .eh_frame => elf.shndx.eh_frame, |
| 10182 | | }.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{ |
| 10427 | }.node(elf).addFloatingChild(gpa, &elf.mf, .{ |
| 10183 | 10428 | .alignment = frame_align.max(elf.mf.flags.block_size), |
| 10184 | 10429 | .enable_next_moved = true, |
| 10185 | 10430 | }), .{ .unit_frame = wip_func.unit }); |
| ... | ... | @@ -10624,12 +10869,46 @@ pub fn idle(elf: *Elf) link.Error!bool { |
| 10624 | 10869 | if (clean_moved or clean_resized or clean_next_moved) try elf.flushPadding(ni); |
| 10625 | 10870 | break :task; |
| 10626 | 10871 | } |
| 10872 | if (elf.bss_moved) { |
| 10873 | elf.bss_moved = false; |
| 10874 | |
| 10875 | const data_phndx = elf.getNode(elf.ni.data).segment; |
| 10876 | const data_offset: u64, const data_vaddr: u64, const data_filesz: u64 = switch (elf.phdrSlice()) { |
| 10877 | inline else => |phdr| .{ |
| 10878 | elf.targetLoad(&phdr[data_phndx].offset), |
| 10879 | elf.targetLoad(&phdr[data_phndx].vaddr), |
| 10880 | elf.targetLoad(&phdr[data_phndx].filesz), |
| 10881 | }, |
| 10882 | }; |
| 10883 | |
| 10884 | const old_bss_addr = elf.shndx.bss.vaddr(elf); |
| 10885 | const new_bss_addr = data_vaddr + data_filesz; |
| 10886 | |
| 10887 | const bss_section_sym: Symbol.Id = .local(elf.shndx.bss.get(elf).lsi); |
| 10888 | bss_section_sym.flushMoved(elf, new_bss_addr); |
| 10889 | switch (elf.shdrPtr(elf.shndx.bss)) { |
| 10890 | inline else => |shdr| { |
| 10891 | elf.targetStore(&shdr.offset, @intCast(data_offset + data_filesz)); |
| 10892 | elf.targetStore(&shdr.addr, @intCast(new_bss_addr)); |
| 10893 | }, |
| 10894 | } |
| 10895 | elf.flushMovedNobitsSymbols( |
| 10896 | elf.shndx.bss, |
| 10897 | old_bss_addr, |
| 10898 | new_bss_addr, |
| 10899 | elf.bss_inputs.items, |
| 10900 | elf.bss_globals.keys(), |
| 10901 | ); |
| 10902 | |
| 10903 | break :task; |
| 10904 | } |
| 10627 | 10905 | } |
| 10628 | 10906 | if (elf.inputs.items.len - elf.input_pending_index > 0) return true; |
| 10629 | 10907 | if (elf.input_sections.items.len - elf.input_section_pending_index > 0) return true; |
| 10630 | 10908 | if (elf.one_shot_fixups.items.len > 0) return true; |
| 10631 | 10909 | if (elf.changed_symtab_index.count() > 0) return true; |
| 10632 | 10910 | if (elf.mf.updates.items.len > 0) return true; |
| 10911 | if (elf.bss_moved) return true; |
| 10633 | 10912 | return false; |
| 10634 | 10913 | } |
| 10635 | 10914 | |
| ... | ... | @@ -10984,8 +11263,23 @@ fn flushElfOffset(elf: *Elf, ni: MappedFile.Node.Index) void { |
| 10984 | 11263 | inline else => |phdr, class| { |
| 10985 | 11264 | const ph = &phdr[phndx]; |
| 10986 | 11265 | elf.targetStore(&ph.offset, @intCast(elf_offset)); |
| 10987 | | if (elf.targetLoad(&ph.type) == .PHDR) { |
| 10988 | | @field(elf.ehdrPtr(), @tagName(class)).phoff = ph.offset; |
| 11266 | switch (elf.targetLoad(&ph.type)) { |
| 11267 | .PHDR => { |
| 11268 | const ehdr = @field(elf.ehdrPtr(), @tagName(class)); |
| 11269 | elf.targetStore(&ehdr.phoff, @intCast(elf_offset)); |
| 11270 | }, |
| 11271 | .TLS => { |
| 11272 | // The `.tbss` section's offset should be at the end of the TLS segment. |
| 11273 | const tls_filesz = elf.targetLoad(&ph.filesz); |
| 11274 | const tbss_shdr = @field(elf.shdrPtr(elf.shndx.tbss), @tagName(class)); |
| 11275 | elf.targetStore(&tbss_shdr.offset, @intCast(elf_offset + tls_filesz)); |
| 11276 | }, |
| 11277 | else => if (ni == elf.ni.data) { |
| 11278 | // The `.bss` section's offset should be at the end of the data segment. |
| 11279 | const data_filesz = elf.targetLoad(&ph.filesz); |
| 11280 | const bss_shdr = @field(elf.shdrPtr(elf.shndx.bss), @tagName(class)); |
| 11281 | elf.targetStore(&bss_shdr.offset, @intCast(elf_offset + data_filesz)); |
| 11282 | }, |
| 10989 | 11283 | } |
| 10990 | 11284 | }, |
| 10991 | 11285 | } |
| ... | ... | @@ -11027,7 +11321,6 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void |
| 11027 | 11321 | .DYNAMIC, |
| 11028 | 11322 | .INTERP, |
| 11029 | 11323 | .PHDR, |
| 11030 | | .TLS, |
| 11031 | 11324 | .GNU_EH_FRAME, |
| 11032 | 11325 | .GNU_RELRO, |
| 11033 | 11326 | => { |
| ... | ... | @@ -11035,6 +11328,22 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void |
| 11035 | 11328 | elf.targetStore(&ph.vaddr, @intCast(new_vaddr)); |
| 11036 | 11329 | elf.targetStore(&ph.paddr, @intCast(new_vaddr)); |
| 11037 | 11330 | }, |
| 11331 | |
| 11332 | .TLS => { |
| 11333 | const new_vaddr = elf.computeNodeVAddr(ni); |
| 11334 | elf.targetStore(&ph.vaddr, @intCast(new_vaddr)); |
| 11335 | elf.targetStore(&ph.paddr, @intCast(new_vaddr)); |
| 11336 | |
| 11337 | // Update the address of the `.tbss` section at the end of this segment: |
| 11338 | const tbss_addr = new_vaddr + elf.tbssOffset(); |
| 11339 | switch (elf.shdrPtr(elf.shndx.tbss)) { |
| 11340 | inline else => |shdr| elf.targetStore(&shdr.addr, @intCast(tbss_addr)), |
| 11341 | } |
| 11342 | Symbol.Id.local(elf.shndx.tbss.get(elf).lsi).flushMoved( |
| 11343 | elf, |
| 11344 | tbss_addr, |
| 11345 | ); |
| 11346 | }, |
| 11038 | 11347 | } |
| 11039 | 11348 | }, |
| 11040 | 11349 | } |
| ... | ... | @@ -11365,6 +11674,89 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void |
| 11365 | 11674 | try ni.childrenMoved(elf.base.comp.gpa, &elf.mf); |
| 11366 | 11675 | } |
| 11367 | 11676 | |
| 11677 | /// Update the value of all symbols in a `NOBITS` section. All symbol values are updated to |
| 11678 | /// `old_value - old_symbol_base + new_symbol_base`. |
| 11679 | /// |
| 11680 | /// For `.bss`, the symbol base is the section's virtual address. |
| 11681 | /// |
| 11682 | /// For `.tbss`, the symbol base is the offset into the TLS segment. |
| 11683 | fn flushMovedNobitsSymbols( |
| 11684 | elf: *Elf, |
| 11685 | shndx: Section.Index, |
| 11686 | old_symbol_base: u64, |
| 11687 | new_symbol_base: u64, |
| 11688 | inputs: []const Node.InputIndex, |
| 11689 | globals: []const Symbol.Global.Index, |
| 11690 | ) void { |
| 11691 | assert(shndx != .UNDEF); |
| 11692 | |
| 11693 | // Update local symbols. |
| 11694 | for (inputs) |ii| { |
| 11695 | var lsi, const end_lsi = ii.localSymbolRange(elf); |
| 11696 | |
| 11697 | while (lsi != end_lsi) : (lsi = @fromBackingInt( |
| 11698 | @backingInt(lsi) + 1, |
| 11699 | )) { |
| 11700 | const sym_shndx: Section.Index, const visibility = switch (elf.symPtr(lsi.index())) { |
| 11701 | inline else => |sym| .{ |
| 11702 | .fromSection(elf.targetLoad(&sym.shndx)), |
| 11703 | elf.targetLoad(&sym.other).visibility, |
| 11704 | }, |
| 11705 | }; |
| 11706 | |
| 11707 | if (sym_shndx != shndx) continue; |
| 11708 | |
| 11709 | switch (visibility) { |
| 11710 | // These are globals demoted to STB_LOCAL and are updated below. |
| 11711 | .HIDDEN, .INTERNAL => continue, |
| 11712 | .PROTECTED => unreachable, |
| 11713 | .DEFAULT => {}, |
| 11714 | } |
| 11715 | |
| 11716 | const symbol: Symbol.Id = .local(lsi); |
| 11717 | symbol.flushMoved( |
| 11718 | elf, |
| 11719 | symbol.value(elf) - old_symbol_base + new_symbol_base, |
| 11720 | ); |
| 11721 | } |
| 11722 | } |
| 11723 | |
| 11724 | // Update global symbols. |
| 11725 | for (globals) |gsi| { |
| 11726 | const symbol: Symbol.Id = .global(gsi); |
| 11727 | |
| 11728 | const sym_shndx: Section.Index = switch (elf.symPtr(symbol.index(elf))) { |
| 11729 | inline else => |sym| .fromSection(elf.targetLoad(&sym.shndx)), |
| 11730 | }; |
| 11731 | assert(sym_shndx == shndx); |
| 11732 | |
| 11733 | symbol.flushMoved( |
| 11734 | elf, |
| 11735 | symbol.value(elf) - old_symbol_base + new_symbol_base, |
| 11736 | ); |
| 11737 | } |
| 11738 | } |
| 11739 | |
| 11740 | /// Updates `vaddr` and `paddr` of the segment header, and marks everything in the segment as moved. |
| 11741 | fn updateSegmentLoadAddress( |
| 11742 | elf: *Elf, |
| 11743 | segment_ni: MappedFile.Node.Index, |
| 11744 | new_vaddr: u64, |
| 11745 | ) std.mem.Allocator.Error!void { |
| 11746 | const phndx = elf.getNode(segment_ni).segment; |
| 11747 | |
| 11748 | switch (elf.phdrSlice()) { |
| 11749 | inline else => |phdr| { |
| 11750 | assert(new_vaddr != elf.targetLoad(&phdr[phndx].vaddr)); |
| 11751 | elf.targetStore(&phdr[phndx].vaddr, @intCast(new_vaddr)); |
| 11752 | elf.targetStore(&phdr[phndx].paddr, @intCast(new_vaddr)); |
| 11753 | }, |
| 11754 | } |
| 11755 | |
| 11756 | try segment_ni.childrenMoved(elf.base.comp.gpa, &elf.mf); |
| 11757 | if (segment_ni == elf.ni.data) elf.bss_moved = true; |
| 11758 | } |
| 11759 | |
| 11368 | 11760 | /// Given the index of a `PT_LOAD`/`PT_NULL` segment, assumes that the phdr's `offset` and `filesz` |
| 11369 | 11761 | /// have been updated as needed by the caller, and updates the `@"align"`, `vaddr`, `paddr`, and |
| 11370 | 11762 | /// `memsz` fields of the segment, in order to place it at a valid virtual address. |
| ... | ... | @@ -11393,22 +11785,23 @@ fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Erro |
| 11393 | 11785 | switch (elf.phdrSlice()) { |
| 11394 | 11786 | inline else => |phdr| { |
| 11395 | 11787 | const offset = elf.targetLoad(&phdr[orig_phndx].offset); |
| 11396 | | const size = elf.targetLoad(&phdr[orig_phndx].filesz); |
| 11397 | | |
| 11398 | | if (size == 0) { |
| 11399 | | assert(elf.targetLoad(&phdr[orig_phndx].type) == .NULL); |
| 11400 | | } else { |
| 11401 | | assert(elf.targetLoad(&phdr[orig_phndx].type) == .LOAD); |
| 11402 | | } |
| 11403 | | |
| 11404 | | elf.targetStore(&phdr[orig_phndx].memsz, size); |
| 11405 | | elf.targetStore(&phdr[orig_phndx].@"align", @intCast(ph_align.toByteUnits())); |
| 11788 | const filesz = elf.targetLoad(&phdr[orig_phndx].filesz); |
| 11406 | 11789 | |
| 11407 | 11790 | const orig_vaddr = elf.targetLoad(&phdr[orig_phndx].vaddr); |
| 11408 | 11791 | assert(elf.targetLoad(&phdr[orig_phndx].paddr) == orig_vaddr); |
| 11409 | 11792 | |
| 11793 | const bss_size = if (segment_ni == elf.ni.data) |
| 11794 | elf.shndx.bss.size(elf) |
| 11795 | else |
| 11796 | 0; |
| 11797 | const memsz = filesz + bss_size; |
| 11798 | |
| 11410 | 11799 | var vaddr: u64 = orig_vaddr; |
| 11411 | 11800 | |
| 11801 | elf.targetStore(&phdr[orig_phndx].@"align", @intCast(ph_align.toByteUnits())); |
| 11802 | elf.targetStore(&phdr[orig_phndx].memsz, @intCast(memsz)); |
| 11803 | elf.targetStore(&phdr[orig_phndx].type, if (memsz > 0) .LOAD else .NULL); |
| 11804 | |
| 11412 | 11805 | // First, we will shift the virtual address as needed in order to maintain the required |
| 11413 | 11806 | // property that vaddr is congruent to offset modulo the phdr alignment. |
| 11414 | 11807 | { |
| ... | ... | @@ -11452,7 +11845,7 @@ fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Erro |
| 11452 | 11845 | // the segment is already known to be moving---making it easier to grow in-place is |
| 11453 | 11846 | // the whole point of the multiplier! |
| 11454 | 11847 | { |
| 11455 | | const target_size = if (vaddr == orig_vaddr) size else size * reserve_size_multiplier; |
| 11848 | const target_size = if (vaddr == orig_vaddr) memsz else memsz * reserve_size_multiplier; |
| 11456 | 11849 | if (vaddr + target_size <= next_page_vaddr) { |
| 11457 | 11850 | break; // hooray, we fit here! |
| 11458 | 11851 | } |
| ... | ... | @@ -11474,17 +11867,13 @@ fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Erro |
| 11474 | 11867 | else => {}, |
| 11475 | 11868 | }; |
| 11476 | 11869 | |
| 11477 | | const free_vaddr = vaddr + size * reserve_size_multiplier; |
| 11870 | const free_vaddr = vaddr + memsz * reserve_size_multiplier; |
| 11478 | 11871 | |
| 11479 | 11872 | const next_align = page_align.max(next_ni.alignment(&elf.mf)); |
| 11480 | 11873 | const next_offset = elf.targetLoad(&next_ph.offset); |
| 11481 | 11874 | const next_new_vaddr = next_align.forward(free_vaddr) + next_offset % next_align.toByteUnits(); |
| 11482 | 11875 | |
| 11483 | | // This logic for updating the data segment's vaddr is identical to how we |
| 11484 | | // will update the vaddr of `phndx` when we break from the loop. |
| 11485 | | elf.targetStore(&next_ph.vaddr, @intCast(next_new_vaddr)); |
| 11486 | | elf.targetStore(&next_ph.paddr, @intCast(next_new_vaddr)); |
| 11487 | | try next_ni.childrenMoved(elf.base.comp.gpa, &elf.mf); |
| 11876 | try elf.updateSegmentLoadAddress(next_ni, next_new_vaddr); |
| 11488 | 11877 | |
| 11489 | 11878 | break; |
| 11490 | 11879 | }, |
| ... | ... | @@ -11507,9 +11896,7 @@ fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Erro |
| 11507 | 11896 | } |
| 11508 | 11897 | |
| 11509 | 11898 | if (vaddr != orig_vaddr) { |
| 11510 | | elf.targetStore(&phdr[phndx].vaddr, @intCast(vaddr)); |
| 11511 | | elf.targetStore(&phdr[phndx].paddr, @intCast(vaddr)); |
| 11512 | | try segment_ni.childrenMoved(elf.base.comp.gpa, &elf.mf); |
| 11899 | try elf.updateSegmentLoadAddress(segment_ni, vaddr); |
| 11513 | 11900 | } |
| 11514 | 11901 | }, |
| 11515 | 11902 | } |
| ... | ... | @@ -11539,21 +11926,50 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo |
| 11539 | 11926 | .ehdr => unreachable, |
| 11540 | 11927 | .shdr => {}, |
| 11541 | 11928 | .segment => |phndx| switch (elf.phdrSlice()) { |
| 11542 | | inline else => |phdr| { |
| 11929 | inline else => |phdr, class| { |
| 11543 | 11930 | assert(elf.phdrs.items[phndx].unwrap().? == ni); |
| 11544 | 11931 | const ph = &phdr[phndx]; |
| 11545 | | elf.targetStore(&ph.filesz, @intCast(size)); |
| 11546 | 11932 | switch (elf.targetLoad(&ph.type)) { |
| 11547 | 11933 | else => unreachable, |
| 11548 | 11934 | .NULL, .LOAD => { |
| 11549 | | elf.targetStore(&ph.type, if (size > 0) .LOAD else .NULL); |
| 11935 | elf.targetStore(&ph.filesz, @intCast(size)); |
| 11550 | 11936 | try elf.allocateSegmentLoadAddress(phndx); |
| 11937 | if (ni == elf.ni.data) elf.bss_moved = true; |
| 11551 | 11938 | }, |
| 11552 | 11939 | .DYNAMIC, .INTERP, .PHDR, .GNU_EH_FRAME, .GNU_RELRO => { |
| 11940 | elf.targetStore(&ph.filesz, @intCast(size)); |
| 11553 | 11941 | elf.targetStore(&ph.memsz, @intCast(size)); |
| 11554 | 11942 | }, |
| 11555 | 11943 | .TLS => { |
| 11556 | | elf.targetStore(&ph.memsz, @intCast(size)); |
| 11944 | // We must fetch this value before modifying our `filesz`. |
| 11945 | const old_tbss_offset = elf.tbssOffset(); |
| 11946 | |
| 11947 | elf.targetStore(&ph.filesz, @intCast(size)); |
| 11948 | |
| 11949 | // Our memsz must include the `.tbss` section. |
| 11950 | const tls_align: Alignment = .fromByteUnits(elf.targetLoad(&ph.@"align")); |
| 11951 | elf.targetStore(&ph.memsz, @intCast( |
| 11952 | tls_align.forward(size + elf.shndx.tbss.size(elf)), |
| 11953 | )); |
| 11954 | |
| 11955 | // `.tbss` section goes at the end of this segment. Update its offset: |
| 11956 | const tls_offset = elf.targetLoad(&ph.offset); |
| 11957 | const tbss_shdr = @field(elf.shdrPtr(elf.shndx.tbss), @tagName(class)); |
| 11958 | elf.targetStore(&tbss_shdr.offset, @intCast(tls_offset + size)); |
| 11959 | // and its address: |
| 11960 | const tls_vaddr = elf.targetLoad(&ph.vaddr); |
| 11961 | const tbss_section_sym: Symbol.Id = .local(elf.shndx.tbss.get(elf).lsi); |
| 11962 | tbss_section_sym.flushMoved(elf, tls_vaddr + size); |
| 11963 | elf.targetStore(&tbss_shdr.addr, @intCast(tls_vaddr + size)); |
| 11964 | // and update the values of symbols in that section: |
| 11965 | elf.flushMovedNobitsSymbols( |
| 11966 | elf.shndx.tbss, |
| 11967 | old_tbss_offset, |
| 11968 | size, |
| 11969 | elf.tbss_inputs.items, |
| 11970 | elf.tbss_globals.keys(), |
| 11971 | ); |
| 11972 | |
| 11557 | 11973 | // TPOFF relocations care about the size of the TLS segment. Re-apply |
| 11558 | 11974 | // those, and also update any GOT entries from GOTTPOFF relocations. |
| 11559 | 11975 | for (elf.tls_size_symbol_relocs.keys()) |reloc| { |
| ... | ... | @@ -11904,17 +12320,17 @@ fn ensurePltEntry(elf: *Elf, gsi: Symbol.Global.Index) Error!bool { |
| 11904 | 12320 | const gpa = elf.base.comp.gpa; |
| 11905 | 12321 | try elf.shndx.rela_plt.relaEnsureAdditionalCapacity(elf, 1); |
| 11906 | 12322 | try elf.plt.ensureUnusedCapacity(gpa, 1); |
| 11907 | | try elf.shndx.plt.get(elf).ni.ensureMinimumSize( |
| 12323 | try elf.shndx.plt.node(elf).ensureMinimumSize( |
| 11908 | 12324 | gpa, |
| 11909 | 12325 | &elf.mf, |
| 11910 | 12326 | plt.entry_size * (plt.header_entries + elf.plt.count() + 1), |
| 11911 | 12327 | ); |
| 11912 | | if (plt.got_plt) |got_plt| try elf.shndx.got_plt.get(elf).ni.ensureMinimumSize( |
| 12328 | if (plt.got_plt) |got_plt| try elf.shndx.got_plt.node(elf).ensureMinimumSize( |
| 11913 | 12329 | gpa, |
| 11914 | 12330 | &elf.mf, |
| 11915 | 12331 | elf.targetPtrSize() * (got_plt.header_entries + elf.plt.count() + 1), |
| 11916 | 12332 | ); |
| 11917 | | if (plt.plt_sec) |plt_sec| try elf.shndx.plt_sec.get(elf).ni.ensureMinimumSize( |
| 12333 | if (plt.plt_sec) |plt_sec| try elf.shndx.plt_sec.node(elf).ensureMinimumSize( |
| 11918 | 12334 | gpa, |
| 11919 | 12335 | &elf.mf, |
| 11920 | 12336 | plt_sec.entry_size * (elf.plt.count() + 1), |
| ... | ... | @@ -11962,7 +12378,7 @@ fn ensurePltEntry(elf: *Elf, gsi: Symbol.Global.Index) Error!bool { |
| 11962 | 12378 | switch (elf.ehdrMachine()) { |
| 11963 | 12379 | .AARCH64, .PPC64, .RISCV => |machine| @panic(@tagName(machine)), |
| 11964 | 12380 | .X86_64 => { |
| 11965 | | const plt_ni = elf.shndx.plt.get(elf).ni; |
| 12381 | const plt_ni = elf.shndx.plt.node(elf); |
| 11966 | 12382 | const plt_addr = plt_addr: switch (elf.shdrPtr(elf.shndx.plt)) { |
| 11967 | 12383 | inline else => |shdr| { |
| 11968 | 12384 | const old_size = 16 * (1 + plt_index); |
| ... | ... | @@ -11986,7 +12402,7 @@ fn ensurePltEntry(elf: *Elf, gsi: Symbol.Global.Index) Error!bool { |
| 11986 | 12402 | }, |
| 11987 | 12403 | }; |
| 11988 | 12404 | |
| 11989 | | const got_plt_ni = elf.shndx.got_plt.get(elf).ni; |
| 12405 | const got_plt_ni = elf.shndx.got_plt.node(elf); |
| 11990 | 12406 | switch (elf.shdrPtr(elf.shndx.got_plt)) { |
| 11991 | 12407 | inline else => |shdr, class| { |
| 11992 | 12408 | assert(elf.targetLoad(&shdr.size) == got_plt_offset); |
| ... | ... | @@ -12000,7 +12416,7 @@ fn ensurePltEntry(elf: *Elf, gsi: Symbol.Global.Index) Error!bool { |
| 12000 | 12416 | }, |
| 12001 | 12417 | } |
| 12002 | 12418 | |
| 12003 | | const plt_sec_ni = elf.shndx.plt_sec.get(elf).ni; |
| 12419 | const plt_sec_ni = elf.shndx.plt_sec.node(elf); |
| 12004 | 12420 | switch (elf.shdrPtr(elf.shndx.plt_sec)) { |
| 12005 | 12421 | inline else => |shdr| { |
| 12006 | 12422 | const old_size = 16 * plt_index; |
| ... | ... | @@ -12024,7 +12440,7 @@ fn ensurePltEntry(elf: *Elf, gsi: Symbol.Global.Index) Error!bool { |
| 12024 | 12440 | }, |
| 12025 | 12441 | .LOONGARCH => { |
| 12026 | 12442 | // add a .PLT entry, writing the template |
| 12027 | | const plt_ni = elf.shndx.plt.get(elf).ni; |
| 12443 | const plt_ni = elf.shndx.plt.node(elf); |
| 12028 | 12444 | const plt_addr, const plt_slice = plt_entry: switch (elf.shdrPtr(elf.shndx.plt)) { |
| 12029 | 12445 | inline else => |shdr| { |
| 12030 | 12446 | const old_size = 16 * (1 + plt_index); |
| ... | ... | @@ -12048,7 +12464,7 @@ fn ensurePltEntry(elf: *Elf, gsi: Symbol.Global.Index) Error!bool { |
| 12048 | 12464 | }; |
| 12049 | 12465 | |
| 12050 | 12466 | // add a .GOT.PLT entry, writing the address of the corresponding .PLT entry |
| 12051 | | const got_plt_ni = elf.shndx.got_plt.get(elf).ni; |
| 12467 | const got_plt_ni = elf.shndx.got_plt.node(elf); |
| 12052 | 12468 | switch (elf.shdrPtr(elf.shndx.got_plt)) { |
| 12053 | 12469 | inline else => |shdr, class| { |
| 12054 | 12470 | assert(elf.targetLoad(&shdr.size) == got_plt_offset); |
| ... | ... | @@ -12080,7 +12496,7 @@ fn ensurePltEntry(elf: *Elf, gsi: Symbol.Global.Index) Error!bool { |
| 12080 | 12496 | }, |
| 12081 | 12497 | .SPARCV9 => { |
| 12082 | 12498 | // add a .PLT entry, writing the template |
| 12083 | | const plt_ni = elf.shndx.plt.get(elf).ni; |
| 12499 | const plt_ni = elf.shndx.plt.node(elf); |
| 12084 | 12500 | switch (elf.shdrPtr(elf.shndx.plt)) { |
| 12085 | 12501 | inline else => |shdr| { |
| 12086 | 12502 | assert(elf.targetLoad(&shdr.size) == got_plt_offset); |
| ... | ... | @@ -12137,7 +12553,7 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad |
| 12137 | 12553 | // We also need to update all of the references from `.plt.sec` to `.got.plt`. |
| 12138 | 12554 | // However, if there's also a flush pending for `.got.plt`, don't bother doing |
| 12139 | 12555 | // this now, because we'll do it when `.got.plt` is flushed anyway. |
| 12140 | | if (elf.shndx.got_plt.get(elf).ni.hasMoved(&elf.mf)) { |
| 12556 | if (elf.shndx.got_plt.node(elf).hasMoved(&elf.mf)) { |
| 12141 | 12557 | return; |
| 12142 | 12558 | } |
| 12143 | 12559 | // Exit this `switch` to update those references. |
| ... | ... | @@ -12152,7 +12568,7 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad |
| 12152 | 12568 | // We also need to update all of the references from `.plt.sec` to `.got.plt`. |
| 12153 | 12569 | // However, if there's also a flush pending for `.plt.sec`, don't bother doing |
| 12154 | 12570 | // this now, because we'll do it when `.plt.sec` is flushed anyway. |
| 12155 | | if (elf.shndx.plt_sec.get(elf).ni.hasMoved(&elf.mf)) { |
| 12571 | if (elf.shndx.plt_sec.node(elf).hasMoved(&elf.mf)) { |
| 12156 | 12572 | return; |
| 12157 | 12573 | } |
| 12158 | 12574 | // Exit this `switch` to update those references. |
| ... | ... | @@ -12161,7 +12577,7 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad |
| 12161 | 12577 | // We are updating the references from `.plt.sec` to `.got.plt`. |
| 12162 | 12578 | const got_plt_addr = elf.shndx.got_plt.vaddr(elf); |
| 12163 | 12579 | const plt_sec_addr = elf.shndx.plt_sec.vaddr(elf); |
| 12164 | | const plt_sec_slice = elf.shndx.plt_sec.get(elf).ni.slice(&elf.mf); |
| 12580 | const plt_sec_slice = elf.shndx.plt_sec.node(elf).slice(&elf.mf); |
| 12165 | 12581 | switch (elf.identClass()) { |
| 12166 | 12582 | .NONE, _ => unreachable, |
| 12167 | 12583 | inline else => |class| { |
| ... | ... | @@ -12194,7 +12610,7 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad |
| 12194 | 12610 | // We also need to update all of the references from `.plt` to `.got.plt`. |
| 12195 | 12611 | // However, if there's also a flush pending for `.got.plt`, don't bother doing |
| 12196 | 12612 | // this now, because we'll do it when `.got.plt` is flushed anyway. |
| 12197 | | if (elf.shndx.got_plt.get(elf).ni.hasMoved(&elf.mf)) { |
| 12613 | if (elf.shndx.got_plt.node(elf).hasMoved(&elf.mf)) { |
| 12198 | 12614 | return; |
| 12199 | 12615 | } |
| 12200 | 12616 | // Exit this `switch` to update those references. |
| ... | ... | @@ -12210,7 +12626,7 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad |
| 12210 | 12626 | // We also need to update all of the references from `.plt` to `.got.plt`. |
| 12211 | 12627 | // However, if there's also a flush pending for `.plt`, don't bother doing |
| 12212 | 12628 | // this now, because we'll do it when `.plt` is flushed anyway. |
| 12213 | | if (elf.shndx.plt.get(elf).ni.hasMoved(&elf.mf)) { |
| 12629 | if (elf.shndx.plt.node(elf).hasMoved(&elf.mf)) { |
| 12214 | 12630 | return; |
| 12215 | 12631 | } |
| 12216 | 12632 | // Exit this `switch` to update those references. |
| ... | ... | @@ -12219,7 +12635,7 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad |
| 12219 | 12635 | // We are updating the references from `.plt` to `.got.plt`. |
| 12220 | 12636 | const got_plt_addr = elf.shndx.got_plt.vaddr(elf); |
| 12221 | 12637 | const plt_addr = elf.shndx.plt.vaddr(elf); |
| 12222 | | const plt_slice = elf.shndx.plt.get(elf).ni.slice(&elf.mf); |
| 12638 | const plt_slice = elf.shndx.plt.node(elf).slice(&elf.mf); |
| 12223 | 12639 | switch (elf.identClass()) { |
| 12224 | 12640 | .NONE, _ => unreachable, |
| 12225 | 12641 | inline else => |class| { |
| ... | ... | @@ -12657,7 +13073,7 @@ const VerdefAdapter = struct { |
| 12657 | 13073 | fn verdefId(elf: *Elf, version: String(.dynstr)) Error!u15 { |
| 12658 | 13074 | const gpa = elf.base.comp.gpa; |
| 12659 | 13075 | const adapter: VerdefAdapter = .{ .elf = elf }; |
| 12660 | | try elf.shndx.gnu_version_d.get(elf).ni.ensureMinimumSize(gpa, &elf.mf, (elf.verdef.count() + 2) * @sizeOf(VerdefEntry)); |
| 13076 | try elf.shndx.gnu_version_d.node(elf).ensureMinimumSize(gpa, &elf.mf, (elf.verdef.count() + 2) * @sizeOf(VerdefEntry)); |
| 12661 | 13077 | const gop = try elf.verdef.getOrPutAdapted(gpa, version, adapter); |
| 12662 | 13078 | |
| 12663 | 13079 | if (gop.found_existing) { |
| ... | ... | @@ -12766,7 +13182,7 @@ const VerneedAdapter = struct { |
| 12766 | 13182 | fn verneedId(elf: *Elf, file: String(.dynstr), version: String(.dynstr)) Error!u15 { |
| 12767 | 13183 | const gpa = elf.base.comp.gpa; |
| 12768 | 13184 | const adapter: VerneedAdapter = .{ .elf = elf }; |
| 12769 | | try elf.shndx.gnu_version_r.get(elf).ni.ensureMinimumSize(gpa, &elf.mf, (elf.verneed.count() + 2) * @sizeOf(VerneedEntry)); |
| 13185 | try elf.shndx.gnu_version_r.node(elf).ensureMinimumSize(gpa, &elf.mf, (elf.verneed.count() + 2) * @sizeOf(VerneedEntry)); |
| 12770 | 13186 | |
| 12771 | 13187 | if (elf.verneed.getIndexAdapted(@as(VerneedAdapter.Key, .{ |
| 12772 | 13188 | .file = file, |