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.