From 9c617747b7575c17783d065ade1e4559a5f9b895 Mon Sep 17 00:00:00 2001 From: simonmar Date: Wed, 30 Mar 2005 09:49:55 +0000 Subject: [PATCH] [project @ 2005-03-30 09:49:55 by simonmar] Hack around a nasty bug on x86_64, caused by failing to align %rsp correctly at a C call. See the comment for details. --- ghc/rts/StgCRun.c | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/ghc/rts/StgCRun.c b/ghc/rts/StgCRun.c index cf210d2..4d5136f 100644 --- a/ghc/rts/StgCRun.c +++ b/ghc/rts/StgCRun.c @@ -225,7 +225,41 @@ static void StgRunIsImplementedInAssembler(void) "addq %0, %%rsp\n\t" "retq" - : : "i"(RESERVED_C_STACK_BYTES+48 /*stack frame size*/)); + : : "i"(RESERVED_C_STACK_BYTES+48+8 /*stack frame size*/)); + /* + HACK alert! + + The x86_64 ABI specifies that on a procedure call, %rsp is + aligned on a 16-byte boundary + 8. That is, the first + argument on the stack after the return address will be + 16-byte aligned. + + Which should be fine: RESERVED_C_STACK_BYTES+48 is a multiple + of 16 bytes. + + BUT... when we do a C-call from STG land, gcc likes to put the + stack alignment adjustment in the prolog. eg. if we're calling + a function with arguments in regs, gcc will insert 'subq $8,%rsp' + in the prolog, to keep %rsp aligned (the return address is 8 + bytes, remember). The mangler throws away the prolog, so we + lose the stack alignment. + + The hack is to add this extra 8 bytes to our %rsp adjustment + here, so that throughout STG code, %rsp is 16-byte aligned, + ready for a C-call. + + A quick way to see if this is wrong is to compile this code: + + main = System.Exit.exitWith ExitSuccess + + And run it with +RTS -sstderr. The stats code in the RTS, in + particular statsPrintf(), relies on the stack alignment because + it saves the %xmm regs on the stack, so it'll fall over if the + stack isn't aligned, and calling exitWith from Haskell invokes + shutdownHaskellAndExit using a C call. + + Future gcc releases will almost certainly break this hack... + */ } #endif /* x86-64 */ -- 1.7.10.4