Skip to content

Commit ed847b8

Browse files
authored
Merge pull request #20777 from alexrp/start-abi-hardening
`start`: Harden against program interpreters that don't adhere fully to the ABI
2 parents 3344ed8 + fff5ce0 commit ed847b8

File tree

1 file changed

+29
-25
lines changed

1 file changed

+29
-25
lines changed

lib/std/start.zig

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,12 @@ fn _start() callconv(.Naked) noreturn {
272272
: [tos] "={rax}" (-> *std.os.plan9.Tos),
273273
);
274274
}
275+
276+
// Note that we maintain a very low level of trust with regards to ABI guarantees at this point.
277+
// We will redundantly align the stack, clear the link register, etc. While e.g. the Linux
278+
// kernel is usually good about upholding the ABI guarantees, the same cannot be said of dynamic
279+
// linkers; musl's ldso, for example, opts to not align the stack when invoking the dynamic
280+
// linker explicitly.
275281
asm volatile (switch (native_arch) {
276282
.x86_64 =>
277283
\\ xorl %%ebp, %%ebp
@@ -291,6 +297,7 @@ fn _start() callconv(.Naked) noreturn {
291297
\\ mov fp, #0
292298
\\ mov lr, #0
293299
\\ mov x0, sp
300+
\\ and sp, x0, #-16
294301
\\ b %[posixCallMainAndExit]
295302
,
296303
.arm, .armeb, .thumb, .thumbeb =>
@@ -322,38 +329,31 @@ fn _start() callconv(.Naked) noreturn {
322329
\\ jsr (%%pc, %%a0)
323330
,
324331
.mips, .mipsel =>
325-
// The lr is already zeroed on entry, as specified by the ABI.
326-
\\ addiu $fp, $zero, 0
332+
\\ move $fp, $0
333+
\\ move $ra, $0
327334
\\ move $a0, $sp
328-
\\ .set push
329-
\\ .set noat
330-
\\ addiu $1, $zero, -16
331-
\\ and $sp, $sp, $1
332-
\\ .set pop
335+
\\ and $sp, -8
333336
\\ j %[posixCallMainAndExit]
334337
,
335338
.mips64, .mips64el =>
336-
// The lr is already zeroed on entry, as specified by the ABI.
337-
\\ addiu $fp, $zero, 0
339+
\\ move $fp, $0
340+
\\ move $ra, $0
338341
\\ move $a0, $sp
339-
\\ .set push
340-
\\ .set noat
341-
\\ daddiu $1, $zero, -16
342-
\\ and $sp, $sp, $1
343-
\\ .set pop
342+
\\ and $sp, -16
344343
\\ j %[posixCallMainAndExit]
345344
,
346345
.powerpc, .powerpcle =>
347-
// Setup the initial stack frame and clear the back chain pointer.
346+
// Set up the initial stack frame, and clear the back chain pointer.
348347
\\ mr 3, 1
348+
\\ clrrwi 1, 1, 4
349349
\\ li 0, 0
350350
\\ stwu 1, -16(1)
351351
\\ stw 0, 0(1)
352352
\\ mtlr 0
353353
\\ b %[posixCallMainAndExit]
354354
,
355355
.powerpc64, .powerpc64le =>
356-
// Setup the initial stack frame and clear the back chain pointer.
356+
// Set up the ToC and initial stack frame, and clear the back chain pointer.
357357
\\ addis 2, 12, .TOC. - %[_start]@ha
358358
\\ addi 2, 2, .TOC. - %[_start]@l
359359
\\ mr 3, 1
@@ -365,18 +365,22 @@ fn _start() callconv(.Naked) noreturn {
365365
,
366366
.s390x =>
367367
// Set up the stack frame (register save area and cleared back-chain slot).
368-
// Note: Stack pointer is guaranteed by ABI to be 8-byte aligned as required.
369-
\\ lgr %r2, %r15
370-
\\ aghi %r15, -160
371-
\\ lghi %r0, 0
372-
\\ stg %r0, 0(%r15)
368+
\\ lgr %%r2, %%r15
369+
\\ lghi %%r0, -16
370+
\\ ngr %%r15, %%r0
371+
\\ aghi %%r15, -160
372+
\\ lghi %%r0, 0
373+
\\ stg %%r0, 0(%%r15)
373374
\\ jg %[posixCallMainAndExit]
374375
,
375376
.sparc64 =>
376-
// argc is stored after a register window (16 registers) plus stack bias
377-
\\ mov %%g0, %%i6
378-
\\ add %%o6, 2175, %%l0
379-
\\ mov %%l0, %%o0
377+
// argc is stored after a register window (16 registers * 8 bytes) plus the stack bias
378+
// (2047 bytes).
379+
\\ mov %%g0, %%fp
380+
\\ add %%sp, 2175, %%o0
381+
\\ add %%sp, 2047, %%sp
382+
\\ and %%sp, -16, %%sp
383+
\\ sub %%sp, 2047, %%sp
380384
\\ ba,a %[posixCallMainAndExit]
381385
,
382386
else => @compileError("unsupported arch"),

0 commit comments

Comments
 (0)