FFI for MacOS-X-Server

Raab, Andreas Andreas.Raab at disney.com
Fri Mar 31 01:54:08 UTC 2000


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 at metaobject.com]
> Sent: Thursday, March 30, 2000 2:15 PM
> To: squeak at 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) : );
> 
> }
> 





More information about the Squeak-dev mailing list