authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2024-07-22 01:22:47+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2024-07-22 01:22:47+02:00
log7bc78967b400322a0fc5651f37a1b0428c37fb9d
treec4eee7937ac827aa648b1b027232dac88106749c
parentecd459b8647a1b7cade31f0286694e14101f80f4
signaturebadge-check Signed by SSH key SHA256:7B/LJ7bpR1eX8aCXSr4mtd5M45VMPKcx9zY8e95b5QM

start: Fix _start() to initialize the ToC for powerpc64.

The previous version of this function referenced the argc_argv_ptr global variable as an inline asm operand. This caused LLVM to generate prologue code to initialize the ToC so that the global variable can actually be accessed. Ordinarily, there's nothing wrong with that. But _start() is a naked function! This makes it actually super surprising that LLVM did this. It also means that the old version only really worked by accident. Once the reference to the global variable was removed, no ToC was set up, thus violating the calling convention once we got to posixCallMainAndExit(). This then caused any attempt to access global variables here to crash - namely when setting std.os.linux.elf_aux_maybe. The fix is to just initialize the ToC manually in _start().

1 files changed, 2 insertions(+), 0 deletions(-)

lib/std/start.zig+2
......@@ -341,6 +341,8 @@ fn _start() callconv(.Naked) noreturn {
341341 .powerpc64, .powerpc64le =>
342342 // Setup the initial stack frame and clear the back chain pointer.
343343 // TODO: Support powerpc64 (big endian) on ELFv2.
344 \\ addis 2, 12, .TOC. - _start@ha
345 \\ addi 2, 2, .TOC. - _start@l
344346 \\ mr 3, 1
345347 \\ li 0, 0
346348 \\ stdu 0, -32(1)