Pop OS X stack padding even if the foreign call is stdcall (#5052)
authorMax Bolingbroke <batterseapower@hotmail.com>
Fri, 1 Apr 2011 23:06:16 +0000 (00:06 +0100)
committerMax Bolingbroke <batterseapower@hotmail.com>
Fri, 1 Apr 2011 23:20:48 +0000 (00:20 +0100)
The problem was that the codegen for foreign calls makes sure the stack
is 16-byte aligned on OS X by pushing some padding. In the case where the
foreign call is cdecl, that padding gets popped after the call, but if the
convention is stdcall then it doesn't generate any popping code at all.

However, this is incorrect because the stdcall only promises to pop the
arguments, not the padding. The fix is to generate code to pop the padding
(if any) on OS X.

compiler/nativeGen/X86/CodeGen.hs

index e606e2c..86ecbf9 100644 (file)
@@ -1587,12 +1587,24 @@ genCCall target dest_regs args = do
             | otherwise
 #endif
             = concatOL push_codes
+       
+         -- Deallocate parameters after call for ccall;
+         -- 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)
+       pop_size | cconv /= StdCallConv = tot_arg_size
+                | otherwise
+#if darwin_TARGET_OS
+                 = arg_pad_size
+#else
+                 = 0
+#endif
+       
        call = callinsns `appOL`
                toOL (
-                       -- Deallocate parameters after call for ccall;
-                       -- but not for stdcall (callee does it)
-                  (if cconv == StdCallConv || tot_arg_size==0 then [] else 
-                  [ADD II32 (OpImm (ImmInt tot_arg_size)) (OpReg esp)])
+                  (if pop_size==0 then [] else 
+                  [ADD II32 (OpImm (ImmInt pop_size)) (OpReg esp)])
                   ++
                   [DELTA (delta + tot_arg_size)]
                )