Last night I ran into a familiar problem --- it turns out that, on RISC-V, some globals are put in an .sbss section. I was using a linker script patterned from my ARM64 one, which doesn't use that. This lead to some headscratching as some globals were being placed after the "end" pointer I'd put in the linker script. objdump showed me that there were some sections that had been put there by default.
Today in #zig-help @rgreenblatt happened to hit something that sounded familiar: this time the presentation was __zig_probe_stack being placed at the end of their loaded data. It was the same thing; he had loaded *(.text) in the linker script, but the probe stack function was placed in a section called .text.__zig_probe_stack, so it just got put at the end too.
TIL these are called orphaned sections, and LLD has a parameter --orphan-handling=error which causes it to error out if any sections are unnamed by the linker script. Access to this would be very helpful for embedded, since the "helpful" behaviour of just putting them at the end is actually kinda dangerous and leads to lots of confusion.
diff --git a/src/link/Elf.zig b/src/link/Elf.zig
index 314e443f3..0d4a817b4 100644
--- a/src/link/Elf.zig
+++ b/src/link/Elf.zig
@@ -1462,6 +1462,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
}
try argv.appendSlice(self.base.options.extra_lld_args);
+ try argv.append("--orphan-handling=error");
if (self.base.options.z_nodelete) {
try argv.append("-z");
I used this to minimally test that it works as expected, and it does. The thing is, the "default" linker script seems to actually orphan everything, letting the linker just drop every section in as an orphan. Here's a demo with the change:
$ cat test.zig
pub fn main() void {}
$ zig build-exe test.zig -target aarch64-linux-musl
ld.lld: error: zig-cache/o/30d7afa88b192b441a081997e43a357b/test.o:(.text) is being placed in '.text'
ld.lld: error: zig-cache/o/30d7afa88b192b441a081997e43a357b/test.o:(.rodata) is being placed in '.rodata'
ld.lld: error: zig-cache/o/30d7afa88b192b441a081997e43a357b/test.o:(.rodata.cst16) is being placed in '.rodata'
ld.lld: error: zig-cache/o/30d7afa88b192b441a081997e43a357b/test.o:(.rodata.cst8) is being placed in '.rodata'
ld.lld: error: zig-cache/o/30d7afa88b192b441a081997e43a357b/test.o:(.rodata.str1.1) is being placed in '.rodata'
ld.lld: error: zig-cache/o/30d7afa88b192b441a081997e43a357b/test.o:(.bss) is being placed in '.bss'
ld.lld: error: zig-cache/o/30d7afa88b192b441a081997e43a357b/test.o:(.tbss) is being placed in '.tbss'
ld.lld: error: zig-cache/o/30d7afa88b192b441a081997e43a357b/test.o:(.data) is being placed in '.data'
ld.lld: error: zig-cache/o/30d7afa88b192b441a081997e43a357b/test.o:(.rodata.cst4) is being placed in '.rodata'
ld.lld: error: zig-cache/o/30d7afa88b192b441a081997e43a357b/test.o:(.rodata.cst32) is being placed in '.rodata'
ld.lld: error: zig-cache/o/30d7afa88b192b441a081997e43a357b/test.o:(.debug_loc) is being placed in '.debug_loc'
ld.lld: error: zig-cache/o/30d7afa88b192b441a081997e43a357b/test.o:(.debug_abbrev) is being placed in '.debug_abbrev'
ld.lld: error: zig-cache/o/30d7afa88b192b441a081997e43a357b/test.o:(.debug_info) is being placed in '.debug_info'
ld.lld: error: zig-cache/o/30d7afa88b192b441a081997e43a357b/test.o:(.debug_ranges) is being placed in '.debug_ranges'
ld.lld: error: zig-cache/o/30d7afa88b192b441a081997e43a357b/test.o:(.debug_str) is being placed in '.debug_str'
ld.lld: error: zig-cache/o/30d7afa88b192b441a081997e43a357b/test.o:(.debug_pubnames) is being placed in '.debug_pubnames'
ld.lld: error: zig-cache/o/30d7afa88b192b441a081997e43a357b/test.o:(.debug_pubtypes) is being placed in '.debug_pubtypes'
ld.lld: error: zig-cache/o/30d7afa88b192b441a081997e43a357b/test.o:(.debug_frame) is being placed in '.debug_frame'
ld.lld: error: zig-cache/o/30d7afa88b192b441a081997e43a357b/test.o:(.debug_line) is being placed in '.debug_line'
ld.lld: error: /Users/kameliya/.cache/zig/o/ab2c2add6c0ae640490aa3cbc70de91c/libc.a(/Users/kameliya/.cache/zig/o/ab2c2add6c0ae640490aa3cbc70de91c/c.o):(.text.memset) is being placed in '
.text'
ld.lld: error: /Users/kameliya/.cache/zig/o/ab2c2add6c0ae640490aa3cbc70de91c/libc.a(/Users/kameliya/.cache/zig/o/ab2c2add6c0ae640490aa3cbc70de91c/c.o):(.text.memcpy) is being placed in '
.text'
ld.lld: error: /Users/kameliya/.cache/zig/o/57ca96a87c228d21d399eedec4c2db72/libcompiler_rt.a(/Users/kameliya/.cache/zig/o/57ca96a87c228d21d399eedec4c2db72/compiler_rt.o):(.text.__divti3
) is being placed in '.text'
ld.lld: error: /Users/kameliya/.cache/zig/o/57ca96a87c228d21d399eedec4c2db72/libcompiler_rt.a(/Users/kameliya/.cache/zig/o/57ca96a87c228d21d399eedec4c2db72/compiler_rt.o):(.text.compiler
_rt.udivmod.udivmod.65) is being placed in '.text'
ld.lld: error: /Users/kameliya/.cache/zig/o/57ca96a87c228d21d399eedec4c2db72/libcompiler_rt.a(/Users/kameliya/.cache/zig/o/57ca96a87c228d21d399eedec4c2db72/compiler_rt.o):(.text.__udivti
3) is being placed in '.text'
ld.lld: error: /Users/kameliya/.cache/zig/o/57ca96a87c228d21d399eedec4c2db72/libcompiler_rt.a(/Users/kameliya/.cache/zig/o/57ca96a87c228d21d399eedec4c2db72/compiler_rt.o):(.text.__muloti
4) is being placed in '.text'
ld.lld: error: <internal>:(.comment) is being placed in '.comment'
ld.lld: error: <internal>:(.got) is being placed in '.got'
ld.lld: error: <internal>:(.symtab) is being placed in '.symtab'
ld.lld: error: <internal>:(.shstrtab) is being placed in '.shstrtab'
ld.lld: error: <internal>:(.strtab) is being placed in '.strtab'
panic: attempt to unwrap error: LLDReportedFailure
/Users/kameliya/Code/zig/lib/std/heap.zig:142:46: 0x1042c73b7 in std.heap.CAllocator.resize (zig1)
const full_len = alignedAllocSize(buf.ptr);
So we may want to only expose an option for this, letting embedded developers opt-in, so they can then choose to include or ignore what they like.
Last night I ran into a familiar problem --- it turns out that, on RISC-V, some globals are put in an
.sbsssection. I was using a linker script patterned from my ARM64 one, which doesn't use that. This lead to some headscratching as some globals were being placed after the "end" pointer I'd put in the linker script.objdumpshowed me that there were some sections that had been put there by default.Today in #zig-help @rgreenblatt happened to hit something that sounded familiar: this time the presentation was
__zig_probe_stackbeing placed at the end of their loaded data. It was the same thing; he had loaded*(.text)in the linker script, but the probe stack function was placed in a section called.text.__zig_probe_stack, so it just got put at the end too.TIL these are called orphaned sections, and LLD has a parameter
--orphan-handling=errorwhich causes it to error out if any sections are unnamed by the linker script. Access to this would be very helpful for embedded, since the "helpful" behaviour of just putting them at the end is actually kinda dangerous and leads to lots of confusion.I used this to minimally test that it works as expected, and it does. The thing is, the "default" linker script seems to actually orphan everything, letting the linker just drop every section in as an orphan. Here's a demo with the change:
So we may want to only expose an option for this, letting embedded developers opt-in, so they can then choose to include or ignore what they like.