[comp.sys.mac.programmer] Calling Assembly Language Subroutines from MPW C

milo@ndmath.UUCP (Greg Corson) (06/23/89)

Suddenly, for speed reasons, I find myself needing to write an assembly language
routine that can be called from my C program and passed arguments.

The assembly routine contains some special purpose graphics code and will need
to use almost all of the 68000's registers.

I haven't been able to find a good example of how to write an assembly
language routine that is callable from C and can be passed arguments from
the C program.  I also need to know what registers need to be saved in the
assembly routine and restored when it returns to the C caller.

If anybody has any examples of this, please send them on...I would REALLY
appreciate it.  A simple do-nothing program shell that shows how to get
an argument and shows what registers need to be saved would be very helpful.

I've programmed in 68000 assembly before, but the compiler I was using at the
time was setup to generate the calling sequence and register saves for me.
I've never tried to write a assembly subroutines under MPW.

Thanks for the help!


Greg Corson
19141 Summers Drive
South Bend, IN 46637
(219) 277-5306 
{pur-ee,rutgers,uunet}!iuvax!ndmath!milo
 

earleh@eleazar.dartmouth.edu (Earle R. Horton) (06/24/89)

In article <1455@ndmath.UUCP> milo@ndmath.UUCP (Greg Corson) writes:
>Suddenly, for speed reasons, I find myself needing to write an assembly language
>routine that can be called from my C program and passed arguments.
...
>I haven't been able to find a good example of how to write an assembly
>language routine that is callable from C and can be passed arguments from
>the C program.  I also need to know what registers need to be saved in the
>assembly routine and restored when it returns to the C caller.
...
>I've programmed in 68000 assembly before, but the compiler I was using at the
>time was setup to generate the calling sequence and register saves for me.
>I've never tried to write a assembly subroutines under MPW.

This is explained in Appendix N of the MPW Asm 2.0.2 manual,
"Structured Assembly Macros."  Using the macros defined in
ProgStrucMacs.a, one can generate functions callable from C or Pascal
which do the correct register saves, return values as appropriate, and
access the callers arguments.  Details may differ, but I feel sure
that this is also included in MPW Asm 3.0, which I would have if being
a graduate student were a more profitable way of spending my time.
The C manual describes which registers need to be saved.  The
importance of reading manuals cannot be mentioned too many times!

Example:

; This MPW Assembler code produces a function callable from
; MPW C.  It accepts four arguments, and returns the result
; of an arithmetic shift right on argument 1.

	CASE	ON			; So you can call "foo," not "FOO."
        Load    'ProgStrucMacs.d'       ; Assemble ProgStrucMacs.a
                                        ; to get this.  Put result in
					; {AIncludes}.

Export  Function        foo(arg1:L,arg2:L,arg3:L,arg4:L):L,C,Link=DEBUG
        ; Arguments default to word size, so need to specify L.
	; This is because C promotes function arguments to int (long).
	VAR	local1,local2:L	; Referenced off of A6, local1 word, local2 long
	BEGIN	SAVE=D2-D7/A2-A4	; Save these when called from MPW C
					; Save A5 if you need it.
	move.l	arg1(a6),local2(a6)	; Put first argument into
					; local stack frame
					; variable
	move.l	local2(a6),d0		; Load local variable into d0
	asr.l	#1,d0			; Arithmetic shift right by 1
	return	
	end

As you can see, generating a C callable function using these macros is
fairly convenient.  In this example, the assembler uses the macros to
generate a LINK instruction to reserve the correct size stack frame,
gives you access to the caller's arguments by named offset from A6,
generates an UNLK instruction, and even puts in a debugger label!

Notes:  C converts function arguments to type int, unless they are
floating point or data structures.  Pointer, char, short, int, and
long arguments can all be declared to be "L" in your assembler
function.  This is not true in Aztec C or Think C (I think).

If you prefer to code without macros, then your function arguments
will be located just above your return address when called, in the
order in which they are declared in the invocation line.  Any return
value may be placed in register D0.  To return, restore the stack
pointer to the same value as when called, execute an RTS.  Do not pop
arguments off the stack.

The following registers should have the same values as when you were
called, just before you do the RTS: d2-d7,a2-a7.

My example function is declared to return a long value ("):L,C...")
but this is only to remind me of the type result expected.  The return
value is explicitly stuffed into d0 for a C function.  This is because
I have tried to get the "return" value to return something in a C
function, and it didn't work.

This is all discussed, as I said, in the manuals, but maybe the
manuals are not that obvious to the beginning user.

The above can be called from MPW C by:

int foo(),result;

	result = foo(arg1,arg2,arg3,arg4);

I did assemble the example, and also wrote a little test program:

#include <stdio.h>
main(){printf("%d\n",foo(1024,0,0,0));}

This produces, no surprise:

512

Earle R. Horton
"People forget how fast you did a job, but they remember how well you
did it."  Salada Tag Lines

ira@Apple.COM (Ira Ruben) (06/24/89)

The article #7476 pretty well summarizes what you need to know about
calling assembly code from C.  However, the only thing I would recommend
is that you use CASE OBJ instead of CASE ON when using the MPW assembler
with C callers.

The reason for this is that CASE OBJ only preserves the casing of references
in the generated object file, which is all you need for the C calling
routine to "see" the called asm module.  In all other respects, the casing
is treated as the standard "ignore case" (actully upper case internally).
By doing this you don't have to warry about the casing of included files,
in particular, the Mac interface files.  With CASE ON you would.