From 9f121f6cd018f4d60c119b934a875d3b9e613cd0 Mon Sep 17 00:00:00 2001 From: wolfgang Date: Mon, 12 Sep 2005 00:10:09 +0000 Subject: [PATCH] [project @ 2005-09-12 00:10:09 by wolfgang] Darwin/x86: Maintain 16-byte alignment for foreign import wrapper calls. --- ghc/rts/Adjustor.c | 93 ++++++++++++++++++++++++++++++++++++++----------- ghc/rts/AdjustorAsm.S | 43 +++++++++++++++++++++++ ghc/rts/Makefile | 6 ++-- 3 files changed, 119 insertions(+), 23 deletions(-) diff --git a/ghc/rts/Adjustor.c b/ghc/rts/Adjustor.c index ea4923a..f0d66c0 100644 --- a/ghc/rts/Adjustor.c +++ b/ghc/rts/Adjustor.c @@ -55,7 +55,7 @@ Haskell side. #else #define UNDERSCORE "" #endif -#if defined(i386_HOST_ARCH) +#if defined(i386_HOST_ARCH) && !defined(darwin_HOST_OS) /* Now here's something obscure for you: @@ -196,6 +196,49 @@ typedef struct AdjustorStub { #endif #endif +#if defined(i386_HOST_ARCH) && defined(darwin_HOST_OS) + +/* !!! !!! WARNING: !!! !!! + * This structure is accessed from AdjustorAsm.s + * Any changes here have to be mirrored in the offsets there. + */ + +typedef struct AdjustorStub { + unsigned char call[8]; + StgStablePtr hptr; + StgFunPtr wptr; + StgInt frame_size; + StgInt argument_size; +} AdjustorStub; +#endif + +#if defined(darwin_HOST_OS) || defined(powerpc_HOST_ARCH) || defined(powerpc64_HOST_ARCH) +static int totalArgumentSize(char *typeString) +{ + int sz = 0; + while(*typeString) + { + char t = *typeString++; + + switch(t) + { + // on 32-bit platforms, Double and Int64 occupy two words. + case 'd': + case 'l': + if(sizeof(void*) == 4) + { + sz += 2; + break; + } + // everything else is one word. + default: + sz += 1; + } + } + return sz; +} +#endif + void* createAdjustor(int cconv, StgStablePtr hptr, StgFunPtr wptr, @@ -210,7 +253,7 @@ createAdjustor(int cconv, StgStablePtr hptr, switch (cconv) { case 0: /* _stdcall */ -#if defined(i386_HOST_ARCH) +#if defined(i386_HOST_ARCH) && !defined(darwin_HOST_OS) /* Magic constant computed by inspecting the code length of the following assembly language snippet (offset and machine code prefixed): @@ -243,7 +286,7 @@ createAdjustor(int cconv, StgStablePtr hptr, break; case 1: /* _ccall */ -#if defined(i386_HOST_ARCH) +#if defined(i386_HOST_ARCH) && !defined(darwin_HOST_OS) /* Magic constant computed by inspecting the code length of the following assembly language snippet (offset and machine code prefixed): @@ -289,6 +332,30 @@ createAdjustor(int cconv, StgStablePtr hptr, adj_code[0x0f] = (unsigned char)0xff; /* jmp *%eax */ adj_code[0x10] = (unsigned char)0xe0; } +#elif defined(i386_HOST_ARCH) && defined(darwin_HOST_OS) + { + /* + What's special about Darwin/Mac OS X on i386? + It wants the stack to stay 16-byte aligned. + + We offload most of the work to AdjustorAsm.S. + */ + AdjustorStub *adjustorStub = stgMallocBytesRWX(sizeof(AdjustorStub)); + adjustor = adjustorStub; + + extern void adjustorCode(void); + int sz = totalArgumentSize(typeString); + + adjustorStub->call[0] = 0xe8; + *(long*)&adjustorStub->call[1] = ((char*)&adjustorCode) - ((char*)adjustorStub + 5); + adjustorStub->hptr = hptr; + adjustorStub->wptr = wptr; + adjustorStub->frame_size = sz * 4 + 12 /* ebp save + extra args */; + adjustorStub->frame_size = (adjustorStub->frame_size + 15) & ~15; // align to 16 bytes + adjustorStub->frame_size -= 12; // we push the extra args separately + adjustorStub->argument_size = sz; + } + #elif defined(x86_64_HOST_ARCH) /* stack at call: @@ -810,24 +877,8 @@ TODO: Depending on how much allocation overhead stgMallocBytes uses for #endif // Calculate the size of the stack frame, in words. - while(*typeString) - { - char t = *typeString++; - - switch(t) - { -#if defined(powerpc_HOST_ARCH) - // on 32-bit platforms, Double and Int64 occupy two words. - case 'd': - case 'l': - sz += 2; - break; -#endif - // everything else is one word. - default: - sz += 1; - } - } + sz = totalArgumentSize(typeString); + // The first eight words of the parameter area // are just "backing store" for the parameters passed in // the GPRs. extra_sz is the number of words beyond those first diff --git a/ghc/rts/AdjustorAsm.S b/ghc/rts/AdjustorAsm.S index 3927843..b95e009 100644 --- a/ghc/rts/AdjustorAsm.S +++ b/ghc/rts/AdjustorAsm.S @@ -1,5 +1,7 @@ #include "../includes/ghcconfig.h" +/* ******************************** PowerPC ******************************** */ + #if defined(powerpc_HOST_ARCH) || defined(powerpc64_HOST_ARCH) #if !(defined(powerpc_HOST_ARCH) && defined(linux_HOST_OS)) /* The following code applies, with some differences, @@ -142,5 +144,46 @@ adjustorCode: mtlr r0 blr #endif + +/* ********************************* i386 ********************************** */ + +#elif defined(i386_TARGET_ARCH) && defined(darwin_TARGET_OS) + +#define WS 4 +#define RETVAL_OFF 5 +#define HEADER_BYTES 8 + +#define HPTR_OFF HEADER_BYTES +#define WPTR_OFF (HEADER_BYTES + 1*WS) +#define FRAMESIZE_OFF (HEADER_BYTES + 2*WS) +#define ARGWORDS_OFF (HEADER_BYTES + 3*WS) + + .globl _adjustorCode +_adjustorCode: + popl %eax + subl $RETVAL_OFF, %eax + + pushl %ebp + movl %esp, %ebp + + subl FRAMESIZE_OFF(%eax), %esp + + pushl %esi + pushl %edi + + leal 8(%ebp), %esi + leal 12(%esp), %edi + movl ARGWORDS_OFF(%eax), %ecx + rep + movsl + + popl %edi + popl %esi + + pushl HPTR_OFF(%eax) + call *WPTR_OFF(%eax) + + leave + ret #endif diff --git a/ghc/rts/Makefile b/ghc/rts/Makefile index 0d09e79..510bd9e 100644 --- a/ghc/rts/Makefile +++ b/ghc/rts/Makefile @@ -58,11 +58,13 @@ EXCLUDED_SRCS += Main.c endif # This file ends up being empty unless we're building for a powerpc -# system, and it is reported that Solaris ld chokes on it when building -# HSrts.o. +# or darwin system, and it is reported that Solaris ld chokes on it when +# building HSrts.o. ifeq "$(findstring $(TargetArch_CPP), powerpc powerpc64)" "" +ifeq "$(findstring $(TargetOS_CPP), darwin)" "" EXCLUDED_SRCS += AdjustorAsm.S endif +endif EXCLUDED_SRCS += parallel/SysMan.c -- 1.7.10.4