From: absurd@apple.apple.com (Tim Dierks, software saboteur)
Subject: Re: help calling assembly from C
Date: Tue, 26 Jan 1993 22:57:21 GMT
Distribution: usa
Organization: MacDTS Marauders
Followup-To: comp.sys.mac.programmer

In article <keith-240193173019@kip-50.taligent.com>, keith@taligent.com
(Keith Rollin) wrote:
> 
> In article <2B6198C1.22487@news.service.uci.edu>, eapg070@orion.oac.uci.edu
> (Caroll Elke Pohl) wrote:
> > 
> > i wonder if someone out there can assist me with a small problem.
> > i'm using MPW (3.2) and want to call an assembly language subroutine
> > i wrote from a C program _however_ i want to pass the parameters in
> > A0 and A1 instead of using the stack (much like certain memory
> > manager traps). how can i get the C compiler to recognize this fact?
> 
> You came really close to answering your own question. You know that there
> are Mac OS functions that work like this, so why don't you declare your
> function the same way they are? For instance:
> 
> #pragma parameter DisposePtr(__A0)
> pascal void DisposePtr(Ptr p); 
> 
> This is an example of a function that simply takes a parameter in A0.
> Here's a more complex example:
> 
> #pragma parameter __D0 HoldMemory(__A0,__A1)
> pascal OSErr HoldMemory(void *address,unsigned long count); 
> 
> HoldMemory takes the first parameter ("address") in A0, and the second
> parameter ("count") in A1. It returns its result in D0 (which will be
> treated like a short, because the function is declared to return an OSErr).
> 
> -----
> Keith Rollin
> Phantom Programmer
> Taligent, Inc.

Unfortunately, MPW doesn't currently work this way (please correct me
if I'm wrong).  While it does use the #pragma register syntax to specify
register passing, I believe it only works for hex inlined functions;
i.e., it's only useful for specifying Toolbox calls or other code
that doesn't require linking, because you can't specify symbols.
This means that if your assembly routine is short (or even if it's not),
you can assemble it, convert it to a bunch of hex constants, and
define it in the same way MPW defines inline code:

#pragma parameter __D0 MyWackyFunction(__A0)
long MyWackyFunction(char *data) = {0xDEAD, 0xFACE, 0xBABE};

or whatever your hex constants are.  This should work as long as your
assembly routine doesn't call other routines or refer to global
variables; i.e., any routine which is entirely self-contained.
Also, your function needs to take its arguments in particular
registers: #pragma parameter can only pass arguments or get
results in the "scratch" registers: D0, D1, D2, A0, and A1.

This approach obviously isn't for all code.  You've got two alternatives:
the best one is just to write a little routine in assembly which pulls
the arguments for the function off of the stack and puts them into
registers, then calls the function, or convert your function so it
takes its parameters on the stack.  An alternative is to use a hex
inlined function which takes its destination in a register and JSRs
to it:

#pragma parameter __D0 CallMyWackyFunction(__A0,__A1)
long CallMyWackyFunction(char *data,void *myWackyFunctionPtr) = 0x4E91;

(0x4E91 is the hex opcode for a JSR (A1)).  You can call this like so:

result = CallMyWackyFunction(data,MyWackyFunction);

By passing a pointer to the routine you wish to call, this avoids the
problem that the hex inline can't call the function itself because
it can't contain symbols that need to be linked.

Hope all this helps;
Tim Dierks
MacDTS, but I speak for myself
Newsgroups: comp.sys.mac.programmer