Interface with C

John van Groningen johnvg@cs.kun.nl
Tue, 9 Jun 1998 11:33:21 +0200


Alan Grover wrote:
>Certainly there is a place to specify the libraries you want to link to.
>But the "code" keyword and the way you specify the interface is not quite
>clear to me. Here is an example from the existing interfaces for the Mac:
>
>SizeWindow :: !WindowPtr !Int !Int !Bool !*Toolbox -> *Toolbox;
>SizeWindow theWindow w h fUpdate t =3D code
>(theWindow=3DD0,w=3DD1,h=3DD2,fUpdate=3DD3,t=3DU)(z=3DZ){
>        call    .SizeWindow
>};

On the PowerMac there are 2 low level interfaces, the interface to the=
 toolbox that was implemented for the 68k to call OS functions and a C=
 interface that is similar to the C interface for other processors. The=
 toolbox interface uses 'code (inputparameters)(outputparameters){' followed=
 by a 'call' and sometimes some 'instruction 0xhexdigits' lines. The C=
 interface uses 'code {' followed by a 'ccall' instruction.

The characters after an input parameter name and =3D describe the interface:
W means push a word (16 bits) on the stack.=20
L means push a long word (32 bits) on the stack.
Dn means move the parameter to register 3+n (on the PowerPC). The calling=
 convention use by the C compiler passes the first argument in r3, the next=
 in r4, ... So D0 is the first argument, D1 is the second,..
U means not used.

>For you non-Mac people, Toolbox is an environment for the Mac API. I've
>deduced that the "code" associates the arguments with the PowerPC registers
>as appropriate for the  call. The "t" and "z" aren't part of the real
>SizeWindow function. I haven't spent enough time to figure out what "t=3DU"
>and "z=3DZ" is for (oh, "t" is the Toolbox). Also, I don't have the
>references that tell what registers are used for what. Also, I do not know
>the calling conventions on the PPC (I used to know them for the 68k), so I
>don't know how to call my own C routines.

Z for output parameters means the result is zero. The names of the output=
 parameters are irrelevant.

C functions can be called in the following way:

f :: !Int !Int -> Int;
f a b =3D code {
        ccall f "II-I"
}

will call:

int f (int,int);

g :: !Int !Int -> (!Int,!Int);
g a b =3D code {
        ccall g "II-II"
}

will call:

void g (int,int,int*,int*);

To pass a string to C use S instead of I in the last parameter of ccall. In=
 C you get a pointer into the Clean heap. This pointer points to a 32 bit=
 length value, followed by the characters.

We are working on a tool that will generate these low level c interfaces=
 from a .h file with some additional type information in Clean.

>Here is a slightly more interesting one, showing some inline assembly:
>
>NewWindow :: !Ptr !Rect !{#Char} !Bool !Int !WindowPtr !Bool !Int !*Toolbox
>-> (!WindowPtr,!*Toolbox);
>NewWindow wStorage (left,top,right,bottom) title visible procID behind
>goAwayFlag refCon t
>=3D code (right=3DW,bottom=3DW,left=3DW,top=3DW,wStorage=3DD0,title=3DO0D1S=
D2,visible=3DD3,
>                  procID=3DD4,behind=3DD5,goAwayFlag=3DD6,refCon=3DD7,t=3DU=
)
>(window_pointer=3DD0,z=3DI8Z)
>{
>        instruction     0x7CC600D0      |       neg     r6,r6
>        instruction     0x7D2900D0      |       neg     r9,r9
>        call    .NewWindow
>};
>
>What the heck is that "00D1SD2"?

O0D1 means load the stack offset stackpointer+0 in register r4 (3+1).
SD2 means load the address of the pascal string in register r5 (3+2). This=
 address is the address of the string in the heap + 7. The first byte is the=
 length mod 256, the next bytes are the characters of the string. There is=
 no '\0' at the end.=20
I8 means increase the stackpointer by 8.
Rn means decrease the stackpointer by n (reserve stack space).

John van Groningen