Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!bloom-beacon!bu-cs!dartvax!eleazar.dartmouth.edu!earleh From: earleh@eleazar.dartmouth.edu (Earle R. Horton) Newsgroups: comp.sys.mac.programmer Subject: Re: Calling Assembly Language Subroutines from MPW C Keywords: MPW, C, Assembly, 68000 Message-ID: <14062@dartvax.Dartmouth.EDU> Date: 23 Jun 89 19:19:03 GMT References: <1455@ndmath.UUCP> Sender: news@dartvax.Dartmouth.EDU Reply-To: earleh@eleazar.dartmouth.edu (Earle R. Horton) Organization: Thayer School of Engineering Lines: 96 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 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