simon@ms.uky.edu (G. Simon Gales) (08/01/89)
I'm trying to call some C functions from assembly, using MSC 5.0 and either MASM or TASM. I could write a dummy _main() in C, if this makes things easier, but I'm still not sure what needs to be setup to call a C subroutine. Can anyone clue me in on how to do this? -- Simon Gales@The University of Kentucky simon@ms.uky.edu | 'Fate... protects fools, little children, simon@UKMA.BITNET | and ships named Enterprise.' {rutgers, uunet}!ukma!simon | - Riker, ST:TNG
pgaughan@dante.nmsu.EDU (Patrick Gaughan) (08/01/89)
Well, I've done some stuff in this area...
The easiest way I can think of is to use the LARGE option on your C
compiler, declare the C functions as far labels and use far calls from
the assembly language routine.
Example:
/* c program */
#include <stdio.h>
int cfnct(a,b)
int a,b;
{
printf("a + b = %d\n",a+b);
return (a+b);
}
; asm program
( miscellaneous instructions )
EXTERN _cfcnt:FAR ; depending on linker, name may not be
. ; case sensitive
.
.
push b
push a
call cfcnt
add sp,4
(function return value in ax, if the function was a long or ptr
type, dx would return the upper half of the return value)
I'm pretty sure this is correct, but you'll have to try it and prove
it for yourself. Like most programmers, I don't memorize every rule,
but given a machine and I few tries at it, I can usually remember how
to do it.
Disclaimer: You're getting desperate if you think I have all the
right answers...
Patrick Gaughan
pgaughan@nmsu.edu
g-tookey@rocky.cs.wisc.edu. (Richard Schaut) (08/01/89)
In article <12324@s.ms.uky.edu> simon@ms.uky.edu (G. Simon Gales) writes: >I'm trying to call some C functions from assembly, using MSC 5.0 and either >MASM or TASM. I could write a dummy _main() in C, if this makes things >easier, but I'm still not sure what needs to be setup to call a C subroutine. > >Can anyone clue me in on how to do this? Sure. Given the following C function, foo(fparm1,fparm2,fparm3) you would need the following code to call (assuming the paramaters are ints) mov ax,[fparm3] push ax mov ax,[fparm2] push ax mov ax,[fparm1] push ax call foo add sp,3*INTSIZE Note that the parameters are pushed onto the stack in reverse order. As for how to retrieve the functions return value, you'l have to concult you compilers documentation. There is no set convention, however most use one of the CPU registers. If the routine doesn't return a value, then all you have to worry about is pushing the parameters onto the stack in reverse order, and restoring the stack when the routine is done. Rick Please send e-mail to: schaut@madnix.UUCP ArpaNet: madnix!schaut@cs.wisc.edu UseNet: ...uwvax!astroatc!nicmad!madnix!schaut {decvax!att}! Madison: an alternative to reality I am posting this through a friend's account. His consent to my use of his account in no way implies his consent to responsibility for the opinions expressed herein.
don@trsvax.UUCP (08/02/89)
>>I'm trying to call some C functions from assembly, using MSC 5.0 and either >>MASM or TASM. I could write a dummy _main() in C, if this makes things >>easier, but I'm still not sure what needs to be setup to call a C subroutine. >> >>Can anyone clue me in on how to do this? >[...] >Note that the parameters are pushed onto the stack in reverse order. As >for how to retrieve the functions return value, you'l have to concult >you compilers documentation. There is no set convention, however most ^^^^^^^^^^^^^^^^^^^^^^^^^^ >use one of the CPU registers. If the routine doesn't return a value, >then all you have to worry about is pushing the parameters onto the >stack in reverse order, and restoring the stack when the routine is done. Is this correct? I thought it was a well-established convention to place the return value in the AX register. Are there some commercial compilers which return it somewhere else? --------------------------------------------------------------------- Don Subt The opinions expressed above are Tandy Corp. strictly mine, not my employer's. 817-390-3068 ...!texbell!letni!rwsys!trsvax!don
hollen@zeta.megatek.uucp (Dion Hollenbeck) (08/02/89)
From article <12324@s.ms.uky.edu>, by simon@ms.uky.edu (G. Simon Gales): > I'm trying to call some C functions from assembly, using MSC 5.0 and either > MASM or TASM. I could write a dummy _main() in C, if this makes things > easier, but I'm still not sure what needs to be setup to call a C subroutine. > > Can anyone clue me in on how to do this? There is a section in the ref. manual dealing specifically with this, but I will summarize. Be aware that I am summarizing from memory and do not have the manual in front of me. I will address both calling C functions from assembly and assembly being called by C. Calling C from Assembly. ======================= Pseudocode the calling interface so you know the order of the arguements. Push the arguements onto the stack from right to left and push multi-word args (floats, far ptrs....) from high to low. Be sure of your memory model so that you can have the segment registers OK. Some memory models ASSUME ES = DS so you must make it so before calling C functions. For instance the tiny memory model assumes that CS = DS = ES = SS. Results are returned in registers. A char in AL, a short int in AX, a long int or float in AX/BX (low order in BX), and a double in AX, BX, CX, DX high order in AX to low order in DX. Calling Assembly from C. ======================== Here is a code fragment for ASM being called by C. ;; FUNCTION ;; read_ee_raw (ee_offset, numbytes, destination) ;; ;; int ee_offset ARG1 ;; int num_bytes ARG2 ;; char far *destination ARG3 - offset ;; ARG4 - segment PUBLIC READ_EE_RAW READ_EE_RAW PROC NEAR PUSH BP ;set up frame pointer MOV BP,SP PUSH AX ;save registers used PUSH DI PUSH SI PUSH DS PUSH ES LDS SI,[EEPROM_BASE] ;get seg:off ptr to EEPROM base MOV AX,[BP+ARG1] ;get byte offset into EEPROM SHL AX,1 ;make word offset ADD SI,AX ;add to base offset MOV DI,[BP+ARG3] ;get offset to destination MOV AX,[BP+ARG4] ;get segment of destination MOV ES,AX ;get in dest segreg MOV CX,[BP+ARG2] ;get count of bytes to read EEPROM_READ_LOOP: LODSW ;read word - high byte is junk STOSB ;write byte LOOP EEPROM_READ_LOOP ;continue until done POP ES ;restore registers used POP DS POP SI POP DI POP AX POP BP ;restore frame pointer RET READ_EE_RAW ENDP No other explanation should be necessary except to say to read the manual to be sure what registers should be saved and restored. You cannot go wrong by saving/restoring all you use. Dion Hollenbeck (619) 455-5590 x2814 Megatek Corporation, 9645 Scranton Road, San Diego, CA 92121 uunet!megatek!hollen or hollen@megatek.uucp
ralerche@lindy.Stanford.EDU (Robert A. Lerche) (08/03/89)
A thing to watch out for when interfacing C and Assembler... the direction flag! Microsoft C's "memcpy" _assumes_ the direction flag is clear (i.e., it doesn't do its own CLD before a REP MOVS). Be sure to clear the direction flag before calling a C routine and clear it if you set it in your own assembler routine -- otherwise havoc can ensue.
t-davidw@microsoft.UUCP (David Weigant) (08/04/89)
In article <663@megatek.UUCP> hollen@zeta.megatek.uucp (Dion Hollenbeck) writes: >From article <12324@s.ms.uky.edu>, by simon@ms.uky.edu (G. Simon Gales): >> I'm trying to call some C functions from assembly, using MSC 5.0 and either > >Results are returned in registers. A char in AL, a >short int in AX, a long int or float in AX/BX (low order in BX), ^ I believe you ment AX/DX for a long int or float. (High order or segment in DX, low order or offset in AX). Other things you might watch out for include C prefixing all variables and function names with an underscore. To get them to link properly you will have to use an underscore in your assembly code. Also, you need to remember that in C, the calling routine needs to clear the stack of any parameters passed into the function. For instance, if you push an integer onto the stack and call a C function, you need to pop the stack upon return from the function to remove the integer. Hope this helps David Weigant
g-tookey@rocky.cs.wisc.edu. (Richard Schaut) (08/04/89)
In article <216100115@trsvax> don@trsvax.UUCP writes: > >>>I'm trying to call some C functions from assembly, using MSC 5.0 and either >>>MASM or TASM. I could write a dummy _main() in C, if this makes things >>>easier, but I'm still not sure what needs to be setup to call a C subroutine. >>> >>>Can anyone clue me in on how to do this? > >>[...] >>Note that the parameters are pushed onto the stack in reverse order. As >>for how to retrieve the functions return value, you'l have to consult >>you compilers documentation. There is no set convention, however most > ^^^^^^^^^^^^^^^^^^^^^^^^^^ >>use one of the CPU registers. > >Is this correct? I thought it was a well-established convention to place >the return value in the AX register. Are there some commercial compilers >which return it somewhere else? Most reputable compilers use AX for 16 bit values and AX DX for 32 bit values, but the off-brand compilers may use something else. Also, once the size of the return value gets larger than 32 bits, then all bets are off (I've even seen some compilers use the stack, e.g. MIX C under CP/M). The safest thing is to not make any assumptions whatsoever about how functions return values for a given compiler. If the compiler's documentation is silent on the subject, then it's best to drop the whole thing in /dev/nul and get a real compiler. Rick Please send e-mail to: schaut@madnix.UUCP ArpaNet: madnix!schaut@cs.wisc.edu UseNet: ...uwvax!astroatc!nicmad!madnix!schaut {decvax!att}! Madison: an alternative to reality I am posting this through a friend's account. His consent to my use of his account in no way implies his consent to responsibility for the opinions expressed herein.