commit b7a544c527f0d54cf9d044f26daf272e9297a786 (tree)
parent 9ff926bb1e47ebad0f13835355841ef4654fbe60
Author: Matthew Lugg <mlugg@mlugg.co.uk>
Date: Mon, 15 Jun 2026 17:57:52 +0100
Elf2: always define `__init_array_start` and friends
These symbols should exist even if there is no actual `.init_array` (or
whichever) section. So, always define them, and if we end up creating
the corresponding section, just update the symbols' values.
Diffstat:
| M | src/link/Elf2.zig | | | 102 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------- |
1 file changed, 81 insertions(+), 21 deletions(-)
diff --git a/src/link/Elf2.zig b/src/link/Elf2.zig
@@ -3254,7 +3254,7 @@ fn initHeaders(
// `FINI_ARRAY`/`PREINIT_ARRAY` sections are instead created by `createInitFiniArraySection`
// when needed (it seems to be legal to leave those undefined if the section doesn't exist).
- try elf.ensureUnusedSymbolCapacity(4, .maybe_global);
+ try elf.ensureUnusedSymbolCapacity(10, .maybe_global);
// Despite the name, `__dso_handle` is necessary even in static binaries.
_ = elf.addGlobalSymbolAssumeCapacity(.{
.node = Section.Index.text.get(elf).ni,
@@ -3292,6 +3292,78 @@ fn initHeaders(
}) catch |err| switch (err) {
error.MultipleDefinitions => unreachable, // no inputs are processed yet
};
+ _ = elf.addGlobalSymbolAssumeCapacity(.{
+ .node = .none,
+ .name = try .string(elf, "__init_array_start"),
+ .value = 0,
+ .size = 0,
+ .type = .NOTYPE,
+ .bind = .strong,
+ .visibility = .HIDDEN,
+ .shndx = .ABS,
+ }) catch |err| switch (err) {
+ error.MultipleDefinitions => unreachable, // no inputs are processed yet
+ };
+ _ = elf.addGlobalSymbolAssumeCapacity(.{
+ .node = .none,
+ .name = try .string(elf, "__init_array_end"),
+ .value = 0,
+ .size = 0,
+ .type = .NOTYPE,
+ .bind = .strong,
+ .visibility = .HIDDEN,
+ .shndx = .ABS,
+ }) catch |err| switch (err) {
+ error.MultipleDefinitions => unreachable, // no inputs are processed yet
+ };
+ _ = elf.addGlobalSymbolAssumeCapacity(.{
+ .node = .none,
+ .name = try .string(elf, "__fini_array_start"),
+ .value = 0,
+ .size = 0,
+ .type = .NOTYPE,
+ .bind = .strong,
+ .visibility = .HIDDEN,
+ .shndx = .ABS,
+ }) catch |err| switch (err) {
+ error.MultipleDefinitions => unreachable, // no inputs are processed yet
+ };
+ _ = elf.addGlobalSymbolAssumeCapacity(.{
+ .node = .none,
+ .name = try .string(elf, "__fini_array_end"),
+ .value = 0,
+ .size = 0,
+ .type = .NOTYPE,
+ .bind = .strong,
+ .visibility = .HIDDEN,
+ .shndx = .ABS,
+ }) catch |err| switch (err) {
+ error.MultipleDefinitions => unreachable, // no inputs are processed yet
+ };
+ _ = elf.addGlobalSymbolAssumeCapacity(.{
+ .node = .none,
+ .name = try .string(elf, "__preinit_array_start"),
+ .value = 0,
+ .size = 0,
+ .type = .NOTYPE,
+ .bind = .strong,
+ .visibility = .HIDDEN,
+ .shndx = .ABS,
+ }) catch |err| switch (err) {
+ error.MultipleDefinitions => unreachable, // no inputs are processed yet
+ };
+ _ = elf.addGlobalSymbolAssumeCapacity(.{
+ .node = .none,
+ .name = try .string(elf, "__preinit_array_end"),
+ .value = 0,
+ .size = 0,
+ .type = .NOTYPE,
+ .bind = .strong,
+ .visibility = .HIDDEN,
+ .shndx = .ABS,
+ }) catch |err| switch (err) {
+ error.MultipleDefinitions => unreachable, // no inputs are processed yet
+ };
if (have_dynamic_section) {
_ = elf.addGlobalSymbolAssumeCapacity(.{
.node = elf.shndx.dynamic.get(elf).ni,
@@ -4759,36 +4831,24 @@ fn createInitFiniArraySection(
});
elf.section_by_name.putAssumeCapacityNoClobber(shndx.name(elf), {});
try elf.ensureUnusedSymbolCapacity(2, .maybe_global);
- _ = elf.addGlobalSymbolAssumeCapacity(.{
+ // These symbols definitely already have strong definitions, because we added them alongside the
+ // other linker-defined symbols, all the way back in `initHeaders`.
+ const start_sym_name = try elf.string(.strtab, "__" ++ name ++ "_start");
+ const end_sym_name = try elf.string(.strtab, "__" ++ name ++ "_end");
+ elf.setGlobalSymbolValue(start_sym_name, elf.globals.strong_def.getPtr(start_sym_name).?, .{
.node = shndx.get(elf).ni,
- .name = try .string(elf, "__" ++ name ++ "_start"),
.value = shndx.vaddr(elf),
.size = 0,
.type = .NOTYPE,
- .bind = .strong,
- .visibility = .HIDDEN,
.shndx = shndx.*,
- }) catch |err| switch (err) {
- error.MultipleDefinitions => return elf.base.comp.link_diags.fail(
- "multiple definitions of '{s}'",
- .{"__" ++ name ++ "_start"},
- ),
- };
- _ = elf.addGlobalSymbolAssumeCapacity(.{
+ });
+ elf.setGlobalSymbolValue(end_sym_name, elf.globals.strong_def.getPtr(end_sym_name).?, .{
.node = shndx.get(elf).ni,
- .name = try .string(elf, "__" ++ name ++ "_end"),
.value = shndx.vaddr(elf),
.size = 0,
.type = .NOTYPE,
- .bind = .strong,
- .visibility = .HIDDEN,
.shndx = shndx.*,
- }) catch |err| switch (err) {
- error.MultipleDefinitions => return elf.base.comp.link_diags.fail(
- "multiple definitions of '{s}'",
- .{"__" ++ name ++ "_end"},
- ),
- };
+ });
}
fn updateInitFiniArraySectionSize(
elf: *Elf,