authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-05-20 12:49:54+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-05-26 06:30:28+01:00
logf801995be40bbf10268c0fa7c13f255cd36b14c0
tree26b0714ba739c2c7437a05263f5731da2442cabe
parent2ec50b7e3d54a55860986110e096b784ed15827f
signaturelock-open Commit is signed but in an unrecognized format.

Elf2: basic support for INIT_ARRAY/FINI_ARRAY/PREINIT_ARRAY


1 files changed, 284 insertions(+), 46 deletions(-)

src/link/Elf2.zig+284-46
...@@ -34,6 +34,10 @@ shndx: struct {...@@ -34,6 +34,10 @@ shndx: struct {
34 dynstr: Section.Index,34 dynstr: Section.Index,
35 dynamic: Section.Index,35 dynamic: Section.Index,
36 tdata: Section.Index,36 tdata: Section.Index,
37 // These sections are created only as needed, and are initially `.UNDEF`.
38 init_array: Section.Index,
39 fini_array: Section.Index,
40 preinit_array: Section.Index,
37},41},
38symtab: std.ArrayList(Symbol),42symtab: std.ArrayList(Symbol),
39globals: struct {43globals: struct {
...@@ -1113,7 +1117,7 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void...@@ -1113,7 +1117,7 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void
1113const Symbol = struct {1117const Symbol = struct {
1114 /// The node which this symbol's value is defined relative to. Possible values are:1118 /// The node which this symbol's value is defined relative to. Possible values are:
1115 /// * `.none` for a SHN_ABS or SHN_UNDEF symbol1119 /// * `.none` for a SHN_ABS or SHN_UNDEF symbol
1116 /// * A section (the symbol's value is that section's vaddr)1120 /// * A section (the symbol's value is some vaddr in that section)
1117 /// * An input section (the symbol's value is some vaddr in that input section)1121 /// * An input section (the symbol's value is some vaddr in that input section)
1118 /// * A NAV, UAV, or lazy code/data (the symbol's value is exactly the vaddr of that node)1122 /// * A NAV, UAV, or lazy code/data (the symbol's value is exactly the vaddr of that node)
1119 node: MappedFile.Node.Index,1123 node: MappedFile.Node.Index,
...@@ -1918,6 +1922,9 @@ fn create(...@@ -1918,6 +1922,9 @@ fn create(
1918 .dynstr = .UNDEF,1922 .dynstr = .UNDEF,
1919 .dynamic = .UNDEF,1923 .dynamic = .UNDEF,
1920 .tdata = .UNDEF,1924 .tdata = .UNDEF,
1925 .init_array = .UNDEF,
1926 .fini_array = .UNDEF,
1927 .preinit_array = .UNDEF,
1921 },1928 },
1922 .symtab = .empty,1929 .symtab = .empty,
1923 .globals = .{1930 .globals = .{
...@@ -3109,47 +3116,100 @@ fn loadObject(...@@ -3109,47 +3116,100 @@ fn loadObject(
3109 defer gpa.free(shstrtab);3116 defer gpa.free(shstrtab);
3110 try elf.nodes.ensureUnusedCapacity(gpa, ehdr.shnum - 1);3117 try elf.nodes.ensureUnusedCapacity(gpa, ehdr.shnum - 1);
3111 try elf.input_sections.ensureUnusedCapacity(gpa, ehdr.shnum - 1);3118 try elf.input_sections.ensureUnusedCapacity(gpa, ehdr.shnum - 1);
3112 for (sections[1..]) |*section| switch (section.shdr.type) {3119 for (sections[1..]) |*section| {
3113 else => {},3120 if (section.shdr.name >= shstrtab.len) continue;
3114 .PROGBITS, .NOBITS => {3121 const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0);
3115 if (section.shdr.name >= shstrtab.len) continue;3122 const opts: struct {
3116 const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0);3123 shndx: Section.Index,
3117 const shndx: Section.Index = elf.namedSection(name) orelse shndx: {3124 has_file_bits: bool,
3118 // TODO: actually generate a .bss section. For now, just throw it into `.data`.3125 node_fixed: bool,
3119 if (std.mem.eql(u8, name, ".bss") or3126 } = switch (section.shdr.type) {
3120 std.mem.startsWith(u8, name, ".bss.")) break :shndx .data;3127 else => continue,
3121 if (std.mem.eql(u8, name, ".tbss") or3128 .PROGBITS => .{
3122 std.mem.startsWith(u8, name, ".tbss.")) break :shndx elf.shndx.tdata;3129 .shndx = elf.namedSection(name) orelse continue,
3123 break :shndx .UNDEF;3130 .has_file_bits = true,
3124 };3131 .node_fixed = false,
3125 if (shndx == .UNDEF) continue;3132 },
3126 const ni = try elf.mf.addLastChildNode(gpa, shndx.get(elf).ni, .{3133 .NOBITS => .{
3127 .size = section.shdr.size,3134 .shndx = shndx: {
3128 .alignment = .fromByteUnits(std.math.ceilPowerOfTwoAssert(3135 // TODO: actually generate a .bss section. For now, just throw it into `.data`.
3129 usize,3136 if (std.mem.eql(u8, name, ".bss") or std.mem.startsWith(u8, name, ".bss.")) {
3130 @intCast(@max(section.shdr.addralign, 1)),3137 break :shndx .data;
3131 )),3138 }
3132 .moved = true, // see assert at end of `flushInputSection`3139 if (elf.shndx.tdata != .UNDEF and
3133 });3140 (std.mem.eql(u8, name, ".tbss") or std.mem.startsWith(u8, name, ".tbss.")))
3134 elf.nodes.appendAssumeCapacity(.{3141 {
3135 .input_section = @enumFromInt(elf.input_sections.items.len),3142 break :shndx elf.shndx.tdata;
3136 });3143 }
3137 section.isi = @enumFromInt(elf.input_sections.items.len);3144 continue;
3138 elf.input_sections.addOneAssumeCapacity().* = .{
3139 .input = input_index,
3140 .file_location = .{
3141 .offset = fl.offset + section.shdr.offset,
3142 .size = if (section.shdr.type == .NOBITS) 0 else section.shdr.size,
3143 },3145 },
3144 // The section vaddr is initially 0, because the symbol addresses are3146 .has_file_bits = false,
3145 // zero-based. This will eventually be updated by `flushMoved`.3147 .node_fixed = false,
3146 .vaddr = 0,3148 },
3147 .node = ni,3149 inline .INIT_ARRAY, .FINI_ARRAY, .PREINIT_ARRAY => |@"type"| .{
3148 .first_reloc = .none,3150 .shndx = shndx: {
3149 };3151 // TODO: the input section name may include a "priority" value between 1
3150 elf.synth_prog_node.increaseEstimatedTotalItems(1);3152 // and 65535 which should affect the order we assemble input sections in
3151 },3153 const init_fini_section_name: []const u8 = switch (@"type") {
3152 };3154 .INIT_ARRAY => "init_array",
3155 .FINI_ARRAY => "fini_array",
3156 .PREINIT_ARRAY => "preinit_array",
3157 else => comptime unreachable,
3158 };
3159 const shndx: *Section.Index = &@field(elf.shndx, init_fini_section_name);
3160 const need_addralign: u8 = switch (class) {
3161 .NONE, _ => unreachable,
3162 .@"32" => 4,
3163 .@"64" => 8,
3164 };
3165 if (section.shdr.addralign != need_addralign) {
3166 return diags.failParse(path, "bad addralign on {t} shdr", .{@"type"});
3167 }
3168 if (shndx.* == .UNDEF) {
3169 try elf.createInitFiniArraySection(shndx, init_fini_section_name, @"type");
3170 }
3171 switch (elf.shdrPtr(shndx.*)) {
3172 inline else => |shdr| {
3173 const old_size = elf.targetLoad(&shdr.size);
3174 elf.targetStore(&shdr.size, @intCast(old_size + section.shdr.size));
3175 },
3176 }
3177 try shndx.get(elf).ni.resized(gpa, &elf.mf);
3178 break :shndx shndx.*;
3179 },
3180 .has_file_bits = true,
3181 // This node must be fixed to prevent padding from being added between different
3182 // INIT_ARRAY/FINI_ARRAY/PREINIT_ARRAY input sections.
3183 .node_fixed = true,
3184 },
3185 };
3186 const ni = try elf.mf.addLastChildNode(gpa, opts.shndx.get(elf).ni, .{
3187 .size = section.shdr.size,
3188 .alignment = .fromByteUnits(std.math.ceilPowerOfTwoAssert(
3189 usize,
3190 @intCast(@max(section.shdr.addralign, 1)),
3191 )),
3192 .moved = true, // see assert at end of `flushInputSection`
3193 .fixed = opts.node_fixed,
3194 });
3195 elf.nodes.appendAssumeCapacity(.{
3196 .input_section = @enumFromInt(elf.input_sections.items.len),
3197 });
3198 section.isi = @enumFromInt(elf.input_sections.items.len);
3199 elf.input_sections.addOneAssumeCapacity().* = .{
3200 .input = input_index,
3201 .file_location = .{
3202 .offset = fl.offset + section.shdr.offset,
3203 .size = if (opts.has_file_bits) section.shdr.size else 0,
3204 },
3205 // The section vaddr is initially 0, because the symbol addresses are
3206 // zero-based. This will eventually be updated by `flushMoved`.
3207 .vaddr = 0,
3208 .node = ni,
3209 .first_reloc = .none,
3210 };
3211 elf.synth_prog_node.increaseEstimatedTotalItems(1);
3212 }
3153 var symmap: std.ArrayList(Symbol.Id) = .empty;3213 var symmap: std.ArrayList(Symbol.Id) = .empty;
3154 defer symmap.deinit(gpa);3214 defer symmap.deinit(gpa);
3155 for (sections[1..], 1..) |*symtab, symtab_shndx| switch (symtab.shdr.type) {3215 for (sections[1..], 1..) |*symtab, symtab_shndx| switch (symtab.shdr.type) {
...@@ -3450,6 +3510,57 @@ fn checkInputIdent(...@@ -3450,6 +3510,57 @@ fn checkInputIdent(
3450 );3510 );
3451}3511}
34523512
3513fn createInitFiniArraySection(
3514 elf: *Elf,
3515 shndx: *Section.Index,
3516 comptime name: []const u8,
3517 @"type": std.elf.SHT,
3518) !void {
3519 assert(shndx.* == .UNDEF);
3520 const addr_align: std.mem.Alignment = switch (elf.identClass()) {
3521 .NONE, _ => unreachable,
3522 .@"32" => .@"4",
3523 .@"64" => .@"8",
3524 };
3525 shndx.* = try elf.addSection(elf.ni.data_rel_ro, .{
3526 .name = "." ++ name,
3527 .type = @"type",
3528 .flags = .{ .WRITE = true, .ALLOC = true },
3529 .node_align = addr_align,
3530 });
3531 try elf.ensureUnusedSymbolCapacity(2, .maybe_global);
3532 _ = elf.addGlobalSymbolAssumeCapacity(.{
3533 .node = shndx.get(elf).ni,
3534 .name = try .string(elf, "__" ++ name ++ "_start"),
3535 .value = shndx.vaddr(elf),
3536 .size = 0,
3537 .type = .NOTYPE,
3538 .bind = .strong,
3539 .visibility = .HIDDEN,
3540 .shndx = shndx.*,
3541 }) catch |err| switch (err) {
3542 error.MultipleDefinitions => return elf.base.comp.link_diags.fail(
3543 "multiple definitions of '{s}'",
3544 .{"__" ++ name ++ "_start"},
3545 ),
3546 };
3547 _ = elf.addGlobalSymbolAssumeCapacity(.{
3548 .node = shndx.get(elf).ni,
3549 .name = try .string(elf, "__" ++ name ++ "_end"),
3550 .value = shndx.vaddr(elf),
3551 .size = 0,
3552 .type = .NOTYPE,
3553 .bind = .strong,
3554 .visibility = .HIDDEN,
3555 .shndx = shndx.*,
3556 }) catch |err| switch (err) {
3557 error.MultipleDefinitions => return elf.base.comp.link_diags.fail(
3558 "multiple definitions of '{s}'",
3559 .{"__" ++ name ++ "_end"},
3560 ),
3561 };
3562}
3563
3453pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) !void {3564pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) !void {
3454 _ = prog_node;3565 _ = prog_node;
3455 elf.prelinkInner() catch |err| switch (err) {3566 elf.prelinkInner() catch |err| switch (err) {
...@@ -3489,6 +3600,9 @@ fn prelinkInner(elf: *Elf) !void {...@@ -3489,6 +3600,9 @@ fn prelinkInner(elf: *Elf) !void {
3489 const needed_len = elf.needed.count();3600 const needed_len = elf.needed.count();
3490 const dynamic_len = needed_len + @intFromBool(elf.options.soname != null) +3601 const dynamic_len = needed_len + @intFromBool(elf.options.soname != null) +
3491 @intFromBool(flags != 0) + @intFromBool(flags_1 != 0) +3602 @intFromBool(flags != 0) + @intFromBool(flags_1 != 0) +
3603 @as(usize, @intFromBool(elf.shndx.init_array != .UNDEF)) * 2 +
3604 @as(usize, @intFromBool(elf.shndx.fini_array != .UNDEF)) * 2 +
3605 @as(usize, @intFromBool(elf.shndx.preinit_array != .UNDEF)) * 2 +
3492 @intFromBool(comp.config.output_mode == .Exe) + 12;3606 @intFromBool(comp.config.output_mode == .Exe) + 12;
3493 const dynamic_size: u32 = @intCast(@sizeOf(ElfN.Addr) * 2 * dynamic_len);3607 const dynamic_size: u32 = @intCast(@sizeOf(ElfN.Addr) * 2 * dynamic_len);
3494 const dynamic_ni = elf.shndx.dynamic.get(elf).ni;3608 const dynamic_ni = elf.shndx.dynamic.get(elf).ni;
...@@ -3520,23 +3634,74 @@ fn prelinkInner(elf: *Elf) !void {...@@ -3520,23 +3634,74 @@ fn prelinkInner(elf: *Elf) !void {
3520 dynamic_entries[dynamic_index] = .{ std.elf.DT_DEBUG, 0 };3634 dynamic_entries[dynamic_index] = .{ std.elf.DT_DEBUG, 0 };
3521 dynamic_index += 1;3635 dynamic_index += 1;
3522 }3636 }
3637 if (elf.shndx.init_array != .UNDEF) {
3638 dynamic_entries[dynamic_index..][0..2].* = .{
3639 .{ std.elf.DT_INIT_ARRAY, @intCast(elf.shndx.init_array.vaddr(elf)) },
3640 .{ std.elf.DT_INIT_ARRAYSZ, elf.targetLoad(
3641 &@field(elf.shdrPtr(elf.shndx.init_array), @tagName(ct_class)).size,
3642 ) },
3643 };
3644 try elf.ensureUnusedRelocCapacity(dynamic_ni, 1);
3645 elf.addRelocAssumeCapacity(
3646 dynamic_ni,
3647 @sizeOf(ElfN.Addr) * (2 * dynamic_index + 1),
3648 .local(elf.shndx.init_array.get(elf).lsi),
3649 0,
3650 .absAddr(elf),
3651 );
3652 dynamic_index += 2;
3653 }
3654 if (elf.shndx.fini_array != .UNDEF) {
3655 dynamic_entries[dynamic_index..][0..2].* = .{
3656 .{ std.elf.DT_FINI_ARRAY, @intCast(elf.shndx.fini_array.vaddr(elf)) },
3657 .{ std.elf.DT_FINI_ARRAYSZ, elf.targetLoad(
3658 &@field(elf.shdrPtr(elf.shndx.fini_array), @tagName(ct_class)).size,
3659 ) },
3660 };
3661 try elf.ensureUnusedRelocCapacity(dynamic_ni, 1);
3662 elf.addRelocAssumeCapacity(
3663 dynamic_ni,
3664 @sizeOf(ElfN.Addr) * (2 * dynamic_index + 1),
3665 .local(elf.shndx.fini_array.get(elf).lsi),
3666 0,
3667 .absAddr(elf),
3668 );
3669 dynamic_index += 2;
3670 }
3671 if (elf.shndx.preinit_array != .UNDEF) {
3672 dynamic_entries[dynamic_index..][0..2].* = .{
3673 .{ std.elf.DT_PREINIT_ARRAY, @intCast(elf.shndx.preinit_array.vaddr(elf)) },
3674 .{ std.elf.DT_PREINIT_ARRAYSZ, elf.targetLoad(
3675 &@field(elf.shdrPtr(elf.shndx.preinit_array), @tagName(ct_class)).size,
3676 ) },
3677 };
3678 try elf.ensureUnusedRelocCapacity(dynamic_ni, 1);
3679 elf.addRelocAssumeCapacity(
3680 dynamic_ni,
3681 @sizeOf(ElfN.Addr) * (2 * dynamic_index + 1),
3682 .local(elf.shndx.preinit_array.get(elf).lsi),
3683 0,
3684 .absAddr(elf),
3685 );
3686 dynamic_index += 2;
3687 }
3523 const rela_dyn_shndx = elf.shndx.got.get(elf).rela_shndx;3688 const rela_dyn_shndx = elf.shndx.got.get(elf).rela_shndx;
3524 const rela_plt_shndx = elf.shndx.got_plt.get(elf).rela_shndx;3689 const rela_plt_shndx = elf.shndx.got_plt.get(elf).rela_shndx;
3525 dynamic_entries[dynamic_index..][0..12].* = .{3690 dynamic_entries[dynamic_index..][0..12].* = .{
3526 .{ std.elf.DT_RELA, @intCast(elf.computeNodeVAddr(rela_dyn_shndx.get(elf).ni)) },3691 .{ std.elf.DT_RELA, @intCast(rela_dyn_shndx.vaddr(elf)) },
3527 .{ std.elf.DT_RELASZ, elf.targetLoad(3692 .{ std.elf.DT_RELASZ, elf.targetLoad(
3528 &@field(elf.shdrPtr(rela_dyn_shndx), @tagName(ct_class)).size,3693 &@field(elf.shdrPtr(rela_dyn_shndx), @tagName(ct_class)).size,
3529 ) },3694 ) },
3530 .{ std.elf.DT_RELAENT, @sizeOf(ElfN.Rela) },3695 .{ std.elf.DT_RELAENT, @sizeOf(ElfN.Rela) },
3531 .{ std.elf.DT_JMPREL, @intCast(elf.computeNodeVAddr(rela_plt_shndx.get(elf).ni)) },3696 .{ std.elf.DT_JMPREL, @intCast(rela_plt_shndx.vaddr(elf)) },
3532 .{ std.elf.DT_PLTRELSZ, elf.targetLoad(3697 .{ std.elf.DT_PLTRELSZ, elf.targetLoad(
3533 &@field(elf.shdrPtr(rela_plt_shndx), @tagName(ct_class)).size,3698 &@field(elf.shdrPtr(rela_plt_shndx), @tagName(ct_class)).size,
3534 ) },3699 ) },
3535 .{ std.elf.DT_PLTGOT, @intCast(elf.computeNodeVAddr(elf.shndx.got_plt.get(elf).ni)) },3700 .{ std.elf.DT_PLTGOT, @intCast(elf.shndx.got_plt.vaddr(elf)) },
3536 .{ std.elf.DT_PLTREL, std.elf.DT_RELA },3701 .{ std.elf.DT_PLTREL, std.elf.DT_RELA },
3537 .{ std.elf.DT_SYMTAB, @intCast(elf.computeNodeVAddr(elf.shndx.dynsym.get(elf).ni)) },3702 .{ std.elf.DT_SYMTAB, @intCast(elf.shndx.dynsym.vaddr(elf)) },
3538 .{ std.elf.DT_SYMENT, @sizeOf(ElfN.Sym) },3703 .{ std.elf.DT_SYMENT, @sizeOf(ElfN.Sym) },
3539 .{ std.elf.DT_STRTAB, @intCast(elf.computeNodeVAddr(elf.shndx.dynstr.get(elf).ni)) },3704 .{ std.elf.DT_STRTAB, @intCast(elf.shndx.dynstr.vaddr(elf)) },
3540 .{ std.elf.DT_STRSZ, elf.targetLoad(3705 .{ std.elf.DT_STRSZ, elf.targetLoad(
3541 &@field(elf.shdrPtr(elf.shndx.dynstr), @tagName(ct_class)).size,3706 &@field(elf.shdrPtr(elf.shndx.dynstr), @tagName(ct_class)).size,
3542 ) },3707 ) },
...@@ -4414,6 +4579,22 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -4414,6 +4579,22 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
4414 }4579 }
4415 }4580 }
4416 }4581 }
4582
4583 // Update global symbols targeting this section
4584 if (elf.node_global_symbols.get(ni)) |first_name| {
4585 assert(first_name != .empty);
4586 const old_addr = elf.targetLoad(&shdr.addr);
4587 var name = first_name;
4588 while (name != .empty) {
4589 const global = elf.globalByName(name).?;
4590 const old_sym_addr: u64 = switch (elf.symPtr(global.symtab_index)) {
4591 inline else => |sym| elf.targetLoad(&sym.value),
4592 };
4593 global.flushMoved(elf, old_sym_addr - old_addr + addr);
4594 name = global.next_in_node;
4595 }
4596 }
4597
4417 elf.targetStore(&shdr.addr, @intCast(addr));4598 elf.targetStore(&shdr.addr, @intCast(addr));
4418 shndx.get(elf).lsi.index().flushMoved(elf, addr);4599 shndx.get(elf).lsi.index().flushMoved(elf, addr);
4419 }4600 }
...@@ -4547,6 +4728,63 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -4547,6 +4728,63 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
4547 .NULL => if (size > 0) elf.targetStore(&shdr.type, .PROGBITS),4728 .NULL => if (size > 0) elf.targetStore(&shdr.type, .PROGBITS),
4548 .PROGBITS => if (size == 0) elf.targetStore(&shdr.type, .NULL),4729 .PROGBITS => if (size == 0) elf.targetStore(&shdr.type, .NULL),
4549 .SYMTAB, .DYNAMIC, .REL, .DYNSYM => return,4730 .SYMTAB, .DYNAMIC, .REL, .DYNSYM => return,
4731 .INIT_ARRAY => {
4732 assert(shndx == elf.shndx.init_array);
4733 if (elf.shndx.dynamic != .UNDEF) {
4734 const dynamic_entries: [][2]class.ElfN().Addr = @ptrCast(@alignCast(
4735 elf.shndx.dynamic.get(elf).ni.slice(&elf.mf),
4736 ));
4737 for (dynamic_entries) |*dynamic_entry|
4738 switch (elf.targetLoad(&dynamic_entry[0])) {
4739 else => {},
4740 std.elf.DT_INIT_ARRAYSZ => dynamic_entry[1] = shdr.size,
4741 };
4742 }
4743 const end_sym_index = elf.globalByName(elf.string(.strtab, "__init_array_end") catch unreachable).?.symtab_index;
4744 const end_sym_ptr = @field(elf.symPtr(end_sym_index), @tagName(class));
4745 const end_vaddr = shndx.vaddr(elf) + elf.targetLoad(&shdr.size);
4746 elf.targetStore(&end_sym_ptr.value, @intCast(end_vaddr));
4747 end_sym_index.flushMoved(elf, end_vaddr);
4748 return;
4749 },
4750 .FINI_ARRAY => {
4751 assert(shndx == elf.shndx.fini_array);
4752 if (elf.shndx.dynamic != .UNDEF) {
4753 const dynamic_entries: [][2]class.ElfN().Addr = @ptrCast(@alignCast(
4754 elf.shndx.dynamic.get(elf).ni.slice(&elf.mf),
4755 ));
4756 for (dynamic_entries) |*dynamic_entry|
4757 switch (elf.targetLoad(&dynamic_entry[0])) {
4758 else => {},
4759 std.elf.DT_FINI_ARRAYSZ => dynamic_entry[1] = shdr.size,
4760 };
4761 }
4762 const end_sym_index = elf.globalByName(elf.string(.strtab, "__fini_array_end") catch unreachable).?.symtab_index;
4763 const end_sym_ptr = @field(elf.symPtr(end_sym_index), @tagName(class));
4764 const end_vaddr = shndx.vaddr(elf) + elf.targetLoad(&shdr.size);
4765 elf.targetStore(&end_sym_ptr.value, @intCast(end_vaddr));
4766 end_sym_index.flushMoved(elf, end_vaddr);
4767 return;
4768 },
4769 .PREINIT_ARRAY => {
4770 assert(shndx == elf.shndx.preinit_array);
4771 if (elf.shndx.dynamic != .UNDEF) {
4772 const dynamic_entries: [][2]class.ElfN().Addr = @ptrCast(@alignCast(
4773 elf.shndx.dynamic.get(elf).ni.slice(&elf.mf),
4774 ));
4775 for (dynamic_entries) |*dynamic_entry|
4776 switch (elf.targetLoad(&dynamic_entry[0])) {
4777 else => {},
4778 std.elf.DT_PREINIT_ARRAYSZ => dynamic_entry[1] = shdr.size,
4779 };
4780 }
4781 const end_sym_index = elf.globalByName(elf.string(.strtab, "__preinit_array_end") catch unreachable).?.symtab_index;
4782 const end_sym_ptr = @field(elf.symPtr(end_sym_index), @tagName(class));
4783 const end_vaddr = shndx.vaddr(elf) + elf.targetLoad(&shdr.size);
4784 elf.targetStore(&end_sym_ptr.value, @intCast(end_vaddr));
4785 end_sym_index.flushMoved(elf, end_vaddr);
4786 return;
4787 },
4550 .STRTAB => {4788 .STRTAB => {
4551 if (elf.shndx.dynamic != .UNDEF) {4789 if (elf.shndx.dynamic != .UNDEF) {
4552 if (shndx == elf.shndx.dynstr) {4790 if (shndx == elf.shndx.dynstr) {