From 5c96192c196c3a43f43de26c8256ed9a784f5140 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 24 Jul 2024 17:38:54 +0200 Subject: [PATCH 01/11] start: Add a comment explaining our paranoid stance on ABI guarantees. --- lib/std/start.zig | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/std/start.zig b/lib/std/start.zig index 9d4edd16bf60..21baacc76446 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -272,6 +272,12 @@ fn _start() callconv(.Naked) noreturn { : [tos] "={rax}" (-> *std.os.plan9.Tos), ); } + + // Note that we maintain a very low level of trust with regards to ABI guarantees at this point. + // We will redundantly align the stack, clear the link register, etc. While e.g. the Linux + // kernel is usually good about upholding the ABI guarantees, the same cannot be said of dynamic + // linkers; musl's ldso, for example, opts to not align the stack when invoking the dynamic + // linker explicitly. asm volatile (switch (native_arch) { .x86_64 => \\ xorl %%ebp, %%ebp From 58e38ff1f82b19ee529f0f5abe74a2c03c204dfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 24 Jul 2024 17:36:15 +0200 Subject: [PATCH 02/11] start: Add a comment explaining the sparc64 stack bias. --- lib/std/start.zig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/std/start.zig b/lib/std/start.zig index 21baacc76446..336526b7b4a6 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -379,7 +379,8 @@ fn _start() callconv(.Naked) noreturn { \\ jg %[posixCallMainAndExit] , .sparc64 => - // argc is stored after a register window (16 registers) plus stack bias + // argc is stored after a register window (16 registers * 8 bytes) plus the stack bias + // (2047 bytes). \\ mov %%g0, %%i6 \\ add %%o6, 2175, %%l0 \\ mov %%l0, %%o0 From 9771390f8980ef455cd0113840556e58ebea4ba1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 24 Jul 2024 17:59:53 +0200 Subject: [PATCH 03/11] start: Simplify the sparc64 inline asm a bit. --- lib/std/start.zig | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/std/start.zig b/lib/std/start.zig index 336526b7b4a6..4c3329a01cbf 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -381,9 +381,8 @@ fn _start() callconv(.Naked) noreturn { .sparc64 => // argc is stored after a register window (16 registers * 8 bytes) plus the stack bias // (2047 bytes). - \\ mov %%g0, %%i6 - \\ add %%o6, 2175, %%l0 - \\ mov %%l0, %%o0 + \\ mov %%g0, %%fp + \\ add %%sp, 2175, %%o0 \\ ba,a %[posixCallMainAndExit] , else => @compileError("unsupported arch"), From 714e7433930e68698b1e33c1de13dc5514cd5a77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 24 Jul 2024 17:34:44 +0200 Subject: [PATCH 04/11] start: Align the stack on aarch64 just in case. The kernel does this as required, but we cannot trust dynamic linkers to do it. --- lib/std/start.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/std/start.zig b/lib/std/start.zig index 4c3329a01cbf..35485a699531 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -297,6 +297,7 @@ fn _start() callconv(.Naked) noreturn { \\ mov fp, #0 \\ mov lr, #0 \\ mov x0, sp + \\ and sp, x0, #-16 \\ b %[posixCallMainAndExit] , .arm, .armeb, .thumb, .thumbeb => From 52653ec82bcc8e10fee9b6d9997b2de41a22a93a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 24 Jul 2024 17:35:47 +0200 Subject: [PATCH 05/11] start: Align the stack on powerpc just in case. The kernel does this as required, but we cannot trust dynamic linkers to do it. --- lib/std/start.zig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/std/start.zig b/lib/std/start.zig index 35485a699531..015f2c077fcc 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -351,8 +351,9 @@ fn _start() callconv(.Naked) noreturn { \\ j %[posixCallMainAndExit] , .powerpc, .powerpcle => - // Setup the initial stack frame and clear the back chain pointer. + // Set up the initial stack frame, and clear the back chain pointer. \\ mr 3, 1 + \\ clrrwi 1, 1, 4 \\ li 0, 0 \\ stwu 1, -16(1) \\ stw 0, 0(1) @@ -360,7 +361,7 @@ fn _start() callconv(.Naked) noreturn { \\ b %[posixCallMainAndExit] , .powerpc64, .powerpc64le => - // Setup the initial stack frame and clear the back chain pointer. + // Set up the ToC and initial stack frame, and clear the back chain pointer. \\ addis 2, 12, .TOC. - %[_start]@ha \\ addi 2, 2, .TOC. - %[_start]@l \\ mr 3, 1 From ce81525f3f3057e4239332b2152bf60f75c5f52a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 24 Jul 2024 17:36:34 +0200 Subject: [PATCH 06/11] start: Align the stack on s390x just in case. The kernel does this as required, but we cannot trust dynamic linkers to do it. --- lib/std/start.zig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/std/start.zig b/lib/std/start.zig index 015f2c077fcc..437498d1d8cc 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -373,8 +373,9 @@ fn _start() callconv(.Naked) noreturn { , .s390x => // Set up the stack frame (register save area and cleared back-chain slot). - // Note: Stack pointer is guaranteed by ABI to be 8-byte aligned as required. \\ lgr %r2, %r15 + \\ lghi %r0, -16 + \\ ngr %r15, %r0 \\ aghi %r15, -160 \\ lghi %r0, 0 \\ stg %r0, 0(%r15) From 1b13d7477d8c9f2154a8779f2e58c65cf1685b05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 24 Jul 2024 17:46:59 +0200 Subject: [PATCH 07/11] start: Properly escape percent signs in the s390x inline asm. Silly mistake in 8ffc41f74705246e61f3c02c253d40b1464ea2bf. --- lib/std/start.zig | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/std/start.zig b/lib/std/start.zig index 437498d1d8cc..78a2c9e496b0 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -373,12 +373,12 @@ fn _start() callconv(.Naked) noreturn { , .s390x => // Set up the stack frame (register save area and cleared back-chain slot). - \\ lgr %r2, %r15 - \\ lghi %r0, -16 - \\ ngr %r15, %r0 - \\ aghi %r15, -160 - \\ lghi %r0, 0 - \\ stg %r0, 0(%r15) + \\ lgr %%r2, %%r15 + \\ lghi %%r0, -16 + \\ ngr %%r15, %%r0 + \\ aghi %%r15, -160 + \\ lghi %%r0, 0 + \\ stg %%r0, 0(%%r15) \\ jg %[posixCallMainAndExit] , .sparc64 => From 47c0464e860486150942b73a78529805d4f320b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 24 Jul 2024 17:41:18 +0200 Subject: [PATCH 08/11] start: Explicitly clear the link register on mips and mips64 just in case. The kernel does this as required, but we cannot trust dynamic linkers to do it. --- lib/std/start.zig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/std/start.zig b/lib/std/start.zig index 78a2c9e496b0..b53f2258e1d5 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -329,8 +329,8 @@ fn _start() callconv(.Naked) noreturn { \\ jsr (%%pc, %%a0) , .mips, .mipsel => - // The lr is already zeroed on entry, as specified by the ABI. - \\ addiu $fp, $zero, 0 + \\ move $fp, $0 + \\ move $ra, $0 \\ move $a0, $sp \\ .set push \\ .set noat @@ -340,8 +340,8 @@ fn _start() callconv(.Naked) noreturn { \\ j %[posixCallMainAndExit] , .mips64, .mips64el => - // The lr is already zeroed on entry, as specified by the ABI. - \\ addiu $fp, $zero, 0 + \\ move $fp, $0 + \\ move $ra, $0 \\ move $a0, $sp \\ .set push \\ .set noat From 5478b0eb3821df4fcdbcb221441e732576be7d68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 24 Jul 2024 18:35:20 +0200 Subject: [PATCH 09/11] start: Simplify mips and mips64 startup code. Switches from using r1 as a temporary to r2. That way, we don't have to set the `noat` assembler option. (r1 is the scratch register used by the assembler's pseudoinstructions; the assembler warns when code uses that register explicitly without `noat` set.) --- lib/std/start.zig | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/lib/std/start.zig b/lib/std/start.zig index b53f2258e1d5..c3e5d0687819 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -332,22 +332,14 @@ fn _start() callconv(.Naked) noreturn { \\ move $fp, $0 \\ move $ra, $0 \\ move $a0, $sp - \\ .set push - \\ .set noat - \\ addiu $1, $zero, -16 - \\ and $sp, $sp, $1 - \\ .set pop + \\ and $sp, -16 \\ j %[posixCallMainAndExit] , .mips64, .mips64el => \\ move $fp, $0 \\ move $ra, $0 \\ move $a0, $sp - \\ .set push - \\ .set noat - \\ daddiu $1, $zero, -16 - \\ and $sp, $sp, $1 - \\ .set pop + \\ and $sp, -16 \\ j %[posixCallMainAndExit] , .powerpc, .powerpcle => From ebefee608810d947fb9a17e853acd30dc619cb88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Thu, 25 Jul 2024 00:55:36 +0200 Subject: [PATCH 10/11] start: Fix mips stack alignment value (should be 8, not 16). --- lib/std/start.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/start.zig b/lib/std/start.zig index c3e5d0687819..2f0a802e4eb4 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -332,7 +332,7 @@ fn _start() callconv(.Naked) noreturn { \\ move $fp, $0 \\ move $ra, $0 \\ move $a0, $sp - \\ and $sp, -16 + \\ and $sp, -8 \\ j %[posixCallMainAndExit] , .mips64, .mips64el => From fff5ce053fcfaf0cf3fea815b4c50c000036ff5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 24 Jul 2024 20:11:36 +0200 Subject: [PATCH 11/11] start: Align the stack on sparc64 just in case. The kernel does this as required, but we cannot trust dynamic linkers to do it. --- lib/std/start.zig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/std/start.zig b/lib/std/start.zig index 2f0a802e4eb4..326857d9c095 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -378,6 +378,9 @@ fn _start() callconv(.Naked) noreturn { // (2047 bytes). \\ mov %%g0, %%fp \\ add %%sp, 2175, %%o0 + \\ add %%sp, 2047, %%sp + \\ and %%sp, -16, %%sp + \\ sub %%sp, 2047, %%sp \\ ba,a %[posixCallMainAndExit] , else => @compileError("unsupported arch"),