Marcel,
The use of 'addr' as indirect pointer is due to a pretty stupid definition in the MacOS (pre X) runtime architecture. The code fragment architecture exports an entry vector consisting of the actual function address (the indirection you see) and the frame base for the function you're calling, rather than adding a bit of glue code for each function that loads the frame pointer when the fragment is entered. Since the caller has to load the frame pointer before entering a fragment this leads to the situation that the C compiler generates (for each function call through a pointer) a call that actually goes to the infamous .ptr_glue which is basically what you see in the FFI code.[Note: the really, REALLY stupid thing is that this requires the C compiler to call .ptr_glue even in cases where the call does not go cross-fragment. You can probably imagine what that means for, e.g., a primitive dispatch table, or a table of combination rules].
I do not know if this has changed with MacOS X (I sure hope so). You will need to dig deep down in the documentation for this (I have no info whatsoever on this issue) to find out. The best way I can think of is to check the assembly code that GCC generates for a function call through a pointer, e.g., for something like:
int testFunc(int addr) { return ((int (*) (void)fn)(); }
- Andreas
-----Original Message----- From: Marcel Weiher [mailto:marcel@metaobject.com] Sent: Thursday, March 30, 2000 2:15 PM To: squeak@cs.uiuc.edu Cc: recipient list not shown Subject: FFI for MacOS-X-Server
Hi folks,
I am currently working on getting FFI up and running on MacOS-X-Server.
As the assembly calling conventions are AFAIK the same as for MacOS (having been taken from AIX), I used Andreas's Mac code as a starting point. However, the gcc inline assembly mechanism is not identical to the one used there, so I've had to adapt the function ffiCallAddressOf().
It's mostly working now, but there are some points of the code I am unclear about, mostly the commented out parts where the original code treated the 'addr' argument as an indirect pointer. Is this correct? On my machine, the address that gets passed here is the direct address of the functin in question (which is why it works no that I've commented out the indirection). There is some code related to this that I've also removed, primarily dealing with GPR2 (frame pointer?) and putting other stuff relative to the "indirect address" argument.
Can anyone shed light on this?
Thanks,
Marcel
---------- ffiCallAddressOf() as modified for gcc/MacOS-X-Server ------
int ffiCallAddressOf(int addr) { int stackBytes = ffiStackIndex*4; int stackGrowth = stackBytes+24; void **destination; int i; printf("addr= %d %x\n",addr,addr); stackGrowth=-stackGrowth;
/* adjust stack frame */ asm( "stwux r1, r1, %0" : : "r" (stackGrowth) ); /* load the stack frame area */
asm( "addi %0, r1, 24 " : "=r" (destination) : ); /* dst
= SP + linkage area */ for (i=0;i<ffiStackIndex;i++ ) { destination[i]=ffiStack[i]; }
if ( fpRegCount > 0 ) { if ( fpRegCount > 8 ) { asm( "lfd f8, %0" : : "" (FPRegs[7])); asm( "lfd f9, %0" : : "" (FPRegs[8])); asm( "lfd f10, %0" : : "" (FPRegs[9])); asm( "lfd f12, %0" : : "" (FPRegs[10])); asm( "lfd f12, %0" : : "" (FPRegs[11])); asm( "lfd f13, %0" : : "" (FPRegs[12])); } asm( "lfd f1, %0" : : "" (FPRegs[0])); asm( "lfd f2, %0" : : "" (FPRegs[1])); asm( "lfd f3, %0" : : "" (FPRegs[2])); asm( "lfd f4, %0" : : "" (FPRegs[3])); asm( "lfd f5, %0" : : "" (FPRegs[4])); asm( "lfd f6, %0" : : "" (FPRegs[5])); asm( "lfd f7, %0" : : "" (FPRegs[6])); } if ( gpRegCount > 0 ) { if ( gpRegCount > 4 ) { asm( "lwz r7, %0" : : "" (GPRegs[4])); asm( "lwz r8, %0" : : "" (GPRegs[5])); asm( "lwz r9, %0" : : "" (GPRegs[6])); asm( "lwz r10, %0" : : "" (GPRegs[7])); } asm( "lwz r3, %0" : : "" (GPRegs[0])); asm( "lwz r4, %0" : : "" (GPRegs[1])); asm( "lwz r5, %0" : : "" (GPRegs[2])); asm( "lwz r6, %0" : : "" (GPRegs[3])); }
/* go calling out */ asm( "mr r12, %0 " : : "r" (addr) ); /* tvector into GPR12 */ /* Note: The code below is nearly identical to to what's described in "MacOS Runtime Architectures" Chapter 2, Listing 2-2, pp. 2-11 */ // asm( "lwz r0, 0(r12) "); /* get entry point */ ?? // asm( "stw r2, 20(r1) "); /* save GPR2 */ ?? asm( "mtctr r12 "); /* move entry point into count register */ // asm( "lwz r2, 4(r12) "); /* new base pointer */ asm( "bctrl "); /* jump through count register and link */ // asm( "lwz r2, 20(r1)" ); /* restore GPR2 */ asm( "lwz r1, 0(r1)" ); /* restore frame */
/* store the result of the call */ asm( "stw r3,%0" : "=g" (intReturnValue) : ); asm( "lwz r12,%0" : : "" (longReturnValue) ); // asm( "stw r3, 0(r12)"); // asm( "stw r4, 4(r12)"); asm( "stfd f1,%0" : "=g" (floatReturnValue) : );
}
squeak-dev@lists.squeakfoundation.org