authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-10-17 11:04:43+02:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-10-17 11:04:43+02:00
logd924f83bf3e1a5726d9eca1e9d501aece08107c5
treeb85938815e41f7587c17e2809898e93542cda203
parentf471212724bb917c57fc89a1cf41b5d365aa3a2d
parent716b778d5564a671148cc524d845f016364d1cec

Merge pull request 'ELF2: Initial bss support' (#36699) from 32/zig:bss_work into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/36699

1 files changed, 587 insertions(+), 171 deletions(-)

src/link/Elf2.zig+587-171
...@@ -66,6 +66,8 @@ shndx: struct {...@@ -66,6 +66,8 @@ shndx: struct {
66 debug_rnglists: Section.Index,66 debug_rnglists: Section.Index,
67 debug_str: Section.Index,67 debug_str: Section.Index,
68 debug_str_offsets: Section.Index,68 debug_str_offsets: Section.Index,
69 bss: Section.Index,
70 tbss: Section.Index,
69 // These sections are created only as needed, and are initially `.UNDEF`.71 // These sections are created only as needed, and are initially `.UNDEF`.
70 init_array: Section.Index,72 init_array: Section.Index,
71 fini_array: Section.Index,73 fini_array: Section.Index,
...@@ -135,6 +137,25 @@ node_global_symbols: std.array_hash_map.Auto(MappedFile.Node.Index, Symbol.Globa...@@ -135,6 +137,25 @@ node_global_symbols: std.array_hash_map.Auto(MappedFile.Node.Index, Symbol.Globa
135/// See the definition of `DsoGlobals`.137/// See the definition of `DsoGlobals`.
136dso_globals: DsoGlobals,138dso_globals: DsoGlobals,
137139
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.
142bss_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.
145tbss_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.
149bss_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.
152tbss_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".
157bss_moved: bool,
158
138shstrtab: StringTable,159shstrtab: StringTable,
139strtab: StringTable,160strtab: StringTable,
140dynstr: StringTable,161dynstr: StringTable,
...@@ -491,8 +512,9 @@ const Archive = struct {...@@ -491,8 +512,9 @@ const Archive = struct {
491};512};
492513
493const Section = struct {514const Section = struct {
494 /// The node corresponding to this section.515 /// File-backed node corresponding to this section.
495 ni: MappedFile.Node.Index,516 /// This is `.none` for `SHT_NOBITS` sections.
517 ni: MappedFile.Node.Index.Optional,
496 /// A symbol which is exactly at the start of this section.518 /// A symbol which is exactly at the start of this section.
497 ///519 ///
498 /// When not emitting a relocatable, or for special section types, this is `.null`.520 /// When not emitting a relocatable, or for special section types, this is `.null`.
...@@ -596,6 +618,13 @@ const Section = struct {...@@ -596,6 +618,13 @@ const Section = struct {
596 return &elf.shdrs.items[@backingInt(shndx) - 1]; // overflow means you tried to get the `.UNDEF` section618 return &elf.shdrs.items[@backingInt(shndx) - 1]; // overflow means you tried to get the `.UNDEF` section
597 }619 }
598620
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 fn name(shndx: Index, elf: *Elf) String(.shstrtab) {628 fn name(shndx: Index, elf: *Elf) String(.shstrtab) {
600 return switch (elf.shdrPtr(shndx)) {629 return switch (elf.shdrPtr(shndx)) {
601 inline else => |shdr| @fromBackingInt(elf.targetLoad(&shdr.name)),630 inline else => |shdr| @fromBackingInt(elf.targetLoad(&shdr.name)),
...@@ -648,21 +677,39 @@ const Section = struct {...@@ -648,21 +677,39 @@ const Section = struct {
648 elf.targetStore(&shdr.addralign, @intCast(min_align.toByteUnits()));677 elf.targetStore(&shdr.addralign, @intCast(min_align.toByteUnits()));
649 },678 },
650 }679 }
651 const ni = shndx.get(elf).ni;680
652 if (min_align.compare(.gt, ni.alignment(&elf.mf))) {681 if (shndx.get(elf).ni.unwrap()) |ni| {
653 try ni.realign(elf.base.comp.gpa, &elf.mf, min_align);682 if (min_align.compare(.gt, ni.alignment(&elf.mf))) {
654 }683 try ni.realign(elf.base.comp.gpa, &elf.mf, min_align);
655 switch (elf.getNode(ni.parent(&elf.mf).unwrap().?)) {684 }
656 .elf => {},685 switch (elf.getNode(ni.parent(&elf.mf).unwrap().?)) {
657 .segment => |phndx| try elf.ensureSegmentAligned(phndx, min_align),686 .elf => {},
658 else => unreachable,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 }
661708
662 /// Asserts that `rela_shndx` is a `SHT_RELA` section and ensures that its node has enough709 /// Asserts that `rela_shndx` is a `SHT_RELA` section and ensures that its node has enough
663 /// unused space to hold `n` additional `ElfN.Rela` entries.710 /// unused space to hold `n` additional `ElfN.Rela` entries.
664 fn relaEnsureAdditionalCapacity(rela_shndx: Index, elf: *Elf, n: usize) Error!void {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 const need_size: u64 = switch (elf.shdrPtr(rela_shndx)) {713 const need_size: u64 = switch (elf.shdrPtr(rela_shndx)) {
667 inline else => |shdr, class| need_size: {714 inline else => |shdr, class| need_size: {
668 assert(elf.targetLoad(&shdr.type) == .RELA);715 assert(elf.targetLoad(&shdr.type) == .RELA);
...@@ -673,7 +720,7 @@ const Section = struct {...@@ -673,7 +720,7 @@ const Section = struct {
673 const opt_free_head = rela_shndx.get(elf).rela.free_head;720 const opt_free_head = rela_shndx.get(elf).rela.free_head;
674 const free_head = opt_free_head.unwrap() orelse break :free_len 0;721 const free_head = opt_free_head.unwrap() orelse break :free_len 0;
675 const relas: []const class.ElfN().Rela = @ptrCast(@alignCast(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 const free_len = elf.targetLoad(&relas[@backingInt(free_head)].addend);725 const free_len = elf.targetLoad(&relas[@backingInt(free_head)].addend);
679 assert(free_len > 0);726 assert(free_len > 0);
...@@ -683,7 +730,7 @@ const Section = struct {...@@ -683,7 +730,7 @@ const Section = struct {
683 break :need_size cur_size + need_additional * ent_size;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 }
688735
689 /// Asserts that `rela_shndx` is a `SHT_RELA` section and deletes the `ElfN.Rela` entry at736 /// Asserts that `rela_shndx` is a `SHT_RELA` section and deletes the `ElfN.Rela` entry at
...@@ -695,7 +742,7 @@ const Section = struct {...@@ -695,7 +742,7 @@ const Section = struct {
695 assert(elf.targetLoad(&shdr.type) == .RELA);742 assert(elf.targetLoad(&shdr.type) == .RELA);
696 assert(elf.targetLoad(&shdr.entsize) == @sizeOf(class.ElfN().Rela));743 assert(elf.targetLoad(&shdr.entsize) == @sizeOf(class.ElfN().Rela));
697 const relas: []class.ElfN().Rela = @ptrCast(@alignCast(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 const opt_free_head = rela_shndx.get(elf).rela.free_head;747 const opt_free_head = rela_shndx.get(elf).rela.free_head;
701 const old_free_len: u32 = free_len: {748 const old_free_len: u32 = free_len: {
...@@ -743,7 +790,7 @@ const Section = struct {...@@ -743,7 +790,7 @@ const Section = struct {
743 assert(elf.targetLoad(&shdr.entsize) == ent_size);790 assert(elf.targetLoad(&shdr.entsize) == ent_size);
744 const new_index: RelaIndex = if (rela_shndx.get(elf).rela.free_head.unwrap()) |free_head| new_index: {791 const new_index: RelaIndex = if (rela_shndx.get(elf).rela.free_head.unwrap()) |free_head| new_index: {
745 const relas: []class.ElfN().Rela = @ptrCast(@alignCast(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 const next: RelaIndex.Optional = @fromBackingInt(@intCast(elf.targetLoad(795 const next: RelaIndex.Optional = @fromBackingInt(@intCast(elf.targetLoad(
749 &relas[@backingInt(free_head)].offset,796 &relas[@backingInt(free_head)].offset,
...@@ -766,7 +813,7 @@ const Section = struct {...@@ -766,7 +813,7 @@ const Section = struct {
766 break :new_index @fromBackingInt(@intCast(@divExact(old_size, ent_size)));813 break :new_index @fromBackingInt(@intCast(@divExact(old_size, ent_size)));
767 };814 };
768 const relas: []class.ElfN().Rela = @ptrCast(@alignCast(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 relas[@backingInt(new_index)] = .{818 relas[@backingInt(new_index)] = .{
772 .offset = @intCast(opts.offset),819 .offset = @intCast(opts.offset),
...@@ -794,7 +841,7 @@ const Section = struct {...@@ -794,7 +841,7 @@ const Section = struct {
794 assert(elf.targetLoad(&shdr.type) == .RELA);841 assert(elf.targetLoad(&shdr.type) == .RELA);
795 assert(elf.targetLoad(&shdr.entsize) == @sizeOf(class.ElfN().Rela));842 assert(elf.targetLoad(&shdr.entsize) == @sizeOf(class.ElfN().Rela));
796 const relas: []class.ElfN().Rela = @ptrCast(@alignCast(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 const rela_info = elf.targetLoad(&relas[@backingInt(index)].info);846 const rela_info = elf.targetLoad(&relas[@backingInt(index)].info);
800 {847 {
...@@ -818,7 +865,7 @@ const Section = struct {...@@ -818,7 +865,7 @@ const Section = struct {
818 assert(elf.targetLoad(&shdr.type) == .RELA);865 assert(elf.targetLoad(&shdr.type) == .RELA);
819 assert(elf.targetLoad(&shdr.entsize) == @sizeOf(class.ElfN().Rela));866 assert(elf.targetLoad(&shdr.entsize) == @sizeOf(class.ElfN().Rela));
820 const relas: []class.ElfN().Rela = @ptrCast(@alignCast(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 const rela_info = elf.targetLoad(&relas[@backingInt(index)].info);871 const rela_info = elf.targetLoad(&relas[@backingInt(index)].info);
...@@ -839,7 +886,7 @@ const Section = struct {...@@ -839,7 +886,7 @@ const Section = struct {
839 assert(elf.targetLoad(&shdr.type) == .RELA);886 assert(elf.targetLoad(&shdr.type) == .RELA);
840 assert(elf.targetLoad(&shdr.entsize) == @sizeOf(class.ElfN().Rela));887 assert(elf.targetLoad(&shdr.entsize) == @sizeOf(class.ElfN().Rela));
841 const relas: []class.ElfN().Rela = @ptrCast(@alignCast(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 const rela_info = elf.targetLoad(&relas[@backingInt(index)].info);892 const rela_info = elf.targetLoad(&relas[@backingInt(index)].info);
...@@ -863,7 +910,7 @@ const Section = struct {...@@ -863,7 +910,7 @@ const Section = struct {
863 assert(elf.targetLoad(&shdr.type) == .RELA);910 assert(elf.targetLoad(&shdr.type) == .RELA);
864 assert(elf.targetLoad(&shdr.entsize) == @sizeOf(class.ElfN().Rela));911 assert(elf.targetLoad(&shdr.entsize) == @sizeOf(class.ElfN().Rela));
865 const relas: []class.ElfN().Rela = @ptrCast(@alignCast(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 const rela_info = elf.targetLoad(&relas[@backingInt(index)].info);916 const rela_info = elf.targetLoad(&relas[@backingInt(index)].info);
...@@ -2220,7 +2267,7 @@ const GotReloc = struct {...@@ -2220,7 +2267,7 @@ const GotReloc = struct {
2220 fn apply(reloc: *GotReloc, elf: *Elf) void {2267 fn apply(reloc: *GotReloc, elf: *Elf) void {
2221 assert(elf.ehdrType() != .REL);2268 assert(elf.ehdrType() != .REL);
2222 const node = reloc.node.unwrap() orelse return; // deleted2269 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 // There's no point applying the relocation now, because it will be re-applied by2271 // There's no point applying the relocation now, because it will be re-applied by
2225 // `flushMoved` at some point anyway.2272 // `flushMoved` at some point anyway.
2226 return;2273 return;
...@@ -2452,7 +2499,7 @@ fn ensureDynsymHashCapacity(elf: *Elf, max_dynsym_count: u32) Error!void {...@@ -2452,7 +2499,7 @@ fn ensureDynsymHashCapacity(elf: *Elf, max_dynsym_count: u32) Error!void {
2452 switch (elf.targetDynsymHashInfo()) {2499 switch (elf.targetDynsymHashInfo()) {
2453 inline else => |info| {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 const header: *info.Header() = @ptrCast(section_slice[0..@sizeOf(info.Header())]);2503 const header: *info.Header() = @ptrCast(section_slice[0..@sizeOf(info.Header())]);
2457 assert(elf.targetLoad(&header.nchain) == cur_dynsym_count);2504 assert(elf.targetLoad(&header.nchain) == cur_dynsym_count);
2458 const nbucket = elf.targetLoad(&header.nbucket);2505 const nbucket = elf.targetLoad(&header.nbucket);
...@@ -2460,7 +2507,7 @@ fn ensureDynsymHashCapacity(elf: *Elf, max_dynsym_count: u32) Error!void {...@@ -2460,7 +2507,7 @@ fn ensureDynsymHashCapacity(elf: *Elf, max_dynsym_count: u32) Error!void {
2460 // We don't need to add any buckets, but we still need to make sure the section is large2507 // We don't need to add any buckets, but we still need to make sure the section is large
2461 // enough to fit `max_dynsym_count` chains.2508 // enough to fit `max_dynsym_count` chains.
2462 const need_size = @sizeOf(info.Header()) + (nbucket + max_dynsym_count) * 4;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 return;2511 return;
2465 }2512 }
2466 // We need more buckets, so we'll have to rebuild the hash table.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,13 +2519,13 @@ fn ensureDynsymHashCapacity(elf: *Elf, max_dynsym_count: u32) Error!void {
24722519
2473 {2520 {
2474 const need_size = @sizeOf(info.Header()) + (new_nbucket + max_dynsym_count) * 4;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 }
24772524
2478 elf.mf.nodes_lock.lock();2525 elf.mf.nodes_lock.lock();
2479 defer elf.mf.nodes_lock.unlock();2526 defer elf.mf.nodes_lock.unlock();
24802527
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 const header: *info.Header() = @ptrCast(section_slice[0..@sizeOf(info.Header())]);2529 const header: *info.Header() = @ptrCast(section_slice[0..@sizeOf(info.Header())]);
2483 const trailing: []info.Int() = @ptrCast(section_slice[@sizeOf(info.Header())..]);2530 const trailing: []info.Int() = @ptrCast(section_slice[@sizeOf(info.Header())..]);
24842531
...@@ -2508,7 +2555,7 @@ fn ensureDynsymHashCapacity(elf: *Elf, max_dynsym_count: u32) Error!void {...@@ -2508,7 +2555,7 @@ fn ensureDynsymHashCapacity(elf: *Elf, max_dynsym_count: u32) Error!void {
2508fn appendDynsymHashEntry(elf: *Elf, dynsym_index: u32) void {2555fn appendDynsymHashEntry(elf: *Elf, dynsym_index: u32) void {
2509 switch (elf.targetDynsymHashInfo()) {2556 switch (elf.targetDynsymHashInfo()) {
2510 inline else => |info| {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 const header: *info.Header() = @ptrCast(section_slice[0..@sizeOf(info.Header())]);2559 const header: *info.Header() = @ptrCast(section_slice[0..@sizeOf(info.Header())]);
2513 assert(elf.targetLoad(&header.nchain) == dynsym_index);2560 assert(elf.targetLoad(&header.nchain) == dynsym_index);
2514 elf.targetStore(&header.nchain, dynsym_index + 1);2561 elf.targetStore(&header.nchain, dynsym_index + 1);
...@@ -2529,7 +2576,7 @@ fn populateDynsymHashEntry(elf: *Elf, dynsym_index: u32) void {...@@ -2529,7 +2576,7 @@ fn populateDynsymHashEntry(elf: *Elf, dynsym_index: u32) void {
25292576
2530 switch (elf.targetDynsymHashInfo()) {2577 switch (elf.targetDynsymHashInfo()) {
2531 inline else => |info| {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 const header: *info.Header() = @ptrCast(section_slice[0..@sizeOf(info.Header())]);2580 const header: *info.Header() = @ptrCast(section_slice[0..@sizeOf(info.Header())]);
2534 const trailing: []info.Int() = @ptrCast(section_slice[@sizeOf(info.Header())..]);2581 const trailing: []info.Int() = @ptrCast(section_slice[@sizeOf(info.Header())..]);
25352582
...@@ -2551,7 +2598,7 @@ fn popDynsymHashEntry(elf: *Elf, dynsym_index: u32) void {...@@ -2551,7 +2598,7 @@ fn popDynsymHashEntry(elf: *Elf, dynsym_index: u32) void {
25512598
2552 switch (elf.targetDynsymHashInfo()) {2599 switch (elf.targetDynsymHashInfo()) {
2553 inline else => |info| {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 const header: *info.Header() = @ptrCast(section_slice[0..@sizeOf(info.Header())]);2602 const header: *info.Header() = @ptrCast(section_slice[0..@sizeOf(info.Header())]);
2556 assert(elf.targetLoad(&header.nchain) == dynsym_index + 1);2603 assert(elf.targetLoad(&header.nchain) == dynsym_index + 1);
2557 elf.targetStore(&header.nchain, dynsym_index);2604 elf.targetStore(&header.nchain, dynsym_index);
...@@ -2570,7 +2617,7 @@ fn clearDynsymHashEntry(elf: *Elf, dynsym_index: u32) void {...@@ -2570,7 +2617,7 @@ fn clearDynsymHashEntry(elf: *Elf, dynsym_index: u32) void {
25702617
2571 switch (elf.targetDynsymHashInfo()) {2618 switch (elf.targetDynsymHashInfo()) {
2572 inline else => |info| {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 const header: *info.Header() = @ptrCast(section_slice[0..@sizeOf(info.Header())]);2621 const header: *info.Header() = @ptrCast(section_slice[0..@sizeOf(info.Header())]);
2575 const trailing: []info.Int() = @ptrCast(section_slice[@sizeOf(info.Header())..]);2622 const trailing: []info.Int() = @ptrCast(section_slice[@sizeOf(info.Header())..]);
25762623
...@@ -2615,7 +2662,7 @@ fn pltEntryIsDead(elf: *Elf, plt_index: usize) bool {...@@ -2615,7 +2662,7 @@ fn pltEntryIsDead(elf: *Elf, plt_index: usize) bool {
2615 inline else => |rela_shdr, class| {2662 inline else => |rela_shdr, class| {
2616 const size = elf.targetLoad(&rela_shdr.size);2663 const size = elf.targetLoad(&rela_shdr.size);
2617 const relas: []class.ElfN().Rela = @ptrCast(@alignCast(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 const rel_type = elf.targetLoad(&relas[plt_index].info).type;2667 const rel_type = elf.targetLoad(&relas[plt_index].info).type;
2621 return rel_type == MachineRelocType.none(elf).unwrap(elf);2668 return rel_type == MachineRelocType.none(elf).unwrap(elf);
...@@ -2636,7 +2683,7 @@ fn addLocalSymbol(elf: *Elf, opts: AddLocalSymbolOptions) Error!Symbol.LocalInde...@@ -2636,7 +2683,7 @@ fn addLocalSymbol(elf: *Elf, opts: AddLocalSymbolOptions) Error!Symbol.LocalInde
26362683
2637 try elf.symtab.ensureUnusedCapacity(gpa, 1);2684 try elf.symtab.ensureUnusedCapacity(gpa, 1);
2638 try elf.changed_symtab_index.ensureUnusedCapacity(gpa, 1);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 inline else => |shdr, class| elf.targetLoad(&shdr.size) + @sizeOf(class.ElfN().Sym),2687 inline else => |shdr, class| elf.targetLoad(&shdr.size) + @sizeOf(class.ElfN().Sym),
2641 });2688 });
26422689
...@@ -2715,7 +2762,7 @@ fn addGlobalSymbol(elf: *Elf, opts: Symbol.Global.AddOptions) (error{...@@ -2715,7 +2762,7 @@ fn addGlobalSymbol(elf: *Elf, opts: Symbol.Global.AddOptions) (error{
2715 try elf.globals_by_name.ensureUnusedCapacity(gpa, 1);2762 try elf.globals_by_name.ensureUnusedCapacity(gpa, 1);
2716 try elf.node_global_symbols.ensureUnusedCapacity(gpa, 1);2763 try elf.node_global_symbols.ensureUnusedCapacity(gpa, 1);
27172764
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 inline else => |shdr, class| elf.targetLoad(&shdr.size) + @sizeOf(class.ElfN().Sym),2766 inline else => |shdr, class| elf.targetLoad(&shdr.size) + @sizeOf(class.ElfN().Sym),
2720 });2767 });
27212768
...@@ -2881,6 +2928,18 @@ fn addGlobalSymbol(elf: *Elf, opts: Symbol.Global.AddOptions) (error{...@@ -2881,6 +2928,18 @@ fn addGlobalSymbol(elf: *Elf, opts: Symbol.Global.AddOptions) (error{
2881 old_head_ptr.prev_in_node = .wrap(gsi);2928 old_head_ptr.prev_in_node = .wrap(gsi);
2882 }2929 }
28832930
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 if (force_local_bind) {2943 if (force_local_bind) {
2885 elf.moveDemotedGlobal(gsi);2944 elf.moveDemotedGlobal(gsi);
2886 }2945 }
...@@ -3059,8 +3118,8 @@ fn updateGlobalDynamic(elf: *Elf, orig_gsi: Symbol.Global.Index, force_apply_rel...@@ -3059,8 +3118,8 @@ fn updateGlobalDynamic(elf: *Elf, orig_gsi: Symbol.Global.Index, force_apply_rel
3059 };3118 };
3060 const need_dynsym_len: u32 = @intCast(@divExact(dynsym_size, dynsym_ent_size) + 1);3119 const need_dynsym_len: u32 = @intCast(@divExact(dynsym_size, dynsym_ent_size) + 1);
30613120
3062 try elf.shndx.dynsym.get(elf).ni.ensureMinimumSize(gpa, &elf.mf, need_dynsym_len * dynsym_ent_size);3121 try elf.shndx.dynsym.node(elf).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);3122 try elf.shndx.gnu_version.node(elf).ensureMinimumSize(gpa, &elf.mf, need_dynsym_len * 2);
3064 try elf.ensureDynsymHashCapacity(need_dynsym_len);3123 try elf.ensureDynsymHashCapacity(need_dynsym_len);
30653124
3066 const dynstr_name: String(.dynstr) = name: {3125 const dynstr_name: String(.dynstr) = name: {
...@@ -3246,7 +3305,7 @@ fn updateGlobalDynamic(elf: *Elf, orig_gsi: Symbol.Global.Index, force_apply_rel...@@ -3246,7 +3305,7 @@ fn updateGlobalDynamic(elf: *Elf, orig_gsi: Symbol.Global.Index, force_apply_rel
3246 errdefer assert(elf.copied_globals.pop().?.key == gsi);3305 errdefer assert(elf.copied_globals.pop().?.key == gsi);
3247 try elf.nodes.ensureUnusedCapacity(gpa, 1);3306 try elf.nodes.ensureUnusedCapacity(gpa, 1);
3248 const node = elf.addNodeAssumeCapacity(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 .size = dso_global.alignment.forward(dso_global.size),3309 .size = dso_global.alignment.forward(dso_global.size),
3251 .alignment = dso_global.alignment,3310 .alignment = dso_global.alignment,
3252 }),3311 }),
...@@ -3318,8 +3377,9 @@ fn setGlobalSymbolValue(elf: *Elf, gsi: Symbol.Global.Index, new: struct {...@@ -3318,8 +3377,9 @@ fn setGlobalSymbolValue(elf: *Elf, gsi: Symbol.Global.Index, new: struct {
3318 type: std.elf.STT,3377 type: std.elf.STT,
3319 shndx: Section.Index,3378 shndx: Section.Index,
3320}) Error!void {3379}) Error!void {
3321 assert(new.shndx != .UNDEF);3380 const gpa = elf.base.comp.gpa;
33223381
3382 assert(new.shndx != .UNDEF);
3323 const global_ptr = gsi.ptr(elf);3383 const global_ptr = gsi.ptr(elf);
33243384
3325 if (global_ptr.symtab_index.ptr(elf).node.unwrap()) |old_node| {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,6 +3401,21 @@ fn setGlobalSymbolValue(elf: *Elf, gsi: Symbol.Global.Index, new: struct {
3341 } else {3401 } else {
3342 assert(global_ptr.next_in_node == .none);3402 assert(global_ptr.next_in_node == .none);
3343 assert(global_ptr.prev_in_node == .none);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 }
33453420
3346 global_ptr.symtab_index.ptr(elf).node = new.node;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,7 +3699,8 @@ fn deleteOwnedDynsym(elf: *Elf, gsi: Symbol.Global.Index) std.mem.Allocator.Erro
36243699
3625const Symbol = struct {3700const Symbol = struct {
3626 /// The node which this symbol's value is defined relative to. Possible values are:3701 /// The node which this symbol's value is defined relative to. Possible values are:
3627 /// * `.none` for a SHN_ABS or SHN_UNDEF symbol3702 /// * `.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 /// * A section (the symbol's value is some vaddr in that section)3704 /// * A section (the symbol's value is some vaddr in that section)
3629 /// * An input section (the symbol's value is some vaddr in that input section)3705 /// * An input section (the symbol's value is some vaddr in that input section)
3630 /// * A NAV, UAV, or lazy code/data (the symbol's value is exactly the vaddr of that node)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,7 +4371,7 @@ fn lazySymbolInner(elf: *Elf, lazy: link.File.LazySymbol) Error!link.File.Symbol
4295 .const_data => .{ .rodata, .OBJECT },4371 .const_data => .{ .rodata, .OBJECT },
4296 };4372 };
4297 const node = elf.addNodeAssumeCapacity(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 switch (lazy.kind) {4375 switch (lazy.kind) {
4300 .code => .{ .lazy_code = @fromBackingInt(@intCast(gop.index)) },4376 .code => .{ .lazy_code = @fromBackingInt(@intCast(gop.index)) },
4301 .const_data => .{ .lazy_const_data = @fromBackingInt(@intCast(gop.index)) },4377 .const_data => .{ .lazy_const_data = @fromBackingInt(@intCast(gop.index)) },
...@@ -4472,7 +4548,7 @@ fn String(section: StringSection) type {...@@ -4472,7 +4548,7 @@ fn String(section: StringSection) type {
4472 _,4548 _,
44734549
4474 fn slice(str: @This(), elf: *Elf) [:0]const u8 {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 const overlong = section_node.sliceConst(&elf.mf)[@backingInt(str)..];4552 const overlong = section_node.sliceConst(&elf.mf)[@backingInt(str)..];
4477 return overlong[0..std.mem.findScalar(u8, overlong, 0).? :0];4553 return overlong[0..std.mem.findScalar(u8, overlong, 0).? :0];
4478 }4554 }
...@@ -4532,14 +4608,14 @@ const StringTable = struct {...@@ -4532,14 +4608,14 @@ const StringTable = struct {
45324608
4533 fn getExisting(st: *StringTable, elf: *Elf, shndx: Section.Index, key: []const u8) u32 {4609 fn getExisting(st: *StringTable, elf: *Elf, shndx: Section.Index, key: []const u8) u32 {
4534 if (key.len == 0) return 0;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 const adapter: StringTable.Adapter = .{ .slice = slice_const };4612 const adapter: StringTable.Adapter = .{ .slice = slice_const };
4537 return st.map.getKeyAdapted(key, adapter).?;4613 return st.map.getKeyAdapted(key, adapter).?;
4538 }4614 }
45394615
4540 fn ensureAdditionalCapacity(st: *StringTable, elf: *Elf, shndx: Section.Index, string_len: usize) Error!void {4616 fn ensureAdditionalCapacity(st: *StringTable, elf: *Elf, shndx: Section.Index, string_len: usize) Error!void {
4541 const gpa = elf.base.comp.gpa;4617 const gpa = elf.base.comp.gpa;
4542 const ni = shndx.get(elf).ni;4618 const ni = shndx.node(elf);
4543 const slice_const = ni.sliceConst(&elf.mf);4619 const slice_const = ni.sliceConst(&elf.mf);
4544 try st.map.ensureUnusedCapacityContext(gpa, 1, .{ .slice = slice_const });4620 try st.map.ensureUnusedCapacityContext(gpa, 1, .{ .slice = slice_const });
4545 const size: u64 = switch (elf.shdrPtr(shndx)) {4621 const size: u64 = switch (elf.shdrPtr(shndx)) {
...@@ -4553,7 +4629,7 @@ const StringTable = struct {...@@ -4553,7 +4629,7 @@ const StringTable = struct {
4553 // case the empty string.4629 // case the empty string.
4554 if (key.len == 0) return 0;4630 if (key.len == 0) return 0;
45554631
4556 const ni = shndx.get(elf).ni;4632 const ni = shndx.node(elf);
4557 const slice_const = ni.sliceConst(&elf.mf);4633 const slice_const = ni.sliceConst(&elf.mf);
4558 const gop = st.map.getOrPutAssumeCapacityAdapted(4634 const gop = st.map.getOrPutAssumeCapacityAdapted(
4559 key,4635 key,
...@@ -4711,6 +4787,8 @@ fn create(...@@ -4711,6 +4787,8 @@ fn create(
4711 .init_array = .UNDEF,4787 .init_array = .UNDEF,
4712 .fini_array = .UNDEF,4788 .fini_array = .UNDEF,
4713 .preinit_array = .UNDEF,4789 .preinit_array = .UNDEF,
4790 .bss = .UNDEF,
4791 .tbss = .UNDEF,
4714 },4792 },
4715 .dynamic = .{4793 .dynamic = .{
4716 .flags = 0,4794 .flags = 0,
...@@ -4738,6 +4816,11 @@ fn create(...@@ -4738,6 +4816,11 @@ fn create(
4738 .symbols = .empty,4816 .symbols = .empty,
4739 .default_sym_vers = .empty,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 .shstrtab = .{ .map = .empty },4824 .shstrtab = .{ .map = .empty },
4742 .strtab = .{ .map = .empty },4825 .strtab = .{ .map = .empty },
4743 .dynstr = .{ .map = .empty },4826 .dynstr = .{ .map = .empty },
...@@ -4820,6 +4903,10 @@ pub fn deinit(elf: *Elf) void {...@@ -4820,6 +4903,10 @@ pub fn deinit(elf: *Elf) void {
4820 elf.dso_globals.string_bytes.deinit(gpa);4903 elf.dso_globals.string_bytes.deinit(gpa);
4821 elf.dso_globals.symbols.deinit(gpa);4904 elf.dso_globals.symbols.deinit(gpa);
4822 elf.dso_globals.default_sym_vers.deinit(gpa);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 elf.shstrtab.map.deinit(gpa);4910 elf.shstrtab.map.deinit(gpa);
4824 elf.strtab.map.deinit(gpa);4911 elf.strtab.map.deinit(gpa);
4825 elf.dynstr.map.deinit(gpa);4912 elf.dynstr.map.deinit(gpa);
...@@ -4905,7 +4992,9 @@ fn initHeaders(...@@ -4905,7 +4992,9 @@ fn initHeaders(
4905 shnum += 1; // .rodata4992 shnum += 1; // .rodata
4906 shnum += 1; // .text4993 shnum += 1; // .text
4907 shnum += 1; // .data4994 shnum += 1; // .data
4995 shnum += 1; // .bss
4908 shnum += @intFromBool(comp.config.any_non_single_threaded); // .tdata4996 shnum += @intFromBool(comp.config.any_non_single_threaded); // .tdata
4997 shnum += @intFromBool(comp.config.any_non_single_threaded); // .tbss
4909 shnum += 1; // .data.rel.ro4998 shnum += 1; // .data.rel.ro
4910 if (have_dynamic) {4999 if (have_dynamic) {
4911 shnum += 1; // .dynamic5000 shnum += 1; // .dynamic
...@@ -5022,9 +5111,13 @@ fn initHeaders(...@@ -5022,9 +5111,13 @@ fn initHeaders(
5022 };5111 };
5023 };5112 };
50245113
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 const expected_nodes_len = @as(usize, if (is_archive) 3 else 0) + // .archive, .archive_header, .archive_elf_member_header5118 const expected_nodes_len = @as(usize, if (is_archive) 3 else 0) + // .archive, .archive_header, .archive_elf_member_header
5026 3 + // `.elf`, `.ehdr`, and `.shdr` nodes5119 3 + // `.elf`, `.ehdr`, and `.shdr` nodes
5027 (shnum - 1) + // -1 because the SHN_UNDEF shdr does not have a `.section` node5120 (shnum - 1 - nobits_shnum) + // -1 because the SHN_UNDEF shdr does not have a `.section` node
5028 (phnum -| 1) + // -1 because the GNU_STACK phdr does not have a `.segment` node5121 (phnum -| 1) + // -1 because the GNU_STACK phdr does not have a `.segment` node
5029 @intFromBool(have_eh_frame and @"type" != .REL); // eh_frame_footer5122 @intFromBool(have_eh_frame and @"type" != .REL); // eh_frame_footer
50305123
...@@ -5476,7 +5569,7 @@ fn initHeaders(...@@ -5476,7 +5569,7 @@ fn initHeaders(
5476 .node_align = node_block_align,5569 .node_align = node_block_align,
5477 .manual_size = true,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;
54805573
5481 try Section.Index.symtab.rename(elf, ".symtab");5574 try Section.Index.symtab.rename(elf, ".symtab");
5482 try Section.Index.shstrtab.rename(elf, ".shstrtab");5575 try Section.Index.shstrtab.rename(elf, ".shstrtab");
...@@ -5489,7 +5582,7 @@ fn initHeaders(...@@ -5489,7 +5582,7 @@ fn initHeaders(
5489 .node_align = node_block_align,5582 .node_align = node_block_align,
5490 .manual_size = true,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 switch (elf.shdrPtr(.symtab)) {5586 switch (elf.shdrPtr(.symtab)) {
5494 inline else => |shdr| elf.targetStore(&shdr.link, @backingInt(Section.Index.strtab)),5587 inline else => |shdr| elf.targetStore(&shdr.link, @backingInt(Section.Index.strtab)),
5495 }5588 }
...@@ -5514,6 +5607,13 @@ fn initHeaders(...@@ -5514,6 +5607,13 @@ fn initHeaders(
5514 .flags = .{ .WRITE = true, .ALLOC = true },5607 .flags = .{ .WRITE = true, .ALLOC = true },
5515 .node_align = node_block_align,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 if (@"type" != .REL) {5617 if (@"type" != .REL) {
5518 elf.shndx.got = try elf.addSection(elf.ni.data_rel_ro, .{5618 elf.shndx.got = try elf.addSection(elf.ni.data_rel_ro, .{
5519 .name = ".got",5619 .name = ".got",
...@@ -5595,7 +5695,7 @@ fn initHeaders(...@@ -5595,7 +5695,7 @@ fn initHeaders(
5595 .flags = .{ .ALLOC = true },5695 .flags = .{ .ALLOC = true },
5596 .size = @intCast(interp.len + 1),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 @memcpy(sec_interp[0..interp.len], interp);5699 @memcpy(sec_interp[0..interp.len], interp);
5600 sec_interp[interp.len] = 0;5700 sec_interp[interp.len] = 0;
5601 }5701 }
...@@ -5620,7 +5720,7 @@ fn initHeaders(...@@ -5620,7 +5720,7 @@ fn initHeaders(
5620 .node_align = node_block_align,5720 .node_align = node_block_align,
5621 .manual_size = true,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 elf.shndx.dynstr = dynstr_shndx;5724 elf.shndx.dynstr = dynstr_shndx;
56255725
5626 switch (class) {5726 switch (class) {
...@@ -5765,7 +5865,7 @@ fn initHeaders(...@@ -5765,7 +5865,7 @@ fn initHeaders(
5765 .size = @sizeOf(info.Header()) + @sizeOf(info.Int()) * (8 + 1),5865 .size = @sizeOf(info.Header()) + @sizeOf(info.Int()) * (8 + 1),
5766 .manual_size = true,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 const header: *info.Header() = @ptrCast(hash_slice[0..@sizeOf(info.Header())]);5869 const header: *info.Header() = @ptrCast(hash_slice[0..@sizeOf(info.Header())]);
5770 header.* = .{ .nbucket = 8, .nchain = 1 };5870 header.* = .{ .nbucket = 8, .nchain = 1 };
5771 if (elf.targetEndian() != std.lang.Endian.native) {5871 if (elf.targetEndian() != std.lang.Endian.native) {
...@@ -5779,7 +5879,7 @@ fn initHeaders(...@@ -5779,7 +5879,7 @@ fn initHeaders(
5779 switch (machine) {5879 switch (machine) {
5780 .AARCH64, .PPC64, .RISCV => @panic(@tagName(machine)),5880 .AARCH64, .PPC64, .RISCV => @panic(@tagName(machine)),
5781 .X86_64 => {5881 .X86_64 => {
5782 const plt_ni = elf.shndx.plt.get(elf).ni;5882 const plt_ni = elf.shndx.plt.node(elf);
5783 const got_plt_sym: Symbol.Id = .local(elf.shndx.got_plt.get(elf).lsi);5883 const got_plt_sym: Symbol.Id = .local(elf.shndx.got_plt.get(elf).lsi);
5784 @memcpy(plt_ni.slice(&elf.mf)[0..16], &[16]u8{5884 @memcpy(plt_ni.slice(&elf.mf)[0..16], &[16]u8{
5785 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // push 0x0(%rip)5885 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // push 0x0(%rip)
...@@ -5804,7 +5904,7 @@ fn initHeaders(...@@ -5804,7 +5904,7 @@ fn initHeaders(
5804 );5904 );
5805 },5905 },
5806 .LOONGARCH => {5906 .LOONGARCH => {
5807 const plt_ni = elf.shndx.plt.get(elf).ni;5907 const plt_ni = elf.shndx.plt.node(elf);
5808 const got_plt_sym: Symbol.Id = .local(elf.shndx.got_plt.get(elf).lsi);5908 const got_plt_sym: Symbol.Id = .local(elf.shndx.got_plt.get(elf).lsi);
5809 @memcpy(plt_ni.slice(&elf.mf)[0..32], switch (class) {5909 @memcpy(plt_ni.slice(&elf.mf)[0..32], switch (class) {
5810 .NONE, _ => unreachable,5910 .NONE, _ => unreachable,
...@@ -5881,7 +5981,7 @@ fn initHeaders(...@@ -5881,7 +5981,7 @@ fn initHeaders(
5881 .manual_size = true,5981 .manual_size = true,
5882 });5982 });
58835983
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 elf.eh_frame_hdr_first_symbol_reloc =5985 elf.eh_frame_hdr_first_symbol_reloc =
5886 @fromBackingInt(@intCast(elf.symbol_relocs.items.len));5986 @fromBackingInt(@intCast(elf.symbol_relocs.items.len));
5887 try elf.dwarf.genEhFrameHdr(5987 try elf.dwarf.genEhFrameHdr(
...@@ -5890,7 +5990,7 @@ fn initHeaders(...@@ -5890,7 +5990,7 @@ fn initHeaders(
5890 Symbol.Id.local(elf.shndx.eh_frame.get(elf).lsi).toTypeErased(),5990 Symbol.Id.local(elf.shndx.eh_frame.get(elf).lsi).toTypeErased(),
5891 );5991 );
5892 _ = elf.addNodeAssumeCapacity(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 .size = addr_align.forward(4),5994 .size = addr_align.forward(4),
5895 .alignment = addr_align,5995 .alignment = addr_align,
5896 }),5996 }),
...@@ -5937,7 +6037,7 @@ fn initHeaders(...@@ -5937,7 +6037,7 @@ fn initHeaders(
59376037
5938 // Despite the name, `__dso_handle` is necessary even in static binaries.6038 // Despite the name, `__dso_handle` is necessary even in static binaries.
5939 _ = elf.addGlobalSymbol(.{6039 _ = elf.addGlobalSymbol(.{
5940 .node = .wrap(Section.Index.text.get(elf).ni),6040 .node = .wrap(Section.Index.text.node(elf)),
5941 .name = "__dso_handle",6041 .name = "__dso_handle",
5942 .value = Section.Index.text.vaddr(elf),6042 .value = Section.Index.text.vaddr(elf),
5943 .size = 0,6043 .size = 0,
...@@ -5952,7 +6052,7 @@ fn initHeaders(...@@ -5952,7 +6052,7 @@ fn initHeaders(
5952 else => |e| return e,6052 else => |e| return e,
5953 };6053 };
5954 _ = elf.addGlobalSymbol(.{6054 _ = elf.addGlobalSymbol(.{
5955 .node = .wrap(elf.shndx.plt.get(elf).ni),6055 .node = .wrap(elf.shndx.plt.node(elf)),
5956 .name = "_PROCEDURE_LINKAGE_TABLE_",6056 .name = "_PROCEDURE_LINKAGE_TABLE_",
5957 .value = elf.shndx.plt.vaddr(elf),6057 .value = elf.shndx.plt.vaddr(elf),
5958 .size = 0,6058 .size = 0,
...@@ -5967,7 +6067,7 @@ fn initHeaders(...@@ -5967,7 +6067,7 @@ fn initHeaders(
5967 else => |e| return e,6067 else => |e| return e,
5968 };6068 };
5969 _ = elf.addGlobalSymbol(.{6069 _ = elf.addGlobalSymbol(.{
5970 .node = .wrap(elf.shndx.got.get(elf).ni),6070 .node = .wrap(elf.shndx.got.node(elf)),
5971 .name = "_GLOBAL_OFFSET_TABLE_",6071 .name = "_GLOBAL_OFFSET_TABLE_",
5972 .value = switch (machine) {6072 .value = switch (machine) {
5973 .AARCH64,6073 .AARCH64,
...@@ -6085,7 +6185,7 @@ fn initHeaders(...@@ -6085,7 +6185,7 @@ fn initHeaders(
6085 };6185 };
6086 if (have_dynamic) {6186 if (have_dynamic) {
6087 _ = elf.addGlobalSymbol(.{6187 _ = elf.addGlobalSymbol(.{
6088 .node = .wrap(elf.shndx.dynamic.get(elf).ni),6188 .node = .wrap(elf.shndx.dynamic.node(elf)),
6089 .name = "_DYNAMIC",6189 .name = "_DYNAMIC",
6090 .value = elf.shndx.dynamic.vaddr(elf),6190 .value = elf.shndx.dynamic.vaddr(elf),
6091 .size = 0,6191 .size = 0,
...@@ -6112,11 +6212,19 @@ fn initHeaders(...@@ -6112,11 +6212,19 @@ fn initHeaders(
6112 .manual_size = true,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, .{6215 if (elf.ni.tls.unwrap()) |tls_segment_ni| {
6116 .name = ".tdata",6216 elf.shndx.tdata = try elf.addSection(tls_segment_ni, .{
6117 .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true },6217 .name = ".tdata",
6118 .node_align = node_block_align,6218 .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true },
6119 });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 switch (comp.config.debug_format) {6228 switch (comp.config.debug_format) {
6121 .strip => {},6229 .strip => {},
6122 .dwarf => {6230 .dwarf => {
...@@ -6323,6 +6431,15 @@ fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {...@@ -6323,6 +6431,15 @@ fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
6323 => elf.computeNodeVAddr(ni),6431 => elf.computeNodeVAddr(ni),
6324 };6432 };
6325}6433}
6434
6435fn 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
6326fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {6443fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
6327 const parent_ni = ni.parent(&elf.mf).unwrap().?;6444 const parent_ni = ni.parent(&elf.mf).unwrap().?;
6328 const parent_vaddr = parent_vaddr: switch (elf.getNode(parent_ni)) {6445 const parent_vaddr = parent_vaddr: switch (elf.getNode(parent_ni)) {
...@@ -6868,7 +6985,7 @@ const SymPtr = union(std.elf.CLASS) {...@@ -6868,7 +6985,7 @@ const SymPtr = union(std.elf.CLASS) {
6868 @"64": *std.elf.Elf64.Sym,6985 @"64": *std.elf.Elf64.Sym,
6869};6986};
6870fn symPtr(elf: *Elf, index: Symbol.Index) SymPtr {6987fn 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 switch (elf.shdrPtr(.symtab)) {6989 switch (elf.shdrPtr(.symtab)) {
6873 inline else => |shdr, class| {6990 inline else => |shdr, class| {
6874 const size = elf.targetLoad(&shdr.size);6991 const size = elf.targetLoad(&shdr.size);
...@@ -6878,7 +6995,7 @@ fn symPtr(elf: *Elf, index: Symbol.Index) SymPtr {...@@ -6878,7 +6995,7 @@ fn symPtr(elf: *Elf, index: Symbol.Index) SymPtr {
6878 }6995 }
6879}6996}
6880fn dynsymPtr(elf: *Elf, index: u32) SymPtr {6997fn 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 switch (elf.shdrPtr(elf.shndx.dynsym)) {6999 switch (elf.shdrPtr(elf.shndx.dynsym)) {
6883 inline else => |shdr, class| {7000 inline else => |shdr, class| {
6884 const size = elf.targetLoad(&shdr.size);7001 const size = elf.targetLoad(&shdr.size);
...@@ -6889,7 +7006,7 @@ fn dynsymPtr(elf: *Elf, index: u32) SymPtr {...@@ -6889,7 +7006,7 @@ fn dynsymPtr(elf: *Elf, index: u32) SymPtr {
6889}7006}
68907007
6891fn versymSlice(elf: *Elf) []std.elf.Versym {7008fn 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 const size = elf.shndx.gnu_version.size(elf);7010 const size = elf.shndx.gnu_version.size(elf);
6894 return @ptrCast(@alignCast(raw_slice[0..@intCast(size)]));7011 return @ptrCast(@alignCast(raw_slice[0..@intCast(size)]));
6895}7012}
...@@ -6903,7 +7020,7 @@ const VerdefEntry = extern struct {...@@ -6903,7 +7020,7 @@ const VerdefEntry = extern struct {
6903 aux: std.elf.Verdaux,7020 aux: std.elf.Verdaux,
6904};7021};
6905fn verdefSlice(elf: *Elf) []VerdefEntry {7022fn 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 const size = elf.shndx.gnu_version_d.size(elf);7024 const size = elf.shndx.gnu_version_d.size(elf);
6908 return @ptrCast(@alignCast(raw_slice[0..@intCast(size)]));7025 return @ptrCast(@alignCast(raw_slice[0..@intCast(size)]));
6909}7026}
...@@ -6916,7 +7033,7 @@ const VerneedEntry = extern union {...@@ -6916,7 +7033,7 @@ const VerneedEntry = extern union {
6916 }7033 }
6917};7034};
6918fn verneedSlice(elf: *Elf) []VerneedEntry {7035fn 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 const size = elf.shndx.gnu_version_r.size(elf);7037 const size = elf.shndx.gnu_version_r.size(elf);
6921 return @ptrCast(@alignCast(raw_slice[0..@intCast(size)]));7038 return @ptrCast(@alignCast(raw_slice[0..@intCast(size)]));
6922}7039}
...@@ -6935,12 +7052,18 @@ fn mapInputSection(elf: *Elf, opts: struct {...@@ -6935,12 +7052,18 @@ fn mapInputSection(elf: *Elf, opts: struct {
6935 name: []const u8,7052 name: []const u8,
6936 flags: std.elf.SHF,7053 flags: std.elf.SHF,
6937 entsize: std.elf.Xword,7054 entsize: std.elf.Xword,
7055 /// Must be one of:
7056 /// * `.PROGBITS`
7057 /// * `.NOBITS`
7058 /// * `.X86_64_UNWIND`
7059 type: std.elf.SHT,
6938}) (Error || error{7060}) (Error || error{
6939 UnsupportedSectionFlags,7061 UnsupportedSectionFlags,
6940 TlsSectionUnavailable,7062 TlsSectionUnavailable,
6941 StripSection,7063 StripSection,
6942 SectionFlagsConflict,7064 SectionFlagsConflict,
6943 SectionTypeConflict,7065 SectionTypeConflict,
7066 UnsupportedNobitsSection,
6944})!Section.Index {7067})!Section.Index {
6945 const gpa = elf.base.comp.gpa;7068 const gpa = elf.base.comp.gpa;
6946 if (opts.flags.INFO_LINK or7069 if (opts.flags.INFO_LINK or
...@@ -6972,12 +7095,10 @@ fn mapInputSection(elf: *Elf, opts: struct {...@@ -6972,12 +7095,10 @@ fn mapInputSection(elf: *Elf, opts: struct {
6972 if (std.mem.startsWith(u8, opts.name, ".data.")) break :name ".data";7095 if (std.mem.startsWith(u8, opts.name, ".data.")) break :name ".data";
6973 if (std.mem.startsWith(u8, opts.name, ".tdata.")) break :name ".tdata";7096 if (std.mem.startsWith(u8, opts.name, ".tdata.")) break :name ".tdata";
6974 if (std.mem.startsWith(u8, opts.name, ".gcc_except_table.")) break :name ".gcc_except_table";7097 if (std.mem.startsWith(u8, opts.name, ".gcc_except_table.")) break :name ".gcc_except_table";
6975 // TODO: actually generate a bss section!7098 if (std.mem.eql(u8, opts.name, ".bss")) break :name ".bss";
6976 if (std.mem.eql(u8, opts.name, ".bss")) break :name ".data";7099 if (std.mem.startsWith(u8, opts.name, ".bss.")) break :name ".bss";
6977 if (std.mem.startsWith(u8, opts.name, ".bss.")) break :name ".data";7100 if (std.mem.eql(u8, opts.name, ".tbss")) break :name ".tbss";
6978 // TODO: actually generate a tbss section!7101 if (std.mem.startsWith(u8, opts.name, ".tbss.")) break :name ".tbss";
6979 if (std.mem.eql(u8, opts.name, ".tbss")) break :name ".tdata";
6980 if (std.mem.startsWith(u8, opts.name, ".tbss.")) break :name ".tdata";
6981 break :name opts.name;7102 break :name opts.name;
6982 },7103 },
6983 };7104 };
...@@ -6998,7 +7119,12 @@ fn mapInputSection(elf: *Elf, opts: struct {...@@ -6998,7 +7119,12 @@ fn mapInputSection(elf: *Elf, opts: struct {
6998 assert(gop.index == elf.shdrs.items.len);7119 assert(gop.index == elf.shdrs.items.len);
6999 return elf.addSection(parent_node, .{7120 return elf.addSection(parent_node, .{
7000 .name = name,7121 .name = name,
7001 .type = .NULL, // because initial size is 07122 .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 .flags = flags: {7128 .flags = flags: {
7003 // We need to decompress the section for linking.7129 // We need to decompress the section for linking.
7004 var flags = opts.flags;7130 var flags = opts.flags;
...@@ -7019,9 +7145,20 @@ fn mapInputSection(elf: *Elf, opts: struct {...@@ -7019,9 +7145,20 @@ fn mapInputSection(elf: *Elf, opts: struct {
7019 return error.SectionFlagsConflict;7145 return error.SectionFlagsConflict;
7020 }7146 }
70217147
7022 switch (elf.targetLoad(&shdr.type)) {7148 const existing_type = elf.targetLoad(&shdr.type);
7023 .NULL, .PROGBITS, .X86_64_UNWIND => {},7149
7024 else => return error.SectionTypeConflict,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 }
70267163
7027 // All okay, combine the section flags7164 // All okay, combine the section flags
...@@ -7060,6 +7197,7 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node...@@ -7060,6 +7197,7 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node
7060 nav.resolved.?.@"threadlocal",7197 nav.resolved.?.@"threadlocal",
7061 },7198 },
7062 .entsize = 0,7199 .entsize = 0,
7200 .type = .PROGBITS,
7063 })) |shndx| {7201 })) |shndx| {
7064 break :section shndx;7202 break :section shndx;
7065 } else |err| switch (err) {7203 } else |err| switch (err) {
...@@ -7069,6 +7207,7 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node...@@ -7069,6 +7207,7 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node
7069 error.UnsupportedSectionFlags,7207 error.UnsupportedSectionFlags,
7070 error.SectionTypeConflict,7208 error.SectionTypeConflict,
7071 error.SectionFlagsConflict,7209 error.SectionFlagsConflict,
7210 error.UnsupportedNobitsSection,
7072 => {}, // fall back to default behavior below7211 => {}, // fall back to default behavior below
70737212
7074 }7213 }
...@@ -7101,7 +7240,7 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node...@@ -7101,7 +7240,7 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node
7101 },7240 },
7102 };7241 };
7103 try shndx.ensureAligned(elf, alignment);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 .alignment = alignment,7244 .alignment = alignment,
7106 }), .{ .nav = nmi });7245 }), .{ .nav = nmi });
7107 nav_gop.value_ptr.* = .{7246 nav_gop.value_ptr.* = .{
...@@ -7143,7 +7282,7 @@ fn uavMapIndex(...@@ -7143,7 +7282,7 @@ fn uavMapIndex(
7143 if (!uav_gop.found_existing) {7282 if (!uav_gop.found_existing) {
7144 const shndx: Section.Index = .data_rel_ro; // TODO: it would be better to use `.rodata` if the UAV value doesn't have relocs7283 const shndx: Section.Index = .data_rel_ro; // TODO: it would be better to use `.rodata` if the UAV value doesn't have relocs
7145 try shndx.ensureAligned(elf, resolved_align);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 .moved = true, // see assert at end of `genUav`7286 .moved = true, // see assert at end of `genUav`
7148 .alignment = resolved_align,7287 .alignment = resolved_align,
7149 }), .{ .uav = umi });7288 }), .{ .uav = umi });
...@@ -7440,6 +7579,9 @@ fn loadObject(...@@ -7440,6 +7579,9 @@ fn loadObject(
7440 .type = .FILE,7579 .type = .FILE,
7441 .shndx = .ABS,7580 .shndx = .ABS,
7442 }) };7581 }) };
7582
7583 var input_has_bss = false;
7584 var input_has_tbss = false;
7443 const target_endian = elf.targetEndian();7585 const target_endian = elf.targetEndian();
7444 switch (elf.identClass()) {7586 switch (elf.identClass()) {
7445 .NONE, _ => unreachable,7587 .NONE, _ => unreachable,
...@@ -7454,13 +7596,25 @@ fn loadObject(...@@ -7454,13 +7596,25 @@ fn loadObject(
7454 return diags.failParse(path, "bad section header location", .{});7596 return diags.failParse(path, "bad section header location", .{});
7455 if (ehdr.shentsize < @sizeOf(ElfN.Shdr))7597 if (ehdr.shentsize < @sizeOf(ElfN.Shdr))
7456 return diags.failParse(path, "unsupported shentsize", .{});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 defer gpa.free(sections);7612 defer gpa.free(sections);
7459 try fr.seekTo(fl.offset + ehdr.shoff);7613 try fr.seekTo(fl.offset + ehdr.shoff);
7460 for (sections) |*section| {7614 for (sections) |*section| {
7461 section.* = .{7615 section.* = .{
7462 .shdr = try r.peekStruct(ElfN.Shdr, target_endian),7616 .shdr = try r.peekStruct(ElfN.Shdr, target_endian),
7463 .isi = null,7617 .placement = .none,
7464 };7618 };
7465 try r.discardAll(ehdr.shentsize);7619 try r.discardAll(ehdr.shentsize);
7466 switch (section.shdr.type) {7620 switch (section.shdr.type) {
...@@ -7487,24 +7641,30 @@ fn loadObject(...@@ -7487,24 +7641,30 @@ fn loadObject(
7487 if (section.shdr.name >= shstrtab.len) continue;7641 if (section.shdr.name >= shstrtab.len) continue;
7488 const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0);7642 const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0);
7489 if (!comp.config.any_unwind_tables and std.mem.eql(u8, name, ".eh_frame")) continue;7643 if (!comp.config.any_unwind_tables and std.mem.eql(u8, name, ".eh_frame")) continue;
7644 const sect_type = section.shdr.type;
7490 const opts: struct {7645 const opts: struct {
7491 shndx: Section.Index,7646 shndx: Section.Index,
7492 node_fixed: bool,7647 node_fixed: bool,
7493 } = switch (section.shdr.type) {7648 } = switch (sect_type) {
7494 else => continue,7649 else => continue,
7495 .PROGBITS, .NOBITS, .X86_64_UNWIND => opts: {7650 .PROGBITS, .NOBITS, .X86_64_UNWIND => opts: {
7496 const shndx = elf.mapInputSection(.{7651 const shndx = elf.mapInputSection(.{
7497 .name = name,7652 .name = name,
7498 .flags = section.shdr.flags.shf,7653 .flags = section.shdr.flags.shf,
7499 .entsize = section.shdr.entsize,7654 .entsize = section.shdr.entsize,
7655 .type = section.shdr.type,
7500 }) catch |err| switch (err) {7656 }) catch |err| switch (err) {
7501 else => |e| return e,7657 else => |e| return e,
7502 error.StripSection => continue,7658 error.StripSection => continue,
7503 error.TlsSectionUnavailable => return diags.failParse(7659 error.TlsSectionUnavailable => {
7504 path,7660 if (section.shdr.size == 0) continue;
7505 "thread-local storage section '{s}' is incompatible with '-fsingle-threaded'",7661
7506 .{name},7662 return diags.failParse(
7507 ),7663 path,
7664 "thread-local storage section '{s}' is incompatible with '-fsingle-threaded'",
7665 .{name},
7666 );
7667 },
7508 error.UnsupportedSectionFlags => if (!section.shdr.flags.shf.ALLOC) {7668 error.UnsupportedSectionFlags => if (!section.shdr.flags.shf.ALLOC) {
7509 // It probably doesn't matter, just skip this section.7669 // It probably doesn't matter, just skip this section.
7510 continue;7670 continue;
...@@ -7529,6 +7689,11 @@ fn loadObject(...@@ -7529,6 +7689,11 @@ fn loadObject(
7529 "flags of section '{s}' conflict with other inputs",7689 "flags of section '{s}' conflict with other inputs",
7530 .{name},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 if (section.shdr.flags.shf.COMPRESSED) {7698 if (section.shdr.flags.shf.COMPRESSED) {
7534 // SHF_COMPRESSED is only allowed on non-alloc sections.7699 // SHF_COMPRESSED is only allowed on non-alloc sections.
...@@ -7595,7 +7760,35 @@ fn loadObject(...@@ -7595,7 +7760,35 @@ fn loadObject(
7595 const need_align: Alignment = .fromByteUnits(7760 const need_align: Alignment = .fromByteUnits(
7596 std.math.ceilPowerOfTwoAssert(usize, @intCast(@max(section.shdr.addralign, 1))),7761 std.math.ceilPowerOfTwoAssert(usize, @intCast(@max(section.shdr.addralign, 1))),
7597 );7762 );
7763
7598 try opts.shndx.ensureAligned(elf, need_align);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 const add_node_opts: MappedFile.Node.AddOptions = .{7792 const add_node_opts: MappedFile.Node.AddOptions = .{
7600 .size = need_align.forward(section.shdr.size),7793 .size = need_align.forward(section.shdr.size),
7601 .alignment = need_align,7794 .alignment = need_align,
...@@ -7603,7 +7796,7 @@ fn loadObject(...@@ -7603,7 +7796,7 @@ fn loadObject(
7603 };7796 };
7604 const ni = elf.addNodeAssumeCapacity(7797 const ni = elf.addNodeAssumeCapacity(
7605 if (opts.node_fixed) ni: {7798 if (opts.node_fixed) ni: {
7606 const shndx_ni = opts.shndx.get(elf).ni;7799 const shndx_ni = opts.shndx.node(elf);
7607 const after_oni: MappedFile.Node.Index.Optional = after: {7800 const after_oni: MappedFile.Node.Index.Optional = after: {
7608 const last_ni = shndx_ni.last(&elf.mf).unwrap() orelse break :after .none;7801 const last_ni = shndx_ni.last(&elf.mf).unwrap() orelse break :after .none;
7609 break :after switch (last_ni.position(&elf.mf)) {7802 break :after switch (last_ni.position(&elf.mf)) {
...@@ -7612,10 +7805,10 @@ fn loadObject(...@@ -7612,10 +7805,10 @@ fn loadObject(
7612 };7805 };
7613 };7806 };
7614 break :ni try shndx_ni.addHeaderChildAfter(gpa, &elf.mf, after_oni, add_node_opts);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 .{ .input_section = @fromBackingInt(@intCast(elf.input_sections.items.len)) },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 elf.input_sections.addOneAssumeCapacity().* = .{7812 elf.input_sections.addOneAssumeCapacity().* = .{
7620 .input = input_index,7813 .input = input_index,
7621 .file_location = .{7814 .file_location = .{
...@@ -7712,7 +7905,33 @@ fn loadObject(...@@ -7712,7 +7905,33 @@ fn loadObject(
7712 },7905 },
7713 };7906 };
77147907
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 };
77167935
7717 switch (input_sym.info.bind) {7936 switch (input_sym.info.bind) {
7718 else => |bind| return diags.failParse(7937 else => |bind| return diags.failParse(
...@@ -7722,20 +7941,20 @@ fn loadObject(...@@ -7722,20 +7941,20 @@ fn loadObject(
7722 ),7941 ),
7723 .LOCAL => {7942 .LOCAL => {
7724 const lsi = try elf.addLocalSymbol(.{7943 const lsi = try elf.addLocalSymbol(.{
7725 .node = .wrap(input_section_node),7944 .node = symbol_oni,
7726 .name = name,7945 .name = name,
7727 .value = input_sym.value,7946 .value = symbol_value,
7728 .size = input_sym.size,7947 .size = input_sym.size,
7729 .type = sym_type,7948 .type = sym_type,
7730 .shndx = elf.getNodeShndx(input_section_node),7949 .shndx = output_shndx,
7731 });7950 });
7732 si.* = .local(lsi);7951 si.* = .local(lsi);
7733 },7952 },
7734 .GLOBAL, .WEAK, .GNU_UNIQUE => |bind| {7953 .GLOBAL, .WEAK, .GNU_UNIQUE => |bind| {
7735 si.* = .global(elf.addGlobalSymbol(.{7954 si.* = .global(elf.addGlobalSymbol(.{
7736 .node = .wrap(input_section_node),7955 .node = symbol_oni,
7737 .name = name,7956 .name = name,
7738 .value = input_sym.value,7957 .value = symbol_value,
7739 .size = input_sym.size,7958 .size = input_sym.size,
7740 .type = sym_type,7959 .type = sym_type,
7741 .bind = switch (bind) {7960 .bind = switch (bind) {
...@@ -7744,7 +7963,7 @@ fn loadObject(...@@ -7744,7 +7963,7 @@ fn loadObject(
7744 else => unreachable,7963 else => unreachable,
7745 },7964 },
7746 .visibility = input_sym.other.visibility,7965 .visibility = input_sym.other.visibility,
7747 .shndx = elf.getNodeShndx(input_section_node),7966 .shndx = output_shndx,
7748 }) catch |err| switch (err) {7967 }) catch |err| switch (err) {
7749 error.MultipleDefinitions => return diags.failParse(7968 error.MultipleDefinitions => return diags.failParse(
7750 path,7969 path,
...@@ -7776,7 +7995,16 @@ fn loadObject(...@@ -7776,7 +7995,16 @@ fn loadObject(
7776 return diags.failParse(path, "unsupported rel entsize", .{});7995 return diags.failParse(path, "unsupported rel entsize", .{});
77777996
7778 const loc_sec = &sections[rel_sec.shdr.info];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 elf.resetNodeRelocs(loc_node);8008 elf.resetNodeRelocs(loc_node);
77818009
7782 const relnum = std.math.divExact(8010 const relnum = std.math.divExact(
...@@ -7843,6 +8071,16 @@ fn loadObject(...@@ -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,7 +8565,7 @@ fn createInitFiniArraySection(
8327 .version = null,8565 .version = null,
8328 }).?;8566 }).?;
8329 try elf.setGlobalSymbolValue(start_gsi, .{8567 try elf.setGlobalSymbolValue(start_gsi, .{
8330 .node = .wrap(shndx.get(elf).ni),8568 .node = .wrap(shndx.node(elf)),
8331 .value = shndx.vaddr(elf),8569 .value = shndx.vaddr(elf),
8332 .size = 0,8570 .size = 0,
8333 .type = .NOTYPE,8571 .type = .NOTYPE,
...@@ -8335,7 +8573,7 @@ fn createInitFiniArraySection(...@@ -8335,7 +8573,7 @@ fn createInitFiniArraySection(
8335 });8573 });
8336 try elf.updateGlobalDynamic(start_gsi, true);8574 try elf.updateGlobalDynamic(start_gsi, true);
8337 try elf.setGlobalSymbolValue(end_gsi, .{8575 try elf.setGlobalSymbolValue(end_gsi, .{
8338 .node = .wrap(shndx.get(elf).ni),8576 .node = .wrap(shndx.node(elf)),
8339 .value = shndx.vaddr(elf),8577 .value = shndx.vaddr(elf),
8340 .size = 0,8578 .size = 0,
8341 .type = .NOTYPE,8579 .type = .NOTYPE,
...@@ -8388,7 +8626,7 @@ fn prelinkInner(elf: *Elf) Error!void {...@@ -8388,7 +8626,7 @@ fn prelinkInner(elf: *Elf) Error!void {
8388 elf.shndx.debug_str_offsets,8626 elf.shndx.debug_str_offsets,
8389 }) |debug_shndx| {8627 }) |debug_shndx| {
8390 if (debug_shndx == .UNDEF) continue;8628 if (debug_shndx == .UNDEF) continue;
8391 const debug_ni = debug_shndx.get(elf).ni;8629 const debug_ni = debug_shndx.node(elf);
8392 const frame_format = debug_shndx.debugFrameFormat(elf);8630 const frame_format = debug_shndx.debugFrameFormat(elf);
8393 const unit_padding_ni = elf.addNodeAssumeCapacity(8631 const unit_padding_ni = elf.addNodeAssumeCapacity(
8394 try debug_ni.addHeaderChildAfter(gpa, &elf.mf, last_header_oni: {8632 try debug_ni.addHeaderChildAfter(gpa, &elf.mf, last_header_oni: {
...@@ -8444,7 +8682,7 @@ fn prelinkInner(elf: *Elf) Error!void {...@@ -8444,7 +8682,7 @@ fn prelinkInner(elf: *Elf) Error!void {
8444 .UNDEF => {},8682 .UNDEF => {},
8445 else => |debug_addr_shndx| {8683 else => |debug_addr_shndx| {
8446 const debug_addr_ni = elf.addNodeAssumeCapacity(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 .alignment = addr_align,8686 .alignment = addr_align,
8449 .next_moved = true,8687 .next_moved = true,
8450 .enable_next_moved = true,8688 .enable_next_moved = true,
...@@ -8465,7 +8703,7 @@ fn prelinkInner(elf: *Elf) Error!void {...@@ -8465,7 +8703,7 @@ fn prelinkInner(elf: *Elf) Error!void {
8465 switch (elf.shndx.debug_abbrev) {8703 switch (elf.shndx.debug_abbrev) {
8466 .UNDEF => {},8704 .UNDEF => {},
8467 else => |debug_abbrev_shndx| elf.dwarf.debug_abbrev.ni = .wrap(elf.addNodeAssumeCapacity(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 .{ .debug_shared = .debug_abbrev },8707 .{ .debug_shared = .debug_abbrev },
8470 )),8708 )),
8471 }8709 }
...@@ -8473,14 +8711,14 @@ fn prelinkInner(elf: *Elf) Error!void {...@@ -8473,14 +8711,14 @@ fn prelinkInner(elf: *Elf) Error!void {
8473 .UNDEF => {},8711 .UNDEF => {},
8474 else => |debug_line_str_shndx| elf.dwarf.debug_line_str.ni =8712 else => |debug_line_str_shndx| elf.dwarf.debug_line_str.ni =
8475 .wrap(elf.addNodeAssumeCapacity(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 .{ .debug_shared = .debug_line_str },8715 .{ .debug_shared = .debug_line_str },
8478 )),8716 )),
8479 }8717 }
8480 switch (elf.shndx.debug_str) {8718 switch (elf.shndx.debug_str) {
8481 .UNDEF => {},8719 .UNDEF => {},
8482 else => |debug_str_shndx| elf.dwarf.debug_str.ni = .wrap(elf.addNodeAssumeCapacity(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 .{ .debug_shared = .debug_str },8722 .{ .debug_shared = .debug_str },
8485 )),8723 )),
8486 }8724 }
...@@ -8488,7 +8726,7 @@ fn prelinkInner(elf: *Elf) Error!void {...@@ -8488,7 +8726,7 @@ fn prelinkInner(elf: *Elf) Error!void {
8488 .UNDEF => {},8726 .UNDEF => {},
8489 else => |debug_str_offsets_shndx| {8727 else => |debug_str_offsets_shndx| {
8490 const debug_str_offsets_ni = elf.addNodeAssumeCapacity(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 .alignment = switch (elf.dwarf.format) {8730 .alignment = switch (elf.dwarf.format) {
8493 .@"32" => .@"4",8731 .@"32" => .@"4",
8494 .@"64" => .@"8",8732 .@"64" => .@"8",
...@@ -8549,7 +8787,7 @@ fn zcuFilesReadyInner(elf: *Elf, zcu: *Zcu) Error!void {...@@ -8549,7 +8787,7 @@ fn zcuFilesReadyInner(elf: *Elf, zcu: *Zcu) Error!void {
8549 else => |debug_info_shndx| {8787 else => |debug_info_shndx| {
8550 const debug_info_ni = unit.debug_info_ni.unwrap() orelse debug_info_ni: {8788 const debug_info_ni = unit.debug_info_ni.unwrap() orelse debug_info_ni: {
8551 const debug_info_ni = elf.addNodeAssumeCapacity(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 .alignment = elf.mf.flags.block_size,8791 .alignment = elf.mf.flags.block_size,
8554 .enable_next_moved = true,8792 .enable_next_moved = true,
8555 }),8793 }),
...@@ -8576,7 +8814,7 @@ fn zcuFilesReadyInner(elf: *Elf, zcu: *Zcu) Error!void {...@@ -8576,7 +8814,7 @@ fn zcuFilesReadyInner(elf: *Elf, zcu: *Zcu) Error!void {
8576 else => |debug_line_shndx| {8814 else => |debug_line_shndx| {
8577 const debug_line_ni = unit.debug_line_ni.unwrap() orelse debug_line_ni: {8815 const debug_line_ni = unit.debug_line_ni.unwrap() orelse debug_line_ni: {
8578 const debug_line_ni = elf.addNodeAssumeCapacity(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 .alignment = elf.mf.flags.block_size,8818 .alignment = elf.mf.flags.block_size,
8581 .enable_next_moved = true,8819 .enable_next_moved = true,
8582 }),8820 }),
...@@ -8600,7 +8838,7 @@ fn zcuFilesReadyInner(elf: *Elf, zcu: *Zcu) Error!void {...@@ -8600,7 +8838,7 @@ fn zcuFilesReadyInner(elf: *Elf, zcu: *Zcu) Error!void {
8600 else => |debug_rnglists_shndx| {8838 else => |debug_rnglists_shndx| {
8601 const debug_rnglists_ni = unit.debug_rnglists_ni.unwrap() orelse debug_rnglists_ni: {8839 const debug_rnglists_ni = unit.debug_rnglists_ni.unwrap() orelse debug_rnglists_ni: {
8602 const debug_rnglists_ni = elf.addNodeAssumeCapacity(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 .next_moved = true,8842 .next_moved = true,
8605 .enable_next_moved = true,8843 .enable_next_moved = true,
8606 }),8844 }),
...@@ -8680,7 +8918,7 @@ fn prepareDynamic(elf: *Elf) Error!void {...@@ -8680,7 +8918,7 @@ fn prepareDynamic(elf: *Elf) Error!void {
86808918
8681 const dynamic_size = dynamic_len * 2 * elf.targetPtrSize();8919 const dynamic_size = dynamic_len * 2 * elf.targetPtrSize();
86828920
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 switch (elf.shdrPtr(elf.shndx.dynamic)) {8922 switch (elf.shdrPtr(elf.shndx.dynamic)) {
8685 inline else => |shdr| elf.targetStore(&shdr.size, @intCast(dynamic_size)),8923 inline else => |shdr| elf.targetStore(&shdr.size, @intCast(dynamic_size)),
8686 }8924 }
...@@ -8702,7 +8940,7 @@ fn flushDynamic(elf: *Elf) void {...@@ -8702,7 +8940,7 @@ fn flushDynamic(elf: *Elf) void {
8702 comp.config.pie);8940 comp.config.pie);
87038941
8704 const dynamic_size = elf.targetLoad(&@field(elf.shdrPtr(elf.shndx.dynamic), @tagName(class)).size);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 const dynamic_entries: [][2]ElfN.Addr = @ptrCast(@alignCast(dynamic_slice));8944 const dynamic_entries: [][2]ElfN.Addr = @ptrCast(@alignCast(dynamic_slice));
87078945
8708 var dynamic_index: usize = 0;8946 var dynamic_index: usize = 0;
...@@ -8816,6 +9054,8 @@ fn flushDynamic(elf: *Elf) void {...@@ -8816,6 +9054,8 @@ fn flushDynamic(elf: *Elf) void {
88169054
8817fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {9055fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
8818 name: []const u8 = "",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 type: std.elf.SHT = .NULL,9059 type: std.elf.SHT = .NULL,
8820 flags: std.elf.SHF = .{},9060 flags: std.elf.SHF = .{},
8821 size: std.elf.Xword = 0,9061 size: std.elf.Xword = 0,
...@@ -8836,7 +9076,9 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -8836,7 +9076,9 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
8836 try elf.ensureSegmentAligned(phndx, opts.addralign);9076 try elf.ensureSegmentAligned(phndx, opts.addralign);
8837 }9077 }
8838 const gpa = elf.base.comp.gpa;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 try elf.shdrs.ensureUnusedCapacity(gpa, 1);9082 try elf.shdrs.ensureUnusedCapacity(gpa, 1);
8841 const want_symbol = opts.flags.ALLOC or switch (opts.type) {9083 const want_symbol = opts.flags.ALLOC or switch (opts.type) {
8842 .NULL, .PROGBITS, .NOBITS, .X86_64_UNWIND => elf.ehdrType() == .REL,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,26 +9119,29 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
8877 .EXEC, .DYN => segment_ni,9119 .EXEC, .DYN => segment_ni,
8878 };9120 };
8879 assert(opts.addralign.check(opts.size));9121 assert(opts.addralign.check(opts.size));
8880 const ni = elf.addNodeAssumeCapacity(try parent_ni.addFloatingChild(gpa, &elf.mf, .{9122 const oni: MappedFile.Node.Index.Optional = switch (opts.type) {
8881 .size = opts.node_align.forward(opts.size),9123 .NOBITS => .none,
8882 .alignment = opts.addralign.max(opts.node_align),9124 else => .wrap(elf.addNodeAssumeCapacity(
8883 .resized = opts.size > 0,9125 try parent_ni.addFloatingChild(gpa, &elf.mf, .{
8884 .bubbles_moved = opts.flags.ALLOC,9126 .size = opts.node_align.forward(opts.size),
8885 }), switch (opts.manual_size) {9127 .alignment = opts.addralign.max(opts.node_align),
8886 false => .{ .section = shndx },9128 .resized = opts.size > 0,
8887 true => .{ .section_manual_size = shndx },9129 .bubbles_moved = opts.flags.ALLOC,
8888 });9130 }),
8889 const addr = elf.computeNodeVAddr(ni);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 elf.shdrs.appendAssumeCapacity(.{9135 elf.shdrs.appendAssumeCapacity(.{
8891 .lsi = if (want_symbol) try elf.addLocalSymbol(.{9136 .lsi = if (want_symbol) try elf.addLocalSymbol(.{
8892 .node = ni.toOptional(),9137 .node = oni,
8893 .name = "",9138 .name = "",
8894 .value = addr,9139 .value = addr,
8895 .size = 0,9140 .size = 0,
8896 .type = .SECTION,9141 .type = .SECTION,
8897 .shndx = shndx,9142 .shndx = shndx,
8898 }) else .null,9143 }) else .null,
8899 .ni = ni,9144 .ni = oni,
8900 .rela = switch (opts.type) {9145 .rela = switch (opts.type) {
8901 .REL => unreachable,9146 .REL => unreachable,
8902 .RELA => .{ .free_head = .none },9147 .RELA => .{ .free_head = .none },
...@@ -8910,7 +9155,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -8910,7 +9155,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
8910 .type = opts.type,9155 .type = opts.type,
8911 .flags = .{ .shf = opts.flags },9156 .flags = .{ .shf = opts.flags },
8912 .addr = @intCast(addr),9157 .addr = @intCast(addr),
8913 .offset = @intCast(elf.computeNodeElfOffset(ni)),9158 .offset = if (oni.unwrap()) |ni| @intCast(elf.computeNodeElfOffset(ni)) else 0,
8914 .size = @intCast(opts.size),9159 .size = @intCast(opts.size),
8915 .link = opts.link,9160 .link = opts.link,
8916 .info = opts.info,9161 .info = opts.info,
...@@ -8973,7 +9218,7 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize)...@@ -8973,7 +9218,7 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize)
8973 .NONE, _ => unreachable,9218 .NONE, _ => unreachable,
8974 inline else => |ct_class| (elf.got.count() + new_got_entries) * @sizeOf(ct_class.ElfN().Addr),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);
89779222
8978 if (elf.shndx.dynamic != .UNDEF) {9223 if (elf.shndx.dynamic != .UNDEF) {
8979 try elf.shndx.rela_dyn.relaEnsureAdditionalCapacity(elf, new_got_entries);9224 try elf.shndx.rela_dyn.relaEnsureAdditionalCapacity(elf, new_got_entries);
...@@ -9816,7 +10061,7 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {...@@ -9816,7 +10061,7 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {
9816 const addr_size = @sizeOf(class.ElfN().Addr);10061 const addr_size = @sizeOf(class.ElfN().Addr);
9817 const offset = got_index * addr_size;10062 const offset = got_index * addr_size;
9818 const entry_ptr: *class.ElfN().Addr = @ptrCast(@alignCast(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 elf.targetStore(entry_ptr, switch (entry_value) {10066 elf.targetStore(entry_ptr, switch (entry_value) {
9822 .unsigned => |x| @intCast(x),10067 .unsigned => |x| @intCast(x),
...@@ -10179,7 +10424,7 @@ fn updateFuncInner(...@@ -10179,7 +10424,7 @@ fn updateFuncInner(
10179 const frame_ni = elf.addNodeAssumeCapacity(try switch (wip_func.frame_format) {10424 const frame_ni = elf.addNodeAssumeCapacity(try switch (wip_func.frame_format) {
10180 .debug_frame => elf.shndx.debug_frame,10425 .debug_frame => elf.shndx.debug_frame,
10181 .eh_frame => elf.shndx.eh_frame,10426 .eh_frame => elf.shndx.eh_frame,
10182 }.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{10427 }.node(elf).addFloatingChild(gpa, &elf.mf, .{
10183 .alignment = frame_align.max(elf.mf.flags.block_size),10428 .alignment = frame_align.max(elf.mf.flags.block_size),
10184 .enable_next_moved = true,10429 .enable_next_moved = true,
10185 }), .{ .unit_frame = wip_func.unit });10430 }), .{ .unit_frame = wip_func.unit });
...@@ -10624,12 +10869,46 @@ pub fn idle(elf: *Elf) link.Error!bool {...@@ -10624,12 +10869,46 @@ pub fn idle(elf: *Elf) link.Error!bool {
10624 if (clean_moved or clean_resized or clean_next_moved) try elf.flushPadding(ni);10869 if (clean_moved or clean_resized or clean_next_moved) try elf.flushPadding(ni);
10625 break :task;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 if (elf.inputs.items.len - elf.input_pending_index > 0) return true;10906 if (elf.inputs.items.len - elf.input_pending_index > 0) return true;
10629 if (elf.input_sections.items.len - elf.input_section_pending_index > 0) return true;10907 if (elf.input_sections.items.len - elf.input_section_pending_index > 0) return true;
10630 if (elf.one_shot_fixups.items.len > 0) return true;10908 if (elf.one_shot_fixups.items.len > 0) return true;
10631 if (elf.changed_symtab_index.count() > 0) return true;10909 if (elf.changed_symtab_index.count() > 0) return true;
10632 if (elf.mf.updates.items.len > 0) return true;10910 if (elf.mf.updates.items.len > 0) return true;
10911 if (elf.bss_moved) return true;
10633 return false;10912 return false;
10634}10913}
1063510914
...@@ -10984,8 +11263,23 @@ fn flushElfOffset(elf: *Elf, ni: MappedFile.Node.Index) void {...@@ -10984,8 +11263,23 @@ fn flushElfOffset(elf: *Elf, ni: MappedFile.Node.Index) void {
10984 inline else => |phdr, class| {11263 inline else => |phdr, class| {
10985 const ph = &phdr[phndx];11264 const ph = &phdr[phndx];
10986 elf.targetStore(&ph.offset, @intCast(elf_offset));11265 elf.targetStore(&ph.offset, @intCast(elf_offset));
10987 if (elf.targetLoad(&ph.type) == .PHDR) {11266 switch (elf.targetLoad(&ph.type)) {
10988 @field(elf.ehdrPtr(), @tagName(class)).phoff = ph.offset;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,7 +11321,6 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
11027 .DYNAMIC,11321 .DYNAMIC,
11028 .INTERP,11322 .INTERP,
11029 .PHDR,11323 .PHDR,
11030 .TLS,
11031 .GNU_EH_FRAME,11324 .GNU_EH_FRAME,
11032 .GNU_RELRO,11325 .GNU_RELRO,
11033 => {11326 => {
...@@ -11035,6 +11328,22 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void...@@ -11035,6 +11328,22 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
11035 elf.targetStore(&ph.vaddr, @intCast(new_vaddr));11328 elf.targetStore(&ph.vaddr, @intCast(new_vaddr));
11036 elf.targetStore(&ph.paddr, @intCast(new_vaddr));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,6 +11674,89 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
11365 try ni.childrenMoved(elf.base.comp.gpa, &elf.mf);11674 try ni.childrenMoved(elf.base.comp.gpa, &elf.mf);
11366}11675}
1136711676
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.
11683fn 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.
11741fn 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/// Given the index of a `PT_LOAD`/`PT_NULL` segment, assumes that the phdr's `offset` and `filesz`11760/// Given the index of a `PT_LOAD`/`PT_NULL` segment, assumes that the phdr's `offset` and `filesz`
11369/// have been updated as needed by the caller, and updates the `@"align"`, `vaddr`, `paddr`, and11761/// have been updated as needed by the caller, and updates the `@"align"`, `vaddr`, `paddr`, and
11370/// `memsz` fields of the segment, in order to place it at a valid virtual address.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,22 +11785,23 @@ fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Erro
11393 switch (elf.phdrSlice()) {11785 switch (elf.phdrSlice()) {
11394 inline else => |phdr| {11786 inline else => |phdr| {
11395 const offset = elf.targetLoad(&phdr[orig_phndx].offset);11787 const offset = elf.targetLoad(&phdr[orig_phndx].offset);
11396 const size = elf.targetLoad(&phdr[orig_phndx].filesz);11788 const filesz = 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()));
1140611789
11407 const orig_vaddr = elf.targetLoad(&phdr[orig_phndx].vaddr);11790 const orig_vaddr = elf.targetLoad(&phdr[orig_phndx].vaddr);
11408 assert(elf.targetLoad(&phdr[orig_phndx].paddr) == orig_vaddr);11791 assert(elf.targetLoad(&phdr[orig_phndx].paddr) == orig_vaddr);
1140911792
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 var vaddr: u64 = orig_vaddr;11799 var vaddr: u64 = orig_vaddr;
1141111800
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 // First, we will shift the virtual address as needed in order to maintain the required11805 // First, we will shift the virtual address as needed in order to maintain the required
11413 // property that vaddr is congruent to offset modulo the phdr alignment.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,7 +11845,7 @@ fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Erro
11452 // the segment is already known to be moving---making it easier to grow in-place is11845 // the segment is already known to be moving---making it easier to grow in-place is
11453 // the whole point of the multiplier!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 if (vaddr + target_size <= next_page_vaddr) {11849 if (vaddr + target_size <= next_page_vaddr) {
11457 break; // hooray, we fit here!11850 break; // hooray, we fit here!
11458 }11851 }
...@@ -11474,17 +11867,13 @@ fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Erro...@@ -11474,17 +11867,13 @@ fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Erro
11474 else => {},11867 else => {},
11475 };11868 };
1147611869
11477 const free_vaddr = vaddr + size * reserve_size_multiplier;11870 const free_vaddr = vaddr + memsz * reserve_size_multiplier;
1147811871
11479 const next_align = page_align.max(next_ni.alignment(&elf.mf));11872 const next_align = page_align.max(next_ni.alignment(&elf.mf));
11480 const next_offset = elf.targetLoad(&next_ph.offset);11873 const next_offset = elf.targetLoad(&next_ph.offset);
11481 const next_new_vaddr = next_align.forward(free_vaddr) + next_offset % next_align.toByteUnits();11874 const next_new_vaddr = next_align.forward(free_vaddr) + next_offset % next_align.toByteUnits();
1148211875
11483 // This logic for updating the data segment's vaddr is identical to how we11876 try elf.updateSegmentLoadAddress(next_ni, next_new_vaddr);
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);
1148811877
11489 break;11878 break;
11490 },11879 },
...@@ -11507,9 +11896,7 @@ fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Erro...@@ -11507,9 +11896,7 @@ fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Erro
11507 }11896 }
1150811897
11509 if (vaddr != orig_vaddr) {11898 if (vaddr != orig_vaddr) {
11510 elf.targetStore(&phdr[phndx].vaddr, @intCast(vaddr));11899 try elf.updateSegmentLoadAddress(segment_ni, vaddr);
11511 elf.targetStore(&phdr[phndx].paddr, @intCast(vaddr));
11512 try segment_ni.childrenMoved(elf.base.comp.gpa, &elf.mf);
11513 }11900 }
11514 },11901 },
11515 }11902 }
...@@ -11539,21 +11926,50 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo...@@ -11539,21 +11926,50 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo
11539 .ehdr => unreachable,11926 .ehdr => unreachable,
11540 .shdr => {},11927 .shdr => {},
11541 .segment => |phndx| switch (elf.phdrSlice()) {11928 .segment => |phndx| switch (elf.phdrSlice()) {
11542 inline else => |phdr| {11929 inline else => |phdr, class| {
11543 assert(elf.phdrs.items[phndx].unwrap().? == ni);11930 assert(elf.phdrs.items[phndx].unwrap().? == ni);
11544 const ph = &phdr[phndx];11931 const ph = &phdr[phndx];
11545 elf.targetStore(&ph.filesz, @intCast(size));
11546 switch (elf.targetLoad(&ph.type)) {11932 switch (elf.targetLoad(&ph.type)) {
11547 else => unreachable,11933 else => unreachable,
11548 .NULL, .LOAD => {11934 .NULL, .LOAD => {
11549 elf.targetStore(&ph.type, if (size > 0) .LOAD else .NULL);11935 elf.targetStore(&ph.filesz, @intCast(size));
11550 try elf.allocateSegmentLoadAddress(phndx);11936 try elf.allocateSegmentLoadAddress(phndx);
11937 if (ni == elf.ni.data) elf.bss_moved = true;
11551 },11938 },
11552 .DYNAMIC, .INTERP, .PHDR, .GNU_EH_FRAME, .GNU_RELRO => {11939 .DYNAMIC, .INTERP, .PHDR, .GNU_EH_FRAME, .GNU_RELRO => {
11940 elf.targetStore(&ph.filesz, @intCast(size));
11553 elf.targetStore(&ph.memsz, @intCast(size));11941 elf.targetStore(&ph.memsz, @intCast(size));
11554 },11942 },
11555 .TLS => {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 // TPOFF relocations care about the size of the TLS segment. Re-apply11973 // TPOFF relocations care about the size of the TLS segment. Re-apply
11558 // those, and also update any GOT entries from GOTTPOFF relocations.11974 // those, and also update any GOT entries from GOTTPOFF relocations.
11559 for (elf.tls_size_symbol_relocs.keys()) |reloc| {11975 for (elf.tls_size_symbol_relocs.keys()) |reloc| {
...@@ -11904,17 +12320,17 @@ fn ensurePltEntry(elf: *Elf, gsi: Symbol.Global.Index) Error!bool {...@@ -11904,17 +12320,17 @@ fn ensurePltEntry(elf: *Elf, gsi: Symbol.Global.Index) Error!bool {
11904 const gpa = elf.base.comp.gpa;12320 const gpa = elf.base.comp.gpa;
11905 try elf.shndx.rela_plt.relaEnsureAdditionalCapacity(elf, 1);12321 try elf.shndx.rela_plt.relaEnsureAdditionalCapacity(elf, 1);
11906 try elf.plt.ensureUnusedCapacity(gpa, 1);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 gpa,12324 gpa,
11909 &elf.mf,12325 &elf.mf,
11910 plt.entry_size * (plt.header_entries + elf.plt.count() + 1),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 gpa,12329 gpa,
11914 &elf.mf,12330 &elf.mf,
11915 elf.targetPtrSize() * (got_plt.header_entries + elf.plt.count() + 1),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 gpa,12334 gpa,
11919 &elf.mf,12335 &elf.mf,
11920 plt_sec.entry_size * (elf.plt.count() + 1),12336 plt_sec.entry_size * (elf.plt.count() + 1),
...@@ -11962,7 +12378,7 @@ fn ensurePltEntry(elf: *Elf, gsi: Symbol.Global.Index) Error!bool {...@@ -11962,7 +12378,7 @@ fn ensurePltEntry(elf: *Elf, gsi: Symbol.Global.Index) Error!bool {
11962 switch (elf.ehdrMachine()) {12378 switch (elf.ehdrMachine()) {
11963 .AARCH64, .PPC64, .RISCV => |machine| @panic(@tagName(machine)),12379 .AARCH64, .PPC64, .RISCV => |machine| @panic(@tagName(machine)),
11964 .X86_64 => {12380 .X86_64 => {
11965 const plt_ni = elf.shndx.plt.get(elf).ni;12381 const plt_ni = elf.shndx.plt.node(elf);
11966 const plt_addr = plt_addr: switch (elf.shdrPtr(elf.shndx.plt)) {12382 const plt_addr = plt_addr: switch (elf.shdrPtr(elf.shndx.plt)) {
11967 inline else => |shdr| {12383 inline else => |shdr| {
11968 const old_size = 16 * (1 + plt_index);12384 const old_size = 16 * (1 + plt_index);
...@@ -11986,7 +12402,7 @@ fn ensurePltEntry(elf: *Elf, gsi: Symbol.Global.Index) Error!bool {...@@ -11986,7 +12402,7 @@ fn ensurePltEntry(elf: *Elf, gsi: Symbol.Global.Index) Error!bool {
11986 },12402 },
11987 };12403 };
1198812404
11989 const got_plt_ni = elf.shndx.got_plt.get(elf).ni;12405 const got_plt_ni = elf.shndx.got_plt.node(elf);
11990 switch (elf.shdrPtr(elf.shndx.got_plt)) {12406 switch (elf.shdrPtr(elf.shndx.got_plt)) {
11991 inline else => |shdr, class| {12407 inline else => |shdr, class| {
11992 assert(elf.targetLoad(&shdr.size) == got_plt_offset);12408 assert(elf.targetLoad(&shdr.size) == got_plt_offset);
...@@ -12000,7 +12416,7 @@ fn ensurePltEntry(elf: *Elf, gsi: Symbol.Global.Index) Error!bool {...@@ -12000,7 +12416,7 @@ fn ensurePltEntry(elf: *Elf, gsi: Symbol.Global.Index) Error!bool {
12000 },12416 },
12001 }12417 }
1200212418
12003 const plt_sec_ni = elf.shndx.plt_sec.get(elf).ni;12419 const plt_sec_ni = elf.shndx.plt_sec.node(elf);
12004 switch (elf.shdrPtr(elf.shndx.plt_sec)) {12420 switch (elf.shdrPtr(elf.shndx.plt_sec)) {
12005 inline else => |shdr| {12421 inline else => |shdr| {
12006 const old_size = 16 * plt_index;12422 const old_size = 16 * plt_index;
...@@ -12024,7 +12440,7 @@ fn ensurePltEntry(elf: *Elf, gsi: Symbol.Global.Index) Error!bool {...@@ -12024,7 +12440,7 @@ fn ensurePltEntry(elf: *Elf, gsi: Symbol.Global.Index) Error!bool {
12024 },12440 },
12025 .LOONGARCH => {12441 .LOONGARCH => {
12026 // add a .PLT entry, writing the template12442 // 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 const plt_addr, const plt_slice = plt_entry: switch (elf.shdrPtr(elf.shndx.plt)) {12444 const plt_addr, const plt_slice = plt_entry: switch (elf.shdrPtr(elf.shndx.plt)) {
12029 inline else => |shdr| {12445 inline else => |shdr| {
12030 const old_size = 16 * (1 + plt_index);12446 const old_size = 16 * (1 + plt_index);
...@@ -12048,7 +12464,7 @@ fn ensurePltEntry(elf: *Elf, gsi: Symbol.Global.Index) Error!bool {...@@ -12048,7 +12464,7 @@ fn ensurePltEntry(elf: *Elf, gsi: Symbol.Global.Index) Error!bool {
12048 };12464 };
1204912465
12050 // add a .GOT.PLT entry, writing the address of the corresponding .PLT entry12466 // 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 switch (elf.shdrPtr(elf.shndx.got_plt)) {12468 switch (elf.shdrPtr(elf.shndx.got_plt)) {
12053 inline else => |shdr, class| {12469 inline else => |shdr, class| {
12054 assert(elf.targetLoad(&shdr.size) == got_plt_offset);12470 assert(elf.targetLoad(&shdr.size) == got_plt_offset);
...@@ -12080,7 +12496,7 @@ fn ensurePltEntry(elf: *Elf, gsi: Symbol.Global.Index) Error!bool {...@@ -12080,7 +12496,7 @@ fn ensurePltEntry(elf: *Elf, gsi: Symbol.Global.Index) Error!bool {
12080 },12496 },
12081 .SPARCV9 => {12497 .SPARCV9 => {
12082 // add a .PLT entry, writing the template12498 // 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 switch (elf.shdrPtr(elf.shndx.plt)) {12500 switch (elf.shdrPtr(elf.shndx.plt)) {
12085 inline else => |shdr| {12501 inline else => |shdr| {
12086 assert(elf.targetLoad(&shdr.size) == got_plt_offset);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,7 +12553,7 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad
12137 // We also need to update all of the references from `.plt.sec` to `.got.plt`.12553 // We also need to update all of the references from `.plt.sec` to `.got.plt`.
12138 // However, if there's also a flush pending for `.got.plt`, don't bother doing12554 // However, if there's also a flush pending for `.got.plt`, don't bother doing
12139 // this now, because we'll do it when `.got.plt` is flushed anyway.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 return;12557 return;
12142 }12558 }
12143 // Exit this `switch` to update those references.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,7 +12568,7 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad
12152 // We also need to update all of the references from `.plt.sec` to `.got.plt`.12568 // We also need to update all of the references from `.plt.sec` to `.got.plt`.
12153 // However, if there's also a flush pending for `.plt.sec`, don't bother doing12569 // However, if there's also a flush pending for `.plt.sec`, don't bother doing
12154 // this now, because we'll do it when `.plt.sec` is flushed anyway.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 return;12572 return;
12157 }12573 }
12158 // Exit this `switch` to update those references.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,7 +12577,7 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad
12161 // We are updating the references from `.plt.sec` to `.got.plt`.12577 // We are updating the references from `.plt.sec` to `.got.plt`.
12162 const got_plt_addr = elf.shndx.got_plt.vaddr(elf);12578 const got_plt_addr = elf.shndx.got_plt.vaddr(elf);
12163 const plt_sec_addr = elf.shndx.plt_sec.vaddr(elf);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 switch (elf.identClass()) {12581 switch (elf.identClass()) {
12166 .NONE, _ => unreachable,12582 .NONE, _ => unreachable,
12167 inline else => |class| {12583 inline else => |class| {
...@@ -12194,7 +12610,7 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad...@@ -12194,7 +12610,7 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad
12194 // We also need to update all of the references from `.plt` to `.got.plt`.12610 // We also need to update all of the references from `.plt` to `.got.plt`.
12195 // However, if there's also a flush pending for `.got.plt`, don't bother doing12611 // However, if there's also a flush pending for `.got.plt`, don't bother doing
12196 // this now, because we'll do it when `.got.plt` is flushed anyway.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 return;12614 return;
12199 }12615 }
12200 // Exit this `switch` to update those references.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,7 +12626,7 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad
12210 // We also need to update all of the references from `.plt` to `.got.plt`.12626 // We also need to update all of the references from `.plt` to `.got.plt`.
12211 // However, if there's also a flush pending for `.plt`, don't bother doing12627 // However, if there's also a flush pending for `.plt`, don't bother doing
12212 // this now, because we'll do it when `.plt` is flushed anyway.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 return;12630 return;
12215 }12631 }
12216 // Exit this `switch` to update those references.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,7 +12635,7 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad
12219 // We are updating the references from `.plt` to `.got.plt`.12635 // We are updating the references from `.plt` to `.got.plt`.
12220 const got_plt_addr = elf.shndx.got_plt.vaddr(elf);12636 const got_plt_addr = elf.shndx.got_plt.vaddr(elf);
12221 const plt_addr = elf.shndx.plt.vaddr(elf);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 switch (elf.identClass()) {12639 switch (elf.identClass()) {
12224 .NONE, _ => unreachable,12640 .NONE, _ => unreachable,
12225 inline else => |class| {12641 inline else => |class| {
...@@ -12657,7 +13073,7 @@ const VerdefAdapter = struct {...@@ -12657,7 +13073,7 @@ const VerdefAdapter = struct {
12657fn verdefId(elf: *Elf, version: String(.dynstr)) Error!u15 {13073fn verdefId(elf: *Elf, version: String(.dynstr)) Error!u15 {
12658 const gpa = elf.base.comp.gpa;13074 const gpa = elf.base.comp.gpa;
12659 const adapter: VerdefAdapter = .{ .elf = elf };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 const gop = try elf.verdef.getOrPutAdapted(gpa, version, adapter);13077 const gop = try elf.verdef.getOrPutAdapted(gpa, version, adapter);
1266213078
12663 if (gop.found_existing) {13079 if (gop.found_existing) {
...@@ -12766,7 +13182,7 @@ const VerneedAdapter = struct {...@@ -12766,7 +13182,7 @@ const VerneedAdapter = struct {
12766fn verneedId(elf: *Elf, file: String(.dynstr), version: String(.dynstr)) Error!u15 {13182fn verneedId(elf: *Elf, file: String(.dynstr), version: String(.dynstr)) Error!u15 {
12767 const gpa = elf.base.comp.gpa;13183 const gpa = elf.base.comp.gpa;
12768 const adapter: VerneedAdapter = .{ .elf = elf };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));
1277013186
12771 if (elf.verneed.getIndexAdapted(@as(VerneedAdapter.Key, .{13187 if (elf.verneed.getIndexAdapted(@as(VerneedAdapter.Key, .{
12772 .file = file,13188 .file = file,