jvkelley@watcgl.waterloo.edu (Jeff Kelley) (08/10/88)
[ To reread the original article, use ^P in rn (is this hypertext?) ] >Can anyone confirm/deny this hunch for me, or better yet tell me exactly >how parameters are handled? > Exec does not concern itself with the parameters, the mechanism by which they are passed to the library is purely a convention between the assembler routine that you link with and the .library. Traditionally, the assembler routine takes the parameters off the stack (where they were put when you called it from your C code) and puts them into the registers the .library code is expecting them in (at the back of the Exec RKM you can find the specifications for 1.1 library functions). Another convention is that pointers should be passed in address registers, everything else in data registers, but this isn't always followed (e.g. dos.library). Both these conventions were adopted, I presume, to optimize the speed potential of the library code. You can, however, define your own convention for passing arguments to your .library. If you are writing the .library in C, it may be convenient to decree that all arguments will be passed on the stack. Your assembler routine would then only need to 'JMP' (not 'JSR') to the appropriate .library vector. That library vector could then 'JMP' directly to your .library function written in C. This avoids the wastage of time (and space) needlessly taking parameters from the stack and putting them in registers only to push the register values back on the stack again. It would be nice if the Lattice C '#pragma libcall' feature would support this method of passing parameters, as it currently only supports the pass-in-register model (which is, admittedly, adequate for the system libraries). -- Jeff Kelley Graphics Lab, Dept. of Computer Science, University of Waterloo uunet!watmath!watcgl!jvkelley tel: (519) 578-4514 "Remember, this is not a competition, only an exhibition. Please, no wagering." - David Letterman
ditto@cbmvax.UUCP (Michael "Ford" Ditto) (08/10/88)
In article <3716@hcr.UUCP> edwin@hcr.UUCP (Edwin Hoogerbeets) writes: >I am working on interfacing C routines to Amiga shared librhcr, and I >need some help. [ describes function's paramters in C calling conventions ] >However, if I have the routine _foo in my library, in which registers >can I expect the Exec to put the parameters to _foo when calling it in >the library? The reason I want to know this is so that I may push these >values on to the stack again to call a C routine. Exec doesn't do anything at all to the paramters to a library function. In fact, Exec never even gets control during a library call: the calling program just does a "jsr offset(basereg)" directly to the code (offset defines which function in the library to call, basereg is a register that points to the base of the library). In other words, you, the designer of the library, determine the calling conventions of each routine in the library. If you want to just use C conventions all the way, go ahead, but you will still need a "stub" interface so that your compiler can jsr to _functionname which will do something like "move yourlibbase,basereg; jmp offset(basereg)". >I have looked in the RKM's and found nothing specific about that, but >from observation it seems that pointers are in the a[0|1] registers and >values go in the d[0|1] registers. What happens if there are more than 4 >parameters? This is a sort of "convention" which makes it easier to remember the calling sequences of library function... if your function will only be called from C, and you will be providing the "stubs" for other programmers to use, then it really doesn't matter what conventions you choose. -- -=] Ford [=- . . (In Real Life: Mike Ditto) . : , ford@kenobi.cts.com This space under construction, ...!ucsd!elgar!ford pardon our dust. ditto@cbmvax.commodore.com
carolyn@cbmvax.UUCP (Carolyn Scheppner CATS) (08/11/88)
In article <3716@hcr.UUCP> edwin@hcr.UUCP (Edwin Hoogerbeets) writes: > >I am working on interfacing C routines to Amiga shared librhcr, and I >need some help. > >A certain function is declared like this in C: > >LONG foo (alpha, bravo, charlie, delta) >LONG alpha, charlie; >struct boing *bravo, *delta; > >where 'struct boing' is some random structure unimportant to this >question. This function is actually an assembler routine in a library >that will take parameters as this declaration suggests. > >However, if I have the routine _foo in my library, in which registers >can I expect the Exec to put the parameters to _foo when calling it in >the library? The reason I want to know this is so that I may push these >values on to the stack again to call a C routine. > >I have looked in the RKM's and found nothing specific about that, but >from observation it seems that pointers are in the a[0|1] registers and >values go in the d[0|1] registers. What happens if there are more than 4 >parameters? 1. A0|1 and D0|1 are used alot for parameter passing because these registers are allowed to be trashed when you call a system routine. Programs can count on D2-D7 and A2-A7 being preserved when they call a system routine. Therefore, if any system routine requires args in any of these registers, the interface code in Amiga.lib must save these registers, pass the args in them, then restore them before returning. 2. It's kind of weird, but here's how it works if you have a C function calling a C routine in a run-time shared library: (hypothetical graphics.library BltOverEasy call) C program does OpenLibrary of graphics.library and stores Base address in globally visible GfxBase variable. C program calls BltOverEasy(lots,of,weird,things,and,more) which causes the args to be pushed on the stack as longs Assembler _BltOverEasy stub in Amiga.lib saves A6 and any untrashable registers needed for passing args to system BltOverEasy code, loads up the appropriate (individual to each function) registers with the arguments from the stack, puts GfxBase in A6, does jsr _LVOBltOverEasy(a6) (_LVOBltOverEasy being a negative hex word constant defined in Amiga.lib, and being the negative offset of the BltOverEasy entry in the GfxBase library jump table - note that these jump tables exist in memory preceding the library Base structure). The jsr hits the jump table which does (generally) a JMP to the rom (or ram) location of the actual library function code, at least the beginning of which is in assembler. Then, if the bulk of the library function happens to be in C, the assembler portion takes the args OUT of the registers, pushes them back on the stack, and jsr's to the C part of the library function. Then fixes the stack pointer when it returns. When all is done, the library function does an RTS with the result in d0. This returns to the stub code in Amiga.lib, which restores all untrashable registers, leaving the result in d0, and does an RTS which returns you to the C program. Note that this may seem like a lot of swapping around, but since the library calls expect their parameters in registers, it means that an assembler program calling a system function can just put the library base in A6, the args in registers, and jsr _LVOBltOverEasy. The current Amiga compilers provide methods for bypassing the Amiga.lib step, instead generating inline code to put your args directly in the appropriate registers and call the _LVO. I believe Manx does this via hard-coded interface code of their own, while Lattice does it via pragma files which are similar to include files but define which register should receive each argument. NOTE - See the couple of pages of text right before the library autodocs in the RKM (any version) for an example of the type of stub code in Amiga.lib. It's enough info to write your own mylib.lib linker lib for calling your own run-time library functions from C. -- ========================================================================== Carolyn Scheppner -- CATS Commodore Amiga Technical Support PHONE 215-431-9180 UUCP ...{uunet,allegra,rutgers}!cbmvax!carolyn Pad with zeros for a light, airy program. ==========================================================================