foreign export dynamic for MacOS X
Wolfgang Thaller
wolfgang.thaller@gmx.net
Wed, 17 Apr 2002 12:02:25 +0200
I recently added PowerPC thunk creation to GHC, and I thought it
would also be useful for hugs.
Cheers,
Wolfgang Thaller
--- for src/builtin.c:
struct thunk_data {
struct thunk_data* next;
struct thunk_data* prev;
HugsStablePtr stable;
#if defined(__ppc__)
char code[13*4];
#else
char code[16];
#endif
};
struct thunk_data* foreignThunks = 0;
static void* mkThunk(void* app, HugsStablePtr s) {
struct thunk_data* thunk
= (struct thunk_data*)malloc(sizeof(struct thunk_data));
char* pc;
if (!thunk) {
/* ToDo: better cleanup */
printf("Can't allocate thunk for foreign export dynamic\n");
exit(1);
}
if (foreignThunks) { /* non-empty list */
foreignThunks->prev = thunk;
}
thunk->next = foreignThunks;
thunk->prev = 0;
foreignThunks = thunk;
thunk->stable = s;
pc = &thunk->code[0];
#if defined(__i386__)
/* 3 bytes: pushl (%esp) */
*pc++ = 0xff; *pc++ = 0x34; *pc++ = 0x24;
/* 8 bytes: movl s,4(%esp) */
*pc++ = 0xc7; *pc++ = 0x44; *pc++ = 0x24; *pc++ = 0x04;
*((HugsStablePtr*)pc)++ = s;
/* 5 bytes: jmp app */
*pc++ = 0xe9;
*((int*)pc)++ = (char*)app - ((char*)&(thunk->code[16]));
#elif defined(__ppc__) && defined(__GNUC__)
/* This is only for MacOS X.
* It does not work on MacOS 9 because of the very strange
* handling of function pointers in OS 9.
* I don't know about LinuxPPC calling conventions.
* Please note that it only works for up to 7 arguments.
*/
{
unsigned long *adj_code = (unsigned long*)pc;
// make room for extra arguments
adj_code[0] = 0x7d2a4b78; //mr r10,r9
adj_code[1] = 0x7d094378; //mr r9,r8
adj_code[2] = 0x7ce83b78; //mr r8,r7
adj_code[3] = 0x7cc73378; //mr r7,r6
adj_code[4] = 0x7ca62b78; //mr r6,r5
adj_code[5] = 0x7c852378; //mr r5,r4
adj_code[6] = 0x7c641b78; //mr r4,r3
adj_code[7] = 0x3c000000; //lis r0,hi(app)
adj_code[7] |= ((unsigned long)app) >> 16;
adj_code[8] = 0x3c600000; //lis r3,hi(s)
adj_code[8] |= ((unsigned long)s) >> 16;
adj_code[9] = 0x60000000; //ori r0,r0,lo(app)
adj_code[9] |= ((unsigned long)app) & 0xFFFF;
adj_code[10] = 0x60630000; //ori r3,r3,lo(s)
adj_code[10] |= ((unsigned long)s) & 0xFFFF;
adj_code[11] = 0x7c0903a6; //mtctr r0
adj_code[12] = 0x4e800420; //bctr
pc = (char*) &adj_code[13];
// Flush the Instruction cache:
//MakeDataExecutable(adjustor,4*13);
/* This would require us to link with CoreServices.framework */
{ /* this should do the same: */
int n = 13;
unsigned long *p = adj_code;
while(n--)
{
__asm__ volatile ("dcbf 0,%0\n\tsync\n\ticbi 0,%0"
: : "g" (p));
p++;
}
__asm__ volatile ("sync\n\tisync");
}
}
#else
ERRMSG(0) "Foreign export dynamic is not supported on this architecture"
EEND;
#endif
assert(pc <= &thunk->code[0] + sizeof(thunk->code));
return &thunk->code; /* a pointer into the middle of the thunk */
}