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 {
6666 debug_rnglists: Section.Index,
6767 debug_str: Section.Index,
6868 debug_str_offsets: Section.Index,
69 bss: Section.Index,
70 tbss: Section.Index,
6971 // These sections are created only as needed, and are initially `.UNDEF`.
7072 init_array: Section.Index,
7173 fini_array: Section.Index,
......@@ -135,6 +137,25 @@ node_global_symbols: std.array_hash_map.Auto(MappedFile.Node.Index, Symbol.Globa
135137/// See the definition of `DsoGlobals`.
136138dso_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
138159shstrtab: StringTable,
139160strtab: StringTable,
140161dynstr: StringTable,
......@@ -491,8 +512,9 @@ const Archive = struct {
491512};
492513
493514const Section = struct {
494 /// The node corresponding to this section.
495 ni: MappedFile.Node.Index,
515 /// File-backed node corresponding to this section.
516 /// This is `.none` for `SHT_NOBITS` sections.
517 ni: MappedFile.Node.Index.Optional,
496518 /// A symbol which is exactly at the start of this section.
497519 ///
498520 /// When not emitting a relocatable, or for special section types, this is `.null`.
......@@ -596,6 +618,13 @@ const Section = struct {
596618 return &elf.shdrs.items[@backingInt(shndx) - 1]; // overflow means you tried to get the `.UNDEF` section
597619 }
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
599628 fn name(shndx: Index, elf: *Elf) String(.shstrtab) {
600629 return switch (elf.shdrPtr(shndx)) {
601630 inline else => |shdr| @fromBackingInt(elf.targetLoad(&shdr.name)),
......@@ -648,21 +677,39 @@ const Section = struct {
648677 elf.targetStore(&shdr.addralign, @intCast(min_align.toByteUnits()));
649678 },
650679 }
651 const ni = shndx.get(elf).ni;
652 if (min_align.compare(.gt, ni.alignment(&elf.mf))) {
653 try ni.realign(elf.base.comp.gpa, &elf.mf, min_align);
654 }
655 switch (elf.getNode(ni.parent(&elf.mf).unwrap().?)) {
656 .elf => {},
657 .segment => |phndx| try elf.ensureSegmentAligned(phndx, min_align),
658 else => unreachable,
680
681 if (shndx.get(elf).ni.unwrap()) |ni| {
682 if (min_align.compare(.gt, ni.alignment(&elf.mf))) {
683 try ni.realign(elf.base.comp.gpa, &elf.mf, min_align);
684 }
685 switch (elf.getNode(ni.parent(&elf.mf).unwrap().?)) {
686 .elf => {},
687 .segment => |phndx| try elf.ensureSegmentAligned(phndx, min_align),
688 else => unreachable,
689 }
690 } else {
691 // For sections without nodes (NOBITS), propagate alignment to the parent.
692 switch (elf.shdrPtr(shndx)) {
693 inline else => |shdr| assert(elf.targetLoad(&shdr.type) == .NOBITS),
694 }
695
696 if (elf.ehdrType() == .REL) return;
697
698 const segment_ni: MappedFile.Node.Index = seg: {
699 if (shndx == elf.shndx.bss) break :seg elf.ni.data;
700 if (shndx == elf.shndx.tbss) break :seg elf.ni.tls.unwrap().?;
701 // NOBITS sections other than `.bss` and `.tbss` are only emitted in `ET_REL`s.
702 unreachable;
703 };
704
705 try elf.ensureSegmentAligned(elf.getNode(segment_ni).segment, min_align);
659706 }
660707 }
661708
662709 /// Asserts that `rela_shndx` is a `SHT_RELA` section and ensures that its node has enough
663710 /// unused space to hold `n` additional `ElfN.Rela` entries.
664711 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);
666713 const need_size: u64 = switch (elf.shdrPtr(rela_shndx)) {
667714 inline else => |shdr, class| need_size: {
668715 assert(elf.targetLoad(&shdr.type) == .RELA);
......@@ -673,7 +720,7 @@ const Section = struct {
673720 const opt_free_head = rela_shndx.get(elf).rela.free_head;
674721 const free_head = opt_free_head.unwrap() orelse break :free_len 0;
675722 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)],
677724 ));
678725 const free_len = elf.targetLoad(&relas[@backingInt(free_head)].addend);
679726 assert(free_len > 0);
......@@ -683,7 +730,7 @@ const Section = struct {
683730 break :need_size cur_size + need_additional * ent_size;
684731 },
685732 };
686 try node.ensureMinimumSize(elf.base.comp.gpa, &elf.mf, need_size);
733 try ni.ensureMinimumSize(elf.base.comp.gpa, &elf.mf, need_size);
687734 }
688735
689736 /// Asserts that `rela_shndx` is a `SHT_RELA` section and deletes the `ElfN.Rela` entry at
......@@ -695,7 +742,7 @@ const Section = struct {
695742 assert(elf.targetLoad(&shdr.type) == .RELA);
696743 assert(elf.targetLoad(&shdr.entsize) == @sizeOf(class.ElfN().Rela));
697744 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))],
699746 ));
700747 const opt_free_head = rela_shndx.get(elf).rela.free_head;
701748 const old_free_len: u32 = free_len: {
......@@ -743,7 +790,7 @@ const Section = struct {
743790 assert(elf.targetLoad(&shdr.entsize) == ent_size);
744791 const new_index: RelaIndex = if (rela_shndx.get(elf).rela.free_head.unwrap()) |free_head| new_index: {
745792 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))],
747794 ));
748795 const next: RelaIndex.Optional = @fromBackingInt(@intCast(elf.targetLoad(
749796 &relas[@backingInt(free_head)].offset,
......@@ -766,7 +813,7 @@ const Section = struct {
766813 break :new_index @fromBackingInt(@intCast(@divExact(old_size, ent_size)));
767814 };
768815 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))],
770817 ));
771818 relas[@backingInt(new_index)] = .{
772819 .offset = @intCast(opts.offset),
......@@ -794,7 +841,7 @@ const Section = struct {
794841 assert(elf.targetLoad(&shdr.type) == .RELA);
795842 assert(elf.targetLoad(&shdr.entsize) == @sizeOf(class.ElfN().Rela));
796843 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))],
798845 ));
799846 const rela_info = elf.targetLoad(&relas[@backingInt(index)].info);
800847 {
......@@ -818,7 +865,7 @@ const Section = struct {
818865 assert(elf.targetLoad(&shdr.type) == .RELA);
819866 assert(elf.targetLoad(&shdr.entsize) == @sizeOf(class.ElfN().Rela));
820867 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))],
822869 ));
823870 {
824871 const rela_info = elf.targetLoad(&relas[@backingInt(index)].info);
......@@ -839,7 +886,7 @@ const Section = struct {
839886 assert(elf.targetLoad(&shdr.type) == .RELA);
840887 assert(elf.targetLoad(&shdr.entsize) == @sizeOf(class.ElfN().Rela));
841888 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))],
843890 ));
844891 {
845892 const rela_info = elf.targetLoad(&relas[@backingInt(index)].info);
......@@ -863,7 +910,7 @@ const Section = struct {
863910 assert(elf.targetLoad(&shdr.type) == .RELA);
864911 assert(elf.targetLoad(&shdr.entsize) == @sizeOf(class.ElfN().Rela));
865912 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))],
867914 ));
868915 {
869916 const rela_info = elf.targetLoad(&relas[@backingInt(index)].info);
......@@ -2220,7 +2267,7 @@ const GotReloc = struct {
22202267 fn apply(reloc: *GotReloc, elf: *Elf) void {
22212268 assert(elf.ehdrType() != .REL);
22222269 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)) {
22242271 // There's no point applying the relocation now, because it will be re-applied by
22252272 // `flushMoved` at some point anyway.
22262273 return;
......@@ -2452,7 +2499,7 @@ fn ensureDynsymHashCapacity(elf: *Elf, max_dynsym_count: u32) Error!void {
24522499 switch (elf.targetDynsymHashInfo()) {
24532500 inline else => |info| {
24542501 {
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));
24562503 const header: *info.Header() = @ptrCast(section_slice[0..@sizeOf(info.Header())]);
24572504 assert(elf.targetLoad(&header.nchain) == cur_dynsym_count);
24582505 const nbucket = elf.targetLoad(&header.nbucket);
......@@ -2460,7 +2507,7 @@ fn ensureDynsymHashCapacity(elf: *Elf, max_dynsym_count: u32) Error!void {
24602507 // We don't need to add any buckets, but we still need to make sure the section is large
24612508 // enough to fit `max_dynsym_count` chains.
24622509 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);
24642511 return;
24652512 }
24662513 // 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 {
24722519
24732520 {
24742521 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);
24762523 }
24772524
24782525 elf.mf.nodes_lock.lock();
24792526 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));
24822529 const header: *info.Header() = @ptrCast(section_slice[0..@sizeOf(info.Header())]);
24832530 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 {
25082555fn appendDynsymHashEntry(elf: *Elf, dynsym_index: u32) void {
25092556 switch (elf.targetDynsymHashInfo()) {
25102557 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));
25122559 const header: *info.Header() = @ptrCast(section_slice[0..@sizeOf(info.Header())]);
25132560 assert(elf.targetLoad(&header.nchain) == dynsym_index);
25142561 elf.targetStore(&header.nchain, dynsym_index + 1);
......@@ -2529,7 +2576,7 @@ fn populateDynsymHashEntry(elf: *Elf, dynsym_index: u32) void {
25292576
25302577 switch (elf.targetDynsymHashInfo()) {
25312578 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));
25332580 const header: *info.Header() = @ptrCast(section_slice[0..@sizeOf(info.Header())]);
25342581 const trailing: []info.Int() = @ptrCast(section_slice[@sizeOf(info.Header())..]);
25352582
......@@ -2551,7 +2598,7 @@ fn popDynsymHashEntry(elf: *Elf, dynsym_index: u32) void {
25512598
25522599 switch (elf.targetDynsymHashInfo()) {
25532600 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));
25552602 const header: *info.Header() = @ptrCast(section_slice[0..@sizeOf(info.Header())]);
25562603 assert(elf.targetLoad(&header.nchain) == dynsym_index + 1);
25572604 elf.targetStore(&header.nchain, dynsym_index);
......@@ -2570,7 +2617,7 @@ fn clearDynsymHashEntry(elf: *Elf, dynsym_index: u32) void {
25702617
25712618 switch (elf.targetDynsymHashInfo()) {
25722619 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));
25742621 const header: *info.Header() = @ptrCast(section_slice[0..@sizeOf(info.Header())]);
25752622 const trailing: []info.Int() = @ptrCast(section_slice[@sizeOf(info.Header())..]);
25762623
......@@ -2615,7 +2662,7 @@ fn pltEntryIsDead(elf: *Elf, plt_index: usize) bool {
26152662 inline else => |rela_shdr, class| {
26162663 const size = elf.targetLoad(&rela_shdr.size);
26172664 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)],
26192666 ));
26202667 const rel_type = elf.targetLoad(&relas[plt_index].info).type;
26212668 return rel_type == MachineRelocType.none(elf).unwrap(elf);
......@@ -2636,7 +2683,7 @@ fn addLocalSymbol(elf: *Elf, opts: AddLocalSymbolOptions) Error!Symbol.LocalInde
26362683
26372684 try elf.symtab.ensureUnusedCapacity(gpa, 1);
26382685 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)) {
26402687 inline else => |shdr, class| elf.targetLoad(&shdr.size) + @sizeOf(class.ElfN().Sym),
26412688 });
26422689
......@@ -2715,7 +2762,7 @@ fn addGlobalSymbol(elf: *Elf, opts: Symbol.Global.AddOptions) (error{
27152762 try elf.globals_by_name.ensureUnusedCapacity(gpa, 1);
27162763 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)) {
27192766 inline else => |shdr, class| elf.targetLoad(&shdr.size) + @sizeOf(class.ElfN().Sym),
27202767 });
27212768
......@@ -2881,6 +2928,18 @@ fn addGlobalSymbol(elf: *Elf, opts: Symbol.Global.AddOptions) (error{
28812928 old_head_ptr.prev_in_node = .wrap(gsi);
28822929 }
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
28842943 if (force_local_bind) {
28852944 elf.moveDemotedGlobal(gsi);
28862945 }
......@@ -3059,8 +3118,8 @@ fn updateGlobalDynamic(elf: *Elf, orig_gsi: Symbol.Global.Index, force_apply_rel
30593118 };
30603119 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);
3063 try elf.shndx.gnu_version.get(elf).ni.ensureMinimumSize(gpa, &elf.mf, need_dynsym_len * 2);
3121 try elf.shndx.dynsym.node(elf).ensureMinimumSize(gpa, &elf.mf, need_dynsym_len * dynsym_ent_size);
3122 try elf.shndx.gnu_version.node(elf).ensureMinimumSize(gpa, &elf.mf, need_dynsym_len * 2);
30643123 try elf.ensureDynsymHashCapacity(need_dynsym_len);
30653124
30663125 const dynstr_name: String(.dynstr) = name: {
......@@ -3246,7 +3305,7 @@ fn updateGlobalDynamic(elf: *Elf, orig_gsi: Symbol.Global.Index, force_apply_rel
32463305 errdefer assert(elf.copied_globals.pop().?.key == gsi);
32473306 try elf.nodes.ensureUnusedCapacity(gpa, 1);
32483307 const node = elf.addNodeAssumeCapacity(
3249 try shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{
3308 try shndx.node(elf).addFloatingChild(gpa, &elf.mf, .{
32503309 .size = dso_global.alignment.forward(dso_global.size),
32513310 .alignment = dso_global.alignment,
32523311 }),
......@@ -3318,8 +3377,9 @@ fn setGlobalSymbolValue(elf: *Elf, gsi: Symbol.Global.Index, new: struct {
33183377 type: std.elf.STT,
33193378 shndx: Section.Index,
33203379}) Error!void {
3321 assert(new.shndx != .UNDEF);
3380 const gpa = elf.base.comp.gpa;
33223381
3382 assert(new.shndx != .UNDEF);
33233383 const global_ptr = gsi.ptr(elf);
33243384
33253385 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 {
33413401 } else {
33423402 assert(global_ptr.next_in_node == .none);
33433403 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 }
33443419 }
33453420
33463421 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
36243699
36253700const Symbol = struct {
36263701 /// The node which this symbol's value is defined relative to. Possible values are:
3627 /// * `.none` for a SHN_ABS or SHN_UNDEF symbol
3702 /// * `.none` for a SHN_ABS or SHN_UNDEF symbol, *or* a symbol in `.bss`/`.tbss`
3703 /// (see `Elf.bss_globals` and `Elf.tbss_globals`)
36283704 /// * A section (the symbol's value is some vaddr in that section)
36293705 /// * An input section (the symbol's value is some vaddr in that input section)
36303706 /// * 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
42954371 .const_data => .{ .rodata, .OBJECT },
42964372 };
42974373 const node = elf.addNodeAssumeCapacity(
4298 try shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{}),
4374 try shndx.node(elf).addFloatingChild(gpa, &elf.mf, .{}),
42994375 switch (lazy.kind) {
43004376 .code => .{ .lazy_code = @fromBackingInt(@intCast(gop.index)) },
43014377 .const_data => .{ .lazy_const_data = @fromBackingInt(@intCast(gop.index)) },
......@@ -4472,7 +4548,7 @@ fn String(section: StringSection) type {
44724548 _,
44734549
44744550 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);
44764552 const overlong = section_node.sliceConst(&elf.mf)[@backingInt(str)..];
44774553 return overlong[0..std.mem.findScalar(u8, overlong, 0).? :0];
44784554 }
......@@ -4532,14 +4608,14 @@ const StringTable = struct {
45324608
45334609 fn getExisting(st: *StringTable, elf: *Elf, shndx: Section.Index, key: []const u8) u32 {
45344610 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);
45364612 const adapter: StringTable.Adapter = .{ .slice = slice_const };
45374613 return st.map.getKeyAdapted(key, adapter).?;
45384614 }
45394615
45404616 fn ensureAdditionalCapacity(st: *StringTable, elf: *Elf, shndx: Section.Index, string_len: usize) Error!void {
45414617 const gpa = elf.base.comp.gpa;
4542 const ni = shndx.get(elf).ni;
4618 const ni = shndx.node(elf);
45434619 const slice_const = ni.sliceConst(&elf.mf);
45444620 try st.map.ensureUnusedCapacityContext(gpa, 1, .{ .slice = slice_const });
45454621 const size: u64 = switch (elf.shdrPtr(shndx)) {
......@@ -4553,7 +4629,7 @@ const StringTable = struct {
45534629 // case the empty string.
45544630 if (key.len == 0) return 0;
45554631
4556 const ni = shndx.get(elf).ni;
4632 const ni = shndx.node(elf);
45574633 const slice_const = ni.sliceConst(&elf.mf);
45584634 const gop = st.map.getOrPutAssumeCapacityAdapted(
45594635 key,
......@@ -4711,6 +4787,8 @@ fn create(
47114787 .init_array = .UNDEF,
47124788 .fini_array = .UNDEF,
47134789 .preinit_array = .UNDEF,
4790 .bss = .UNDEF,
4791 .tbss = .UNDEF,
47144792 },
47154793 .dynamic = .{
47164794 .flags = 0,
......@@ -4738,6 +4816,11 @@ fn create(
47384816 .symbols = .empty,
47394817 .default_sym_vers = .empty,
47404818 },
4819 .bss_globals = .empty,
4820 .tbss_globals = .empty,
4821 .bss_inputs = .empty,
4822 .tbss_inputs = .empty,
4823 .bss_moved = false,
47414824 .shstrtab = .{ .map = .empty },
47424825 .strtab = .{ .map = .empty },
47434826 .dynstr = .{ .map = .empty },
......@@ -4820,6 +4903,10 @@ pub fn deinit(elf: *Elf) void {
48204903 elf.dso_globals.string_bytes.deinit(gpa);
48214904 elf.dso_globals.symbols.deinit(gpa);
48224905 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);
48234910 elf.shstrtab.map.deinit(gpa);
48244911 elf.strtab.map.deinit(gpa);
48254912 elf.dynstr.map.deinit(gpa);
......@@ -4905,7 +4992,9 @@ fn initHeaders(
49054992 shnum += 1; // .rodata
49064993 shnum += 1; // .text
49074994 shnum += 1; // .data
4995 shnum += 1; // .bss
49084996 shnum += @intFromBool(comp.config.any_non_single_threaded); // .tdata
4997 shnum += @intFromBool(comp.config.any_non_single_threaded); // .tbss
49094998 shnum += 1; // .data.rel.ro
49104999 if (have_dynamic) {
49115000 shnum += 1; // .dynamic
......@@ -5022,9 +5111,13 @@ fn initHeaders(
50225111 };
50235112 };
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
50255118 const expected_nodes_len = @as(usize, if (is_archive) 3 else 0) + // .archive, .archive_header, .archive_elf_member_header
50265119 3 + // `.elf`, `.ehdr`, and `.shdr` nodes
5027 (shnum - 1) + // -1 because the SHN_UNDEF shdr does not have a `.section` node
5120 (shnum - 1 - nobits_shnum) + // -1 because the SHN_UNDEF shdr does not have a `.section` node
50285121 (phnum -| 1) + // -1 because the GNU_STACK phdr does not have a `.segment` node
50295122 @intFromBool(have_eh_frame and @"type" != .REL); // eh_frame_footer
50305123
......@@ -5476,7 +5569,7 @@ fn initHeaders(
54765569 .node_align = node_block_align,
54775570 .manual_size = true,
54785571 }));
5479 Section.Index.get(.shstrtab, elf).ni.slice(&elf.mf)[0] = 0;
5572 Section.Index.shstrtab.node(elf).slice(&elf.mf)[0] = 0;
54805573
54815574 try Section.Index.symtab.rename(elf, ".symtab");
54825575 try Section.Index.shstrtab.rename(elf, ".shstrtab");
......@@ -5489,7 +5582,7 @@ fn initHeaders(
54895582 .node_align = node_block_align,
54905583 .manual_size = true,
54915584 }));
5492 Section.Index.get(.strtab, elf).ni.slice(&elf.mf)[0] = 0;
5585 Section.Index.strtab.node(elf).slice(&elf.mf)[0] = 0;
54935586 switch (elf.shdrPtr(.symtab)) {
54945587 inline else => |shdr| elf.targetStore(&shdr.link, @backingInt(Section.Index.strtab)),
54955588 }
......@@ -5514,6 +5607,13 @@ fn initHeaders(
55145607 .flags = .{ .WRITE = true, .ALLOC = true },
55155608 .node_align = node_block_align,
55165609 }));
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
55175617 if (@"type" != .REL) {
55185618 elf.shndx.got = try elf.addSection(elf.ni.data_rel_ro, .{
55195619 .name = ".got",
......@@ -5595,7 +5695,7 @@ fn initHeaders(
55955695 .flags = .{ .ALLOC = true },
55965696 .size = @intCast(interp.len + 1),
55975697 });
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);
55995699 @memcpy(sec_interp[0..interp.len], interp);
56005700 sec_interp[interp.len] = 0;
56015701 }
......@@ -5620,7 +5720,7 @@ fn initHeaders(
56205720 .node_align = node_block_align,
56215721 .manual_size = true,
56225722 });
5623 dynstr_shndx.get(elf).ni.slice(&elf.mf)[0] = 0;
5723 dynstr_shndx.node(elf).slice(&elf.mf)[0] = 0;
56245724 elf.shndx.dynstr = dynstr_shndx;
56255725
56265726 switch (class) {
......@@ -5765,7 +5865,7 @@ fn initHeaders(
57655865 .size = @sizeOf(info.Header()) + @sizeOf(info.Int()) * (8 + 1),
57665866 .manual_size = true,
57675867 });
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));
57695869 const header: *info.Header() = @ptrCast(hash_slice[0..@sizeOf(info.Header())]);
57705870 header.* = .{ .nbucket = 8, .nchain = 1 };
57715871 if (elf.targetEndian() != std.lang.Endian.native) {
......@@ -5779,7 +5879,7 @@ fn initHeaders(
57795879 switch (machine) {
57805880 .AARCH64, .PPC64, .RISCV => @panic(@tagName(machine)),
57815881 .X86_64 => {
5782 const plt_ni = elf.shndx.plt.get(elf).ni;
5882 const plt_ni = elf.shndx.plt.node(elf);
57835883 const got_plt_sym: Symbol.Id = .local(elf.shndx.got_plt.get(elf).lsi);
57845884 @memcpy(plt_ni.slice(&elf.mf)[0..16], &[16]u8{
57855885 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // push 0x0(%rip)
......@@ -5804,7 +5904,7 @@ fn initHeaders(
58045904 );
58055905 },
58065906 .LOONGARCH => {
5807 const plt_ni = elf.shndx.plt.get(elf).ni;
5907 const plt_ni = elf.shndx.plt.node(elf);
58085908 const got_plt_sym: Symbol.Id = .local(elf.shndx.got_plt.get(elf).lsi);
58095909 @memcpy(plt_ni.slice(&elf.mf)[0..32], switch (class) {
58105910 .NONE, _ => unreachable,
......@@ -5881,7 +5981,7 @@ fn initHeaders(
58815981 .manual_size = true,
58825982 });
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);
58855985 elf.eh_frame_hdr_first_symbol_reloc =
58865986 @fromBackingInt(@intCast(elf.symbol_relocs.items.len));
58875987 try elf.dwarf.genEhFrameHdr(
......@@ -5890,7 +5990,7 @@ fn initHeaders(
58905990 Symbol.Id.local(elf.shndx.eh_frame.get(elf).lsi).toTypeErased(),
58915991 );
58925992 _ = 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, .{
58945994 .size = addr_align.forward(4),
58955995 .alignment = addr_align,
58965996 }),
......@@ -5937,7 +6037,7 @@ fn initHeaders(
59376037
59386038 // Despite the name, `__dso_handle` is necessary even in static binaries.
59396039 _ = elf.addGlobalSymbol(.{
5940 .node = .wrap(Section.Index.text.get(elf).ni),
6040 .node = .wrap(Section.Index.text.node(elf)),
59416041 .name = "__dso_handle",
59426042 .value = Section.Index.text.vaddr(elf),
59436043 .size = 0,
......@@ -5952,7 +6052,7 @@ fn initHeaders(
59526052 else => |e| return e,
59536053 };
59546054 _ = elf.addGlobalSymbol(.{
5955 .node = .wrap(elf.shndx.plt.get(elf).ni),
6055 .node = .wrap(elf.shndx.plt.node(elf)),
59566056 .name = "_PROCEDURE_LINKAGE_TABLE_",
59576057 .value = elf.shndx.plt.vaddr(elf),
59586058 .size = 0,
......@@ -5967,7 +6067,7 @@ fn initHeaders(
59676067 else => |e| return e,
59686068 };
59696069 _ = elf.addGlobalSymbol(.{
5970 .node = .wrap(elf.shndx.got.get(elf).ni),
6070 .node = .wrap(elf.shndx.got.node(elf)),
59716071 .name = "_GLOBAL_OFFSET_TABLE_",
59726072 .value = switch (machine) {
59736073 .AARCH64,
......@@ -6085,7 +6185,7 @@ fn initHeaders(
60856185 };
60866186 if (have_dynamic) {
60876187 _ = elf.addGlobalSymbol(.{
6088 .node = .wrap(elf.shndx.dynamic.get(elf).ni),
6188 .node = .wrap(elf.shndx.dynamic.node(elf)),
60896189 .name = "_DYNAMIC",
60906190 .value = elf.shndx.dynamic.vaddr(elf),
60916191 .size = 0,
......@@ -6112,11 +6212,19 @@ fn initHeaders(
61126212 .manual_size = true,
61136213 });
61146214 }
6115 if (elf.ni.tls.unwrap()) |tls_segment_ni| elf.shndx.tdata = try elf.addSection(tls_segment_ni, .{
6116 .name = ".tdata",
6117 .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true },
6118 .node_align = node_block_align,
6119 });
6215 if (elf.ni.tls.unwrap()) |tls_segment_ni| {
6216 elf.shndx.tdata = try elf.addSection(tls_segment_ni, .{
6217 .name = ".tdata",
6218 .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true },
6219 .node_align = node_block_align,
6220 });
6221
6222 elf.shndx.tbss = try elf.addSection(tls_segment_ni, .{
6223 .name = ".tbss",
6224 .type = .NOBITS,
6225 .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true },
6226 });
6227 }
61206228 switch (comp.config.debug_format) {
61216229 .strip => {},
61226230 .dwarf => {
......@@ -6323,6 +6431,15 @@ fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
63236431 => elf.computeNodeVAddr(ni),
63246432 };
63256433}
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
63266443fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
63276444 const parent_ni = ni.parent(&elf.mf).unwrap().?;
63286445 const parent_vaddr = parent_vaddr: switch (elf.getNode(parent_ni)) {
......@@ -6868,7 +6985,7 @@ const SymPtr = union(std.elf.CLASS) {
68686985 @"64": *std.elf.Elf64.Sym,
68696986};
68706987fn 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);
68726989 switch (elf.shdrPtr(.symtab)) {
68736990 inline else => |shdr, class| {
68746991 const size = elf.targetLoad(&shdr.size);
......@@ -6878,7 +6995,7 @@ fn symPtr(elf: *Elf, index: Symbol.Index) SymPtr {
68786995 }
68796996}
68806997fn 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);
68826999 switch (elf.shdrPtr(elf.shndx.dynsym)) {
68837000 inline else => |shdr, class| {
68847001 const size = elf.targetLoad(&shdr.size);
......@@ -6889,7 +7006,7 @@ fn dynsymPtr(elf: *Elf, index: u32) SymPtr {
68897006}
68907007
68917008fn 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);
68937010 const size = elf.shndx.gnu_version.size(elf);
68947011 return @ptrCast(@alignCast(raw_slice[0..@intCast(size)]));
68957012}
......@@ -6903,7 +7020,7 @@ const VerdefEntry = extern struct {
69037020 aux: std.elf.Verdaux,
69047021};
69057022fn 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);
69077024 const size = elf.shndx.gnu_version_d.size(elf);
69087025 return @ptrCast(@alignCast(raw_slice[0..@intCast(size)]));
69097026}
......@@ -6916,7 +7033,7 @@ const VerneedEntry = extern union {
69167033 }
69177034};
69187035fn 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);
69207037 const size = elf.shndx.gnu_version_r.size(elf);
69217038 return @ptrCast(@alignCast(raw_slice[0..@intCast(size)]));
69227039}
......@@ -6935,12 +7052,18 @@ fn mapInputSection(elf: *Elf, opts: struct {
69357052 name: []const u8,
69367053 flags: std.elf.SHF,
69377054 entsize: std.elf.Xword,
7055 /// Must be one of:
7056 /// * `.PROGBITS`
7057 /// * `.NOBITS`
7058 /// * `.X86_64_UNWIND`
7059 type: std.elf.SHT,
69387060}) (Error || error{
69397061 UnsupportedSectionFlags,
69407062 TlsSectionUnavailable,
69417063 StripSection,
69427064 SectionFlagsConflict,
69437065 SectionTypeConflict,
7066 UnsupportedNobitsSection,
69447067})!Section.Index {
69457068 const gpa = elf.base.comp.gpa;
69467069 if (opts.flags.INFO_LINK or
......@@ -6972,12 +7095,10 @@ fn mapInputSection(elf: *Elf, opts: struct {
69727095 if (std.mem.startsWith(u8, opts.name, ".data.")) break :name ".data";
69737096 if (std.mem.startsWith(u8, opts.name, ".tdata.")) break :name ".tdata";
69747097 if (std.mem.startsWith(u8, opts.name, ".gcc_except_table.")) break :name ".gcc_except_table";
6975 // TODO: actually generate a bss section!
6976 if (std.mem.eql(u8, opts.name, ".bss")) break :name ".data";
6977 if (std.mem.startsWith(u8, opts.name, ".bss.")) break :name ".data";
6978 // TODO: actually generate a tbss section!
6979 if (std.mem.eql(u8, opts.name, ".tbss")) break :name ".tdata";
6980 if (std.mem.startsWith(u8, opts.name, ".tbss.")) break :name ".tdata";
7098 if (std.mem.eql(u8, opts.name, ".bss")) break :name ".bss";
7099 if (std.mem.startsWith(u8, opts.name, ".bss.")) break :name ".bss";
7100 if (std.mem.eql(u8, opts.name, ".tbss")) break :name ".tbss";
7101 if (std.mem.startsWith(u8, opts.name, ".tbss.")) break :name ".tbss";
69817102 break :name opts.name;
69827103 },
69837104 };
......@@ -6998,7 +7119,12 @@ fn mapInputSection(elf: *Elf, opts: struct {
69987119 assert(gop.index == elf.shdrs.items.len);
69997120 return elf.addSection(parent_node, .{
70007121 .name = name,
7001 .type = .NULL, // because initial size is 0
7122 .type = switch (opts.type) {
7123 .PROGBITS => .NULL, // size is 0
7124 .X86_64_UNWIND => .X86_64_UNWIND,
7125 .NOBITS => if (elf.ehdrType() == .REL) .NOBITS else return error.UnsupportedNobitsSection,
7126 else => unreachable,
7127 },
70027128 .flags = flags: {
70037129 // We need to decompress the section for linking.
70047130 var flags = opts.flags;
......@@ -7019,9 +7145,20 @@ fn mapInputSection(elf: *Elf, opts: struct {
70197145 return error.SectionFlagsConflict;
70207146 }
70217147
7022 switch (elf.targetLoad(&shdr.type)) {
7023 .NULL, .PROGBITS, .X86_64_UNWIND => {},
7024 else => return error.SectionTypeConflict,
7148 const existing_type = elf.targetLoad(&shdr.type);
7149
7150 switch (opts.type) {
7151 .PROGBITS, .X86_64_UNWIND => switch (existing_type) {
7152 .NULL, .PROGBITS, .X86_64_UNWIND => {},
7153 else => return error.SectionTypeConflict,
7154 },
7155
7156 .NOBITS => switch (existing_type) {
7157 .NOBITS => {},
7158 else => return error.SectionTypeConflict,
7159 },
7160
7161 else => unreachable,
70257162 }
70267163
70277164 // All okay, combine the section flags
......@@ -7060,6 +7197,7 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node
70607197 nav.resolved.?.@"threadlocal",
70617198 },
70627199 .entsize = 0,
7200 .type = .PROGBITS,
70637201 })) |shndx| {
70647202 break :section shndx;
70657203 } else |err| switch (err) {
......@@ -7069,6 +7207,7 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node
70697207 error.UnsupportedSectionFlags,
70707208 error.SectionTypeConflict,
70717209 error.SectionFlagsConflict,
7210 error.UnsupportedNobitsSection,
70727211 => {}, // fall back to default behavior below
70737212
70747213 }
......@@ -7101,7 +7240,7 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node
71017240 },
71027241 };
71037242 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, .{
71057244 .alignment = alignment,
71067245 }), .{ .nav = nmi });
71077246 nav_gop.value_ptr.* = .{
......@@ -7143,7 +7282,7 @@ fn uavMapIndex(
71437282 if (!uav_gop.found_existing) {
71447283 const shndx: Section.Index = .data_rel_ro; // TODO: it would be better to use `.rodata` if the UAV value doesn't have relocs
71457284 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, .{
71477286 .moved = true, // see assert at end of `genUav`
71487287 .alignment = resolved_align,
71497288 }), .{ .uav = umi });
......@@ -7440,6 +7579,9 @@ fn loadObject(
74407579 .type = .FILE,
74417580 .shndx = .ABS,
74427581 }) };
7582
7583 var input_has_bss = false;
7584 var input_has_tbss = false;
74437585 const target_endian = elf.targetEndian();
74447586 switch (elf.identClass()) {
74457587 .NONE, _ => unreachable,
......@@ -7454,13 +7596,25 @@ fn loadObject(
74547596 return diags.failParse(path, "bad section header location", .{});
74557597 if (ehdr.shentsize < @sizeOf(ElfN.Shdr))
74567598 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
74587612 defer gpa.free(sections);
74597613 try fr.seekTo(fl.offset + ehdr.shoff);
74607614 for (sections) |*section| {
74617615 section.* = .{
74627616 .shdr = try r.peekStruct(ElfN.Shdr, target_endian),
7463 .isi = null,
7617 .placement = .none,
74647618 };
74657619 try r.discardAll(ehdr.shentsize);
74667620 switch (section.shdr.type) {
......@@ -7487,24 +7641,30 @@ fn loadObject(
74877641 if (section.shdr.name >= shstrtab.len) continue;
74887642 const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0);
74897643 if (!comp.config.any_unwind_tables and std.mem.eql(u8, name, ".eh_frame")) continue;
7644 const sect_type = section.shdr.type;
74907645 const opts: struct {
74917646 shndx: Section.Index,
74927647 node_fixed: bool,
7493 } = switch (section.shdr.type) {
7648 } = switch (sect_type) {
74947649 else => continue,
74957650 .PROGBITS, .NOBITS, .X86_64_UNWIND => opts: {
74967651 const shndx = elf.mapInputSection(.{
74977652 .name = name,
74987653 .flags = section.shdr.flags.shf,
74997654 .entsize = section.shdr.entsize,
7655 .type = section.shdr.type,
75007656 }) catch |err| switch (err) {
75017657 else => |e| return e,
75027658 error.StripSection => continue,
7503 error.TlsSectionUnavailable => return diags.failParse(
7504 path,
7505 "thread-local storage section '{s}' is incompatible with '-fsingle-threaded'",
7506 .{name},
7507 ),
7659 error.TlsSectionUnavailable => {
7660 if (section.shdr.size == 0) continue;
7661
7662 return diags.failParse(
7663 path,
7664 "thread-local storage section '{s}' is incompatible with '-fsingle-threaded'",
7665 .{name},
7666 );
7667 },
75087668 error.UnsupportedSectionFlags => if (!section.shdr.flags.shf.ALLOC) {
75097669 // It probably doesn't matter, just skip this section.
75107670 continue;
......@@ -7529,6 +7689,11 @@ fn loadObject(
75297689 "flags of section '{s}' conflict with other inputs",
75307690 .{name},
75317691 ),
7692 error.UnsupportedNobitsSection => return diags.failParse(
7693 path,
7694 "unsupported section type SHT_NOBITS for non-bss section '{s}'",
7695 .{name},
7696 ),
75327697 };
75337698 if (section.shdr.flags.shf.COMPRESSED) {
75347699 // SHF_COMPRESSED is only allowed on non-alloc sections.
......@@ -7595,7 +7760,35 @@ fn loadObject(
75957760 const need_align: Alignment = .fromByteUnits(
75967761 std.math.ceilPowerOfTwoAssert(usize, @intCast(@max(section.shdr.addralign, 1))),
75977762 );
7763
75987764 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
75997792 const add_node_opts: MappedFile.Node.AddOptions = .{
76007793 .size = need_align.forward(section.shdr.size),
76017794 .alignment = need_align,
......@@ -7603,7 +7796,7 @@ fn loadObject(
76037796 };
76047797 const ni = elf.addNodeAssumeCapacity(
76057798 if (opts.node_fixed) ni: {
7606 const shndx_ni = opts.shndx.get(elf).ni;
7799 const shndx_ni = opts.shndx.node(elf);
76077800 const after_oni: MappedFile.Node.Index.Optional = after: {
76087801 const last_ni = shndx_ni.last(&elf.mf).unwrap() orelse break :after .none;
76097802 break :after switch (last_ni.position(&elf.mf)) {
......@@ -7612,10 +7805,10 @@ fn loadObject(
76127805 };
76137806 };
76147807 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),
76167809 .{ .input_section = @fromBackingInt(@intCast(elf.input_sections.items.len)) },
76177810 );
7618 section.isi = @fromBackingInt(@intCast(elf.input_sections.items.len));
7811 section.placement = .{ .progbits = @fromBackingInt(@intCast(elf.input_sections.items.len)) };
76197812 elf.input_sections.addOneAssumeCapacity().* = .{
76207813 .input = input_index,
76217814 .file_location = .{
......@@ -7712,7 +7905,33 @@ fn loadObject(
77127905 },
77137906 };
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
77177936 switch (input_sym.info.bind) {
77187937 else => |bind| return diags.failParse(
......@@ -7722,20 +7941,20 @@ fn loadObject(
77227941 ),
77237942 .LOCAL => {
77247943 const lsi = try elf.addLocalSymbol(.{
7725 .node = .wrap(input_section_node),
7944 .node = symbol_oni,
77267945 .name = name,
7727 .value = input_sym.value,
7946 .value = symbol_value,
77287947 .size = input_sym.size,
77297948 .type = sym_type,
7730 .shndx = elf.getNodeShndx(input_section_node),
7949 .shndx = output_shndx,
77317950 });
77327951 si.* = .local(lsi);
77337952 },
77347953 .GLOBAL, .WEAK, .GNU_UNIQUE => |bind| {
77357954 si.* = .global(elf.addGlobalSymbol(.{
7736 .node = .wrap(input_section_node),
7955 .node = symbol_oni,
77377956 .name = name,
7738 .value = input_sym.value,
7957 .value = symbol_value,
77397958 .size = input_sym.size,
77407959 .type = sym_type,
77417960 .bind = switch (bind) {
......@@ -7744,7 +7963,7 @@ fn loadObject(
77447963 else => unreachable,
77457964 },
77467965 .visibility = input_sym.other.visibility,
7747 .shndx = elf.getNodeShndx(input_section_node),
7966 .shndx = output_shndx,
77487967 }) catch |err| switch (err) {
77497968 error.MultipleDefinitions => return diags.failParse(
77507969 path,
......@@ -7776,7 +7995,16 @@ fn loadObject(
77767995 return diags.failParse(path, "unsupported rel entsize", .{});
77777996
77787997 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
77808008 elf.resetNodeRelocs(loc_node);
77818009
77828010 const relnum = std.math.divExact(
......@@ -7843,6 +8071,16 @@ fn loadObject(
78438071 };
78448072 },
78458073 };
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 }
78468084 },
78478085 }
78488086}
......@@ -8327,7 +8565,7 @@ fn createInitFiniArraySection(
83278565 .version = null,
83288566 }).?;
83298567 try elf.setGlobalSymbolValue(start_gsi, .{
8330 .node = .wrap(shndx.get(elf).ni),
8568 .node = .wrap(shndx.node(elf)),
83318569 .value = shndx.vaddr(elf),
83328570 .size = 0,
83338571 .type = .NOTYPE,
......@@ -8335,7 +8573,7 @@ fn createInitFiniArraySection(
83358573 });
83368574 try elf.updateGlobalDynamic(start_gsi, true);
83378575 try elf.setGlobalSymbolValue(end_gsi, .{
8338 .node = .wrap(shndx.get(elf).ni),
8576 .node = .wrap(shndx.node(elf)),
83398577 .value = shndx.vaddr(elf),
83408578 .size = 0,
83418579 .type = .NOTYPE,
......@@ -8388,7 +8626,7 @@ fn prelinkInner(elf: *Elf) Error!void {
83888626 elf.shndx.debug_str_offsets,
83898627 }) |debug_shndx| {
83908628 if (debug_shndx == .UNDEF) continue;
8391 const debug_ni = debug_shndx.get(elf).ni;
8629 const debug_ni = debug_shndx.node(elf);
83928630 const frame_format = debug_shndx.debugFrameFormat(elf);
83938631 const unit_padding_ni = elf.addNodeAssumeCapacity(
83948632 try debug_ni.addHeaderChildAfter(gpa, &elf.mf, last_header_oni: {
......@@ -8444,7 +8682,7 @@ fn prelinkInner(elf: *Elf) Error!void {
84448682 .UNDEF => {},
84458683 else => |debug_addr_shndx| {
84468684 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, .{
84488686 .alignment = addr_align,
84498687 .next_moved = true,
84508688 .enable_next_moved = true,
......@@ -8465,7 +8703,7 @@ fn prelinkInner(elf: *Elf) Error!void {
84658703 switch (elf.shndx.debug_abbrev) {
84668704 .UNDEF => {},
84678705 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, .{}),
84698707 .{ .debug_shared = .debug_abbrev },
84708708 )),
84718709 }
......@@ -8473,14 +8711,14 @@ fn prelinkInner(elf: *Elf) Error!void {
84738711 .UNDEF => {},
84748712 else => |debug_line_str_shndx| elf.dwarf.debug_line_str.ni =
84758713 .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, .{}),
84778715 .{ .debug_shared = .debug_line_str },
84788716 )),
84798717 }
84808718 switch (elf.shndx.debug_str) {
84818719 .UNDEF => {},
84828720 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, .{}),
84848722 .{ .debug_shared = .debug_str },
84858723 )),
84868724 }
......@@ -8488,7 +8726,7 @@ fn prelinkInner(elf: *Elf) Error!void {
84888726 .UNDEF => {},
84898727 else => |debug_str_offsets_shndx| {
84908728 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, .{
84928730 .alignment = switch (elf.dwarf.format) {
84938731 .@"32" => .@"4",
84948732 .@"64" => .@"8",
......@@ -8549,7 +8787,7 @@ fn zcuFilesReadyInner(elf: *Elf, zcu: *Zcu) Error!void {
85498787 else => |debug_info_shndx| {
85508788 const debug_info_ni = unit.debug_info_ni.unwrap() orelse debug_info_ni: {
85518789 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, .{
85538791 .alignment = elf.mf.flags.block_size,
85548792 .enable_next_moved = true,
85558793 }),
......@@ -8576,7 +8814,7 @@ fn zcuFilesReadyInner(elf: *Elf, zcu: *Zcu) Error!void {
85768814 else => |debug_line_shndx| {
85778815 const debug_line_ni = unit.debug_line_ni.unwrap() orelse debug_line_ni: {
85788816 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, .{
85808818 .alignment = elf.mf.flags.block_size,
85818819 .enable_next_moved = true,
85828820 }),
......@@ -8600,7 +8838,7 @@ fn zcuFilesReadyInner(elf: *Elf, zcu: *Zcu) Error!void {
86008838 else => |debug_rnglists_shndx| {
86018839 const debug_rnglists_ni = unit.debug_rnglists_ni.unwrap() orelse debug_rnglists_ni: {
86028840 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, .{
86048842 .next_moved = true,
86058843 .enable_next_moved = true,
86068844 }),
......@@ -8680,7 +8918,7 @@ fn prepareDynamic(elf: *Elf) Error!void {
86808918
86818919 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);
86848922 switch (elf.shdrPtr(elf.shndx.dynamic)) {
86858923 inline else => |shdr| elf.targetStore(&shdr.size, @intCast(dynamic_size)),
86868924 }
......@@ -8702,7 +8940,7 @@ fn flushDynamic(elf: *Elf) void {
87028940 comp.config.pie);
87038941
87048942 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)];
87068944 const dynamic_entries: [][2]ElfN.Addr = @ptrCast(@alignCast(dynamic_slice));
87078945
87088946 var dynamic_index: usize = 0;
......@@ -8816,6 +9054,8 @@ fn flushDynamic(elf: *Elf) void {
88169054
88179055fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
88189056 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.
88199059 type: std.elf.SHT = .NULL,
88209060 flags: std.elf.SHF = .{},
88219061 size: std.elf.Xword = 0,
......@@ -8836,7 +9076,9 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
88369076 try elf.ensureSegmentAligned(phndx, opts.addralign);
88379077 }
88389078 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 }
88409082 try elf.shdrs.ensureUnusedCapacity(gpa, 1);
88419083 const want_symbol = opts.flags.ALLOC or switch (opts.type) {
88429084 .NULL, .PROGBITS, .NOBITS, .X86_64_UNWIND => elf.ehdrType() == .REL,
......@@ -8877,26 +9119,29 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
88779119 .EXEC, .DYN => segment_ni,
88789120 };
88799121 assert(opts.addralign.check(opts.size));
8880 const ni = elf.addNodeAssumeCapacity(try parent_ni.addFloatingChild(gpa, &elf.mf, .{
8881 .size = opts.node_align.forward(opts.size),
8882 .alignment = opts.addralign.max(opts.node_align),
8883 .resized = opts.size > 0,
8884 .bubbles_moved = opts.flags.ALLOC,
8885 }), switch (opts.manual_size) {
8886 false => .{ .section = shndx },
8887 true => .{ .section_manual_size = shndx },
8888 });
8889 const addr = elf.computeNodeVAddr(ni);
9122 const oni: MappedFile.Node.Index.Optional = switch (opts.type) {
9123 .NOBITS => .none,
9124 else => .wrap(elf.addNodeAssumeCapacity(
9125 try parent_ni.addFloatingChild(gpa, &elf.mf, .{
9126 .size = opts.node_align.forward(opts.size),
9127 .alignment = opts.addralign.max(opts.node_align),
9128 .resized = opts.size > 0,
9129 .bubbles_moved = opts.flags.ALLOC,
9130 }),
9131 if (opts.manual_size) .{ .section_manual_size = shndx } else .{ .section = shndx },
9132 )),
9133 };
9134 const addr = if (oni.unwrap()) |ni| elf.computeNodeVAddr(ni) else 0;
88909135 elf.shdrs.appendAssumeCapacity(.{
88919136 .lsi = if (want_symbol) try elf.addLocalSymbol(.{
8892 .node = ni.toOptional(),
9137 .node = oni,
88939138 .name = "",
88949139 .value = addr,
88959140 .size = 0,
88969141 .type = .SECTION,
88979142 .shndx = shndx,
88989143 }) else .null,
8899 .ni = ni,
9144 .ni = oni,
89009145 .rela = switch (opts.type) {
89019146 .REL => unreachable,
89029147 .RELA => .{ .free_head = .none },
......@@ -8910,7 +9155,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
89109155 .type = opts.type,
89119156 .flags = .{ .shf = opts.flags },
89129157 .addr = @intCast(addr),
8913 .offset = @intCast(elf.computeNodeElfOffset(ni)),
9158 .offset = if (oni.unwrap()) |ni| @intCast(elf.computeNodeElfOffset(ni)) else 0,
89149159 .size = @intCast(opts.size),
89159160 .link = opts.link,
89169161 .info = opts.info,
......@@ -8973,7 +9218,7 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize)
89739218 .NONE, _ => unreachable,
89749219 inline else => |ct_class| (elf.got.count() + new_got_entries) * @sizeOf(ct_class.ElfN().Addr),
89759220 };
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
89789223 if (elf.shndx.dynamic != .UNDEF) {
89799224 try elf.shndx.rela_dyn.relaEnsureAdditionalCapacity(elf, new_got_entries);
......@@ -9816,7 +10061,7 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {
981610061 const addr_size = @sizeOf(class.ElfN().Addr);
981710062 const offset = got_index * addr_size;
981810063 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],
982010065 ));
982110066 elf.targetStore(entry_ptr, switch (entry_value) {
982210067 .unsigned => |x| @intCast(x),
......@@ -10179,7 +10424,7 @@ fn updateFuncInner(
1017910424 const frame_ni = elf.addNodeAssumeCapacity(try switch (wip_func.frame_format) {
1018010425 .debug_frame => elf.shndx.debug_frame,
1018110426 .eh_frame => elf.shndx.eh_frame,
10182 }.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{
10427 }.node(elf).addFloatingChild(gpa, &elf.mf, .{
1018310428 .alignment = frame_align.max(elf.mf.flags.block_size),
1018410429 .enable_next_moved = true,
1018510430 }), .{ .unit_frame = wip_func.unit });
......@@ -10624,12 +10869,46 @@ pub fn idle(elf: *Elf) link.Error!bool {
1062410869 if (clean_moved or clean_resized or clean_next_moved) try elf.flushPadding(ni);
1062510870 break :task;
1062610871 }
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 }
1062710905 }
1062810906 if (elf.inputs.items.len - elf.input_pending_index > 0) return true;
1062910907 if (elf.input_sections.items.len - elf.input_section_pending_index > 0) return true;
1063010908 if (elf.one_shot_fixups.items.len > 0) return true;
1063110909 if (elf.changed_symtab_index.count() > 0) return true;
1063210910 if (elf.mf.updates.items.len > 0) return true;
10911 if (elf.bss_moved) return true;
1063310912 return false;
1063410913}
1063510914
......@@ -10984,8 +11263,23 @@ fn flushElfOffset(elf: *Elf, ni: MappedFile.Node.Index) void {
1098411263 inline else => |phdr, class| {
1098511264 const ph = &phdr[phndx];
1098611265 elf.targetStore(&ph.offset, @intCast(elf_offset));
10987 if (elf.targetLoad(&ph.type) == .PHDR) {
10988 @field(elf.ehdrPtr(), @tagName(class)).phoff = ph.offset;
11266 switch (elf.targetLoad(&ph.type)) {
11267 .PHDR => {
11268 const ehdr = @field(elf.ehdrPtr(), @tagName(class));
11269 elf.targetStore(&ehdr.phoff, @intCast(elf_offset));
11270 },
11271 .TLS => {
11272 // The `.tbss` section's offset should be at the end of the TLS segment.
11273 const tls_filesz = elf.targetLoad(&ph.filesz);
11274 const tbss_shdr = @field(elf.shdrPtr(elf.shndx.tbss), @tagName(class));
11275 elf.targetStore(&tbss_shdr.offset, @intCast(elf_offset + tls_filesz));
11276 },
11277 else => if (ni == elf.ni.data) {
11278 // The `.bss` section's offset should be at the end of the data segment.
11279 const data_filesz = elf.targetLoad(&ph.filesz);
11280 const bss_shdr = @field(elf.shdrPtr(elf.shndx.bss), @tagName(class));
11281 elf.targetStore(&bss_shdr.offset, @intCast(elf_offset + data_filesz));
11282 },
1098911283 }
1099011284 },
1099111285 }
......@@ -11027,7 +11321,6 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
1102711321 .DYNAMIC,
1102811322 .INTERP,
1102911323 .PHDR,
11030 .TLS,
1103111324 .GNU_EH_FRAME,
1103211325 .GNU_RELRO,
1103311326 => {
......@@ -11035,6 +11328,22 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
1103511328 elf.targetStore(&ph.vaddr, @intCast(new_vaddr));
1103611329 elf.targetStore(&ph.paddr, @intCast(new_vaddr));
1103711330 },
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 },
1103811347 }
1103911348 },
1104011349 }
......@@ -11365,6 +11674,89 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
1136511674 try ni.childrenMoved(elf.base.comp.gpa, &elf.mf);
1136611675}
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
1136811760/// Given the index of a `PT_LOAD`/`PT_NULL` segment, assumes that the phdr's `offset` and `filesz`
1136911761/// have been updated as needed by the caller, and updates the `@"align"`, `vaddr`, `paddr`, and
1137011762/// `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
1139311785 switch (elf.phdrSlice()) {
1139411786 inline else => |phdr| {
1139511787 const offset = elf.targetLoad(&phdr[orig_phndx].offset);
11396 const size = elf.targetLoad(&phdr[orig_phndx].filesz);
11397
11398 if (size == 0) {
11399 assert(elf.targetLoad(&phdr[orig_phndx].type) == .NULL);
11400 } else {
11401 assert(elf.targetLoad(&phdr[orig_phndx].type) == .LOAD);
11402 }
11403
11404 elf.targetStore(&phdr[orig_phndx].memsz, size);
11405 elf.targetStore(&phdr[orig_phndx].@"align", @intCast(ph_align.toByteUnits()));
11788 const filesz = elf.targetLoad(&phdr[orig_phndx].filesz);
1140611789
1140711790 const orig_vaddr = elf.targetLoad(&phdr[orig_phndx].vaddr);
1140811791 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
1141011799 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
1141211805 // First, we will shift the virtual address as needed in order to maintain the required
1141311806 // property that vaddr is congruent to offset modulo the phdr alignment.
1141411807 {
......@@ -11452,7 +11845,7 @@ fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Erro
1145211845 // the segment is already known to be moving---making it easier to grow in-place is
1145311846 // the whole point of the multiplier!
1145411847 {
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;
1145611849 if (vaddr + target_size <= next_page_vaddr) {
1145711850 break; // hooray, we fit here!
1145811851 }
......@@ -11474,17 +11867,13 @@ fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Erro
1147411867 else => {},
1147511868 };
1147611869
11477 const free_vaddr = vaddr + size * reserve_size_multiplier;
11870 const free_vaddr = vaddr + memsz * reserve_size_multiplier;
1147811871
1147911872 const next_align = page_align.max(next_ni.alignment(&elf.mf));
1148011873 const next_offset = elf.targetLoad(&next_ph.offset);
1148111874 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 we
11484 // will update the vaddr of `phndx` when we break from the loop.
11485 elf.targetStore(&next_ph.vaddr, @intCast(next_new_vaddr));
11486 elf.targetStore(&next_ph.paddr, @intCast(next_new_vaddr));
11487 try next_ni.childrenMoved(elf.base.comp.gpa, &elf.mf);
11876 try elf.updateSegmentLoadAddress(next_ni, next_new_vaddr);
1148811877
1148911878 break;
1149011879 },
......@@ -11507,9 +11896,7 @@ fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Erro
1150711896 }
1150811897
1150911898 if (vaddr != orig_vaddr) {
11510 elf.targetStore(&phdr[phndx].vaddr, @intCast(vaddr));
11511 elf.targetStore(&phdr[phndx].paddr, @intCast(vaddr));
11512 try segment_ni.childrenMoved(elf.base.comp.gpa, &elf.mf);
11899 try elf.updateSegmentLoadAddress(segment_ni, vaddr);
1151311900 }
1151411901 },
1151511902 }
......@@ -11539,21 +11926,50 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo
1153911926 .ehdr => unreachable,
1154011927 .shdr => {},
1154111928 .segment => |phndx| switch (elf.phdrSlice()) {
11542 inline else => |phdr| {
11929 inline else => |phdr, class| {
1154311930 assert(elf.phdrs.items[phndx].unwrap().? == ni);
1154411931 const ph = &phdr[phndx];
11545 elf.targetStore(&ph.filesz, @intCast(size));
1154611932 switch (elf.targetLoad(&ph.type)) {
1154711933 else => unreachable,
1154811934 .NULL, .LOAD => {
11549 elf.targetStore(&ph.type, if (size > 0) .LOAD else .NULL);
11935 elf.targetStore(&ph.filesz, @intCast(size));
1155011936 try elf.allocateSegmentLoadAddress(phndx);
11937 if (ni == elf.ni.data) elf.bss_moved = true;
1155111938 },
1155211939 .DYNAMIC, .INTERP, .PHDR, .GNU_EH_FRAME, .GNU_RELRO => {
11940 elf.targetStore(&ph.filesz, @intCast(size));
1155311941 elf.targetStore(&ph.memsz, @intCast(size));
1155411942 },
1155511943 .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
1155711973 // TPOFF relocations care about the size of the TLS segment. Re-apply
1155811974 // those, and also update any GOT entries from GOTTPOFF relocations.
1155911975 for (elf.tls_size_symbol_relocs.keys()) |reloc| {
......@@ -11904,17 +12320,17 @@ fn ensurePltEntry(elf: *Elf, gsi: Symbol.Global.Index) Error!bool {
1190412320 const gpa = elf.base.comp.gpa;
1190512321 try elf.shndx.rela_plt.relaEnsureAdditionalCapacity(elf, 1);
1190612322 try elf.plt.ensureUnusedCapacity(gpa, 1);
11907 try elf.shndx.plt.get(elf).ni.ensureMinimumSize(
12323 try elf.shndx.plt.node(elf).ensureMinimumSize(
1190812324 gpa,
1190912325 &elf.mf,
1191012326 plt.entry_size * (plt.header_entries + elf.plt.count() + 1),
1191112327 );
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(
1191312329 gpa,
1191412330 &elf.mf,
1191512331 elf.targetPtrSize() * (got_plt.header_entries + elf.plt.count() + 1),
1191612332 );
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(
1191812334 gpa,
1191912335 &elf.mf,
1192012336 plt_sec.entry_size * (elf.plt.count() + 1),
......@@ -11962,7 +12378,7 @@ fn ensurePltEntry(elf: *Elf, gsi: Symbol.Global.Index) Error!bool {
1196212378 switch (elf.ehdrMachine()) {
1196312379 .AARCH64, .PPC64, .RISCV => |machine| @panic(@tagName(machine)),
1196412380 .X86_64 => {
11965 const plt_ni = elf.shndx.plt.get(elf).ni;
12381 const plt_ni = elf.shndx.plt.node(elf);
1196612382 const plt_addr = plt_addr: switch (elf.shdrPtr(elf.shndx.plt)) {
1196712383 inline else => |shdr| {
1196812384 const old_size = 16 * (1 + plt_index);
......@@ -11986,7 +12402,7 @@ fn ensurePltEntry(elf: *Elf, gsi: Symbol.Global.Index) Error!bool {
1198612402 },
1198712403 };
1198812404
11989 const got_plt_ni = elf.shndx.got_plt.get(elf).ni;
12405 const got_plt_ni = elf.shndx.got_plt.node(elf);
1199012406 switch (elf.shdrPtr(elf.shndx.got_plt)) {
1199112407 inline else => |shdr, class| {
1199212408 assert(elf.targetLoad(&shdr.size) == got_plt_offset);
......@@ -12000,7 +12416,7 @@ fn ensurePltEntry(elf: *Elf, gsi: Symbol.Global.Index) Error!bool {
1200012416 },
1200112417 }
1200212418
12003 const plt_sec_ni = elf.shndx.plt_sec.get(elf).ni;
12419 const plt_sec_ni = elf.shndx.plt_sec.node(elf);
1200412420 switch (elf.shdrPtr(elf.shndx.plt_sec)) {
1200512421 inline else => |shdr| {
1200612422 const old_size = 16 * plt_index;
......@@ -12024,7 +12440,7 @@ fn ensurePltEntry(elf: *Elf, gsi: Symbol.Global.Index) Error!bool {
1202412440 },
1202512441 .LOONGARCH => {
1202612442 // 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);
1202812444 const plt_addr, const plt_slice = plt_entry: switch (elf.shdrPtr(elf.shndx.plt)) {
1202912445 inline else => |shdr| {
1203012446 const old_size = 16 * (1 + plt_index);
......@@ -12048,7 +12464,7 @@ fn ensurePltEntry(elf: *Elf, gsi: Symbol.Global.Index) Error!bool {
1204812464 };
1204912465
1205012466 // 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);
1205212468 switch (elf.shdrPtr(elf.shndx.got_plt)) {
1205312469 inline else => |shdr, class| {
1205412470 assert(elf.targetLoad(&shdr.size) == got_plt_offset);
......@@ -12080,7 +12496,7 @@ fn ensurePltEntry(elf: *Elf, gsi: Symbol.Global.Index) Error!bool {
1208012496 },
1208112497 .SPARCV9 => {
1208212498 // 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);
1208412500 switch (elf.shdrPtr(elf.shndx.plt)) {
1208512501 inline else => |shdr| {
1208612502 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
1213712553 // We also need to update all of the references from `.plt.sec` to `.got.plt`.
1213812554 // However, if there's also a flush pending for `.got.plt`, don't bother doing
1213912555 // 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)) {
1214112557 return;
1214212558 }
1214312559 // Exit this `switch` to update those references.
......@@ -12152,7 +12568,7 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad
1215212568 // We also need to update all of the references from `.plt.sec` to `.got.plt`.
1215312569 // However, if there's also a flush pending for `.plt.sec`, don't bother doing
1215412570 // 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)) {
1215612572 return;
1215712573 }
1215812574 // Exit this `switch` to update those references.
......@@ -12161,7 +12577,7 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad
1216112577 // We are updating the references from `.plt.sec` to `.got.plt`.
1216212578 const got_plt_addr = elf.shndx.got_plt.vaddr(elf);
1216312579 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);
1216512581 switch (elf.identClass()) {
1216612582 .NONE, _ => unreachable,
1216712583 inline else => |class| {
......@@ -12194,7 +12610,7 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad
1219412610 // We also need to update all of the references from `.plt` to `.got.plt`.
1219512611 // However, if there's also a flush pending for `.got.plt`, don't bother doing
1219612612 // 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)) {
1219812614 return;
1219912615 }
1220012616 // Exit this `switch` to update those references.
......@@ -12210,7 +12626,7 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad
1221012626 // We also need to update all of the references from `.plt` to `.got.plt`.
1221112627 // However, if there's also a flush pending for `.plt`, don't bother doing
1221212628 // 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)) {
1221412630 return;
1221512631 }
1221612632 // Exit this `switch` to update those references.
......@@ -12219,7 +12635,7 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad
1221912635 // We are updating the references from `.plt` to `.got.plt`.
1222012636 const got_plt_addr = elf.shndx.got_plt.vaddr(elf);
1222112637 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);
1222312639 switch (elf.identClass()) {
1222412640 .NONE, _ => unreachable,
1222512641 inline else => |class| {
......@@ -12657,7 +13073,7 @@ const VerdefAdapter = struct {
1265713073fn verdefId(elf: *Elf, version: String(.dynstr)) Error!u15 {
1265813074 const gpa = elf.base.comp.gpa;
1265913075 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));
1266113077 const gop = try elf.verdef.getOrPutAdapted(gpa, version, adapter);
1266213078
1266313079 if (gop.found_existing) {
......@@ -12766,7 +13182,7 @@ const VerneedAdapter = struct {
1276613182fn verneedId(elf: *Elf, file: String(.dynstr), version: String(.dynstr)) Error!u15 {
1276713183 const gpa = elf.base.comp.gpa;
1276813184 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
1277113187 if (elf.verneed.getIndexAdapted(@as(VerneedAdapter.Key, .{
1277213188 .file = file,