rts/base: Fix #9423
[ghc.git] / includes / Stg.h
index 4faed91..9edb6a0 100644 (file)
@@ -19,7 +19,7 @@
  * "Rts.h" instead.
  *
  * To understand the structure of the RTS headers, see the wiki:
- *   http://hackage.haskell.org/trac/ghc/wiki/Commentary/SourceTree/Includes
+ *   http://ghc.haskell.org/trac/ghc/wiki/Commentary/SourceTree/Includes
  *
  * ---------------------------------------------------------------------------*/
 
@@ -213,23 +213,50 @@ typedef StgFunPtr       F_;
 #define II_(X)          static StgWordArray (X) GNU_ATTRIBUTE(aligned (8))
 #define IF_(f)    static StgFunPtr GNUC3_ATTRIBUTE(used) f(void)
 #define FN_(f)    StgFunPtr f(void)
-#define EF_(f)    extern StgFunPtr f(void)
+#define EF_(f)    extern StgFunPtr f()   /* See Note [External function prototypes] */
+
+/* Note [External function prototypes]  See Trac #8965
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The external-function macro EF_(F) used to be defined as
+    extern StgFunPtr f(void)
+i.e a function of zero arguments.  On most platforms this doesn't
+matter very much: calls to these functions put the parameters in the
+usual places anyway, and (with the exception of varargs) things just
+work.
+
+However, the ELFv2 ABI on ppc64 optimises stack allocation
+(http://gcc.gnu.org/ml/gcc-patches/2013-11/msg01149.html): a call to a
+function that has a prototype, is not varargs, and receives all parameters
+in registers rather than on the stack does not require the caller to
+allocate an argument save area.  The incorrect prototypes cause GCC to
+believe that all functions declared this way can be called without an
+argument save area, but if the callee has sufficiently many arguments then
+it will expect that area to be present, and will thus corrupt the caller's
+stack.  This happens in particular with calls to runInteractiveProcess in
+libraries/process/cbits/runProcess.c, and led to Trac #8965.
+
+The simplest fix appears to be to declare these external functions with an
+unspecified argument list rather than a void argument list.  This is no
+worse for platforms that don't care either way, and allows a successful
+bootstrap of GHC 7.8 on little-endian Linux ppc64 (which uses the ELFv2
+ABI).
+*/
+
 
 /* -----------------------------------------------------------------------------
    Tail calls
-
-   This needs to be up near the top as the register line on alpha needs
-   to be before all procedures (inline & out-of-line).
    -------------------------------------------------------------------------- */
 
-#include "stg/TailCalls.h"
+#define JMP_(cont) return((StgFunPtr)(cont))
+#define FB_
+#define FE_
 
 /* -----------------------------------------------------------------------------
    Other Stg stuff...
    -------------------------------------------------------------------------- */
 
 #include "stg/DLL.h"
-#include "stg/MachRegs.h"
+#include "stg/RtsMachRegs.h"
 #include "stg/Regs.h"
 #include "stg/Ticky.h"
 
@@ -241,6 +268,7 @@ typedef StgFunPtr       F_;
 #include "stg/MiscClosures.h"
 #endif
 
+#include "stg/Prim.h" /* ghc-prim fallbacks */
 #include "stg/SMP.h" // write_barrier() inline is required
 
 /* -----------------------------------------------------------------------------
@@ -257,7 +285,7 @@ typedef StgFunPtr       F_;
 INLINE_HEADER void     ASSIGN_FLT (W_ [], StgFloat);
 INLINE_HEADER StgFloat    PK_FLT     (W_ []);
 
-#if ALIGNMENT_FLOAT <= ALIGNMENT_LONG
+#if ALIGNMENT_FLOAT <= ALIGNMENT_VOID_P
 
 INLINE_HEADER void     ASSIGN_FLT(W_ p_dest[], StgFloat src) { *(StgFloat *)p_dest = src; }
 INLINE_HEADER StgFloat PK_FLT    (W_ p_src[])                { return *(StgFloat *)p_src; }
@@ -278,9 +306,9 @@ INLINE_HEADER StgFloat PK_FLT(W_ p_src[])
     return(y.f);
 }
 
-#endif /* ALIGNMENT_FLOAT > ALIGNMENT_LONG */
+#endif /* ALIGNMENT_FLOAT > ALIGNMENT_VOID_P */
 
-#if ALIGNMENT_DOUBLE <= ALIGNMENT_LONG
+#if ALIGNMENT_DOUBLE <= ALIGNMENT_VOID_P
 
 INLINE_HEADER void     ASSIGN_DBL (W_ [], StgDouble);
 INLINE_HEADER StgDouble   PK_DBL     (W_ []);
@@ -288,7 +316,7 @@ INLINE_HEADER StgDouble   PK_DBL     (W_ []);
 INLINE_HEADER void      ASSIGN_DBL(W_ p_dest[], StgDouble src) { *(StgDouble *)p_dest = src; }
 INLINE_HEADER StgDouble PK_DBL    (W_ p_src[])                 { return *(StgDouble *)p_src; }
 
-#else /* ALIGNMENT_DOUBLE > ALIGNMENT_LONG */
+#else /* ALIGNMENT_DOUBLE > ALIGNMENT_VOID_P */
 
 /* Sparc uses two floating point registers to hold a double.  We can
  * write ASSIGN_DBL and PK_DBL by directly accessing the registers