Keep the C stack pointer 16-byte aligned on all x86 platforms, not just Mac OS X...
authorSimon Marlow <marlowsd@gmail.com>
Fri, 17 Jun 2011 22:18:04 +0000 (23:18 +0100)
committerSimon Marlow <marlowsd@gmail.com>
Mon, 27 Jun 2011 11:49:02 +0000 (12:49 +0100)
The OS X ABI requires the C stack pointer to be 16-byte aligned at a
function call.  As far as I know this is not a requirement on other
x86 ABIs, but it seems that gcc is now generating SSE2 code that
assumes stack alignment (-mincoming-stack-boundary defaults to 4), so
we have to respect 16-byte alignment.

compiler/nativeGen/X86/CodeGen.hs
rts/StgCRun.c

index a667c51..d191733 100644 (file)
@@ -1620,10 +1620,10 @@ genCCall target dest_regs args =
                     let
                         sizes               = map (arg_size . cmmExprType . hintlessCmm) (reverse args)
                         raw_arg_size        = sum sizes
-                        tot_arg_size        = if isDarwin then roundTo 16 raw_arg_size else raw_arg_size
+                        tot_arg_size        = roundTo 16 raw_arg_size
                         arg_pad_size        = tot_arg_size - raw_arg_size
                     delta0 <- getDeltaNat
-                    when isDarwin $ setDeltaNat (delta0 - arg_pad_size)
+                    setDeltaNat (delta0 - arg_pad_size)
 
                     use_sse2 <- sse2Enabled
                     push_codes <- mapM (push_arg use_sse2) (reverse args)
@@ -1646,7 +1646,7 @@ genCCall target dest_regs args =
                                         ++ "probably because too many return values."
 
                     let push_code
-                            | isDarwin && (arg_pad_size /= 0)
+                            | arg_pad_size /= 0
                             = toOL [SUB II32 (OpImm (ImmInt arg_pad_size)) (OpReg esp),
                                     DELTA (delta0 - arg_pad_size)]
                               `appOL` concatOL push_codes
@@ -1657,10 +1657,9 @@ genCCall target dest_regs args =
                           -- but not for stdcall (callee does it)
                           --
                           -- We have to pop any stack padding we added
-                          -- on Darwin even if we are doing stdcall, though (#5052)
+                          -- even if we are doing stdcall, though (#5052)
                         pop_size | cconv /= StdCallConv = tot_arg_size
-                                 | isDarwin = arg_pad_size
-                                 | otherwise = 0
+                                 | otherwise = arg_pad_size
 
                         call = callinsns `appOL`
                                toOL (
@@ -1703,10 +1702,6 @@ genCCall target dest_regs args =
                             assign_code dest_regs)
 
                   where
-                    isDarwin = case platformOS (targetPlatform dflags) of
-                               OSDarwin -> True
-                               _        -> False
-
                     arg_size :: CmmType -> Int  -- Width in bytes
                     arg_size ty = widthInBytes (typeWidth ty)
 
index e28353c..a5a4e93 100644 (file)
@@ -128,18 +128,29 @@ StgFunPtr StgReturn(void)
 #define STG_GLOBAL ".global "
 #endif
 
-StgRegTable *
-StgRun(StgFunPtr f, StgRegTable *basereg) {
+static void GNUC3_ATTRIBUTE(used)
+StgRunIsImplementedInAssembler(void)
+{
+    __asm__ volatile (
+        STG_GLOBAL STG_RUN "\n"
+       STG_RUN ":\n\t"
 
-    unsigned char space[ RESERVED_C_STACK_BYTES + 4*sizeof(void *) ];
-    StgRegTable * r;
+       /*
+         * move %esp down to reserve an area for temporary storage
+         * during the execution of STG code.
+         *
+         * The stack pointer has to be aligned to a multiple of 16
+         * bytes from here - this is a requirement of the C ABI, so
+         * that C code can assign SSE2 registers directly to/from
+         * stack locations.
+        */
+        "subl %0, %%esp\n\t"
 
-    __asm__ volatile (
        /*
         * save callee-saves registers on behalf of the STG code.
         */
-       "movl %%esp, %%eax\n\t"
-       "addl %4, %%eax\n\t"
+        "movl %%esp, %%eax\n\t"
+        "addl %0-16, %%eax\n\t"
         "movl %%ebx,0(%%eax)\n\t"
         "movl %%esi,4(%%eax)\n\t"
         "movl %%edi,8(%%eax)\n\t"
@@ -147,25 +158,17 @@ StgRun(StgFunPtr f, StgRegTable *basereg) {
        /*
         * Set BaseReg
         */
-       "movl %3,%%ebx\n\t"
+        "movl 24(%%eax),%%ebx\n\t"
        /*
         * grab the function argument from the stack
         */
-        "movl %2,%%eax\n\t"
-        
-       /*
-        * Darwin note:
-        * The stack pointer has to be aligned to a multiple of 16 bytes at
-        * this point. This works out correctly with gcc 4.0.1, but it might
-        * break at any time in the future. TODO: Make this future-proof.
-        */
-
-       /*
+        "movl 20(%%eax),%%eax\n\t"
+        /*
         * jump to it
         */
         "jmp *%%eax\n\t"
 
-       STG_GLOBAL STG_RETURN "\n"
+        STG_GLOBAL STG_RETURN "\n"
                STG_RETURN ":\n\t"
 
        "movl %%esi, %%eax\n\t"   /* Return value in R1  */
@@ -174,18 +177,19 @@ StgRun(StgFunPtr f, StgRegTable *basereg) {
         * restore callee-saves registers.  (Don't stomp on %%eax!)
         */
        "movl %%esp, %%edx\n\t"
-       "addl %4, %%edx\n\t"
+        "addl %0, %%edx\n\t"
         "movl 0(%%edx),%%ebx\n\t"      /* restore the registers saved above */
         "movl 4(%%edx),%%esi\n\t"
         "movl 8(%%edx),%%edi\n\t"
         "movl 12(%%edx),%%ebp\n\t"
 
-      : "=&a" (r), "=m" (space)
-      : "m" (f), "m" (basereg), "i" (RESERVED_C_STACK_BYTES)
-      : "edx" /* stomps on %edx */
-    );
+        "addl %0, %%esp\n\t"
+        "ret"
 
-    return r;
+      : : "i" (RESERVED_C_STACK_BYTES + 16 + 12)
+        // + 16 to make room for the 4 registers we have to save
+        // + 12 because we need to align %esp to a 16-byte boundary (#5250)
+    );
 }
 
 #endif