How to call C function from 16-bit assembler

Started by brookebree, November 03, 2008, 08:17:14 PM

Previous topic - Next topic

brookebree

I have been writing 16-bit assembly applications for years and now need to be able to call some c code from my assembly code.  A  guy that has written the c code that I need is totally changing my assembly by changing my stack setup, data segment names, my near procs to far  procs, changing my .obj link order,etc which has all resulted in various problems with my .asm programs  which which won't work with all his changes to my .asm.

Is there an easier way to call a c function from 16-bit assembly without all these C overhead changes that I'm told have to be made to my .asm?   Can I just include the c.obj in my link and call c function as a far call in my code, or is there much more involved in doing this as this c guy is telling me.   code sample would be appreciated.   I use Microsoft MASM v6.11, Link v5.60 for my assmbly & using Turbo-C version 2.01 for the new c stuff I'm trying to call from my .asm.

thanks in advance - Dale

MichaelW

#1
I don't know what sort of programming style you use, but assuming that you take advantage of the MASM features intended to support mixed-language programming, and assuming that the C code uses standard memory models and calling conventions, calling C functions from your source should not be difficult. Here is a quick example that calls a few functions from the TC 2.01 libraries:

;====================================================================
.model large, c
.386
;====================================================================

printf  PROTO c :VARARG
rand    PROTO c
getch   PROTO c

fact    PROTO c :DWORD

;====================================================================

.stack
.data

    fmtd  db    "%d%c",0
    fmth  db    "%c%xh%c",0

.code

;====================================================================

;-------------------------------------------------------------
; This dummy procedure prevents the linker from returning an
; "unresolved external" error. Something in the library code
; is apparently referencing this name, and while the dummy
; procedure will satisfy the linker, if the library were to
; actually call the procedure it would probably fail.
;-------------------------------------------------------------

main proc
  ret
main endp

.startup

;====================================================================

    REPEAT 100
      invoke rand
      invoke printf, ADDR fmtd, ax, 9
    ENDM

    invoke printf, ADDR fmth, 10, 1234h, 10

    invoke fact, 5
    invoke printf, ADDR fmtd, ax, 10

    invoke getch

;====================================================================

.exit

end

And the batch file that I use to build and run the test app:

ML /c clibtest.asm
pause
LINK16 /MAP clibtest.obj c0l.obj fact.obj,,,cl.lib;
pause
clibtest
pause


And a listing for the directory I was working in:

11/04/2008  03:49a                 102 makeit.bat
11/04/2008  03:52a               1,327 clibtest.asm
05/11/1989  02:01a               2,043 C0L.OBJ
05/11/1989  02:01a             111,074 CL.LIB
01/13/1995  01:10p             364,544 LINK16.EXE
03/29/1999  05:45p             372,736 ML.EXE
07/22/2001  05:31a               9,687 ML.ERR
11/04/2008  03:52a               8,269 clibtest.map
11/04/2008  03:52a              12,188 clibtest.exe
11/04/2008  03:52a               3,628 clibtest.obj
11/04/2008  03:51a                 439 FACT.OBJ


I used ML version 6.14 from the MASM32 package, but I think 6.11 should work the same for this.

I arbitrarily decided to use the Large memory model libraries. At least for the distribution that I have, there is a problem with the TC 2.01 libraries in that printf does not support floating-point formats. The only way I could find to correct this problem was to link in forcefp.obj from a later version of TC.

Edit:

After I installed TC 2.01 I changed the test to include a function created from this source (note that under Compiler/Options the Model must be set to large):

int fact( int n )
{
    int res = 1;
    printf( "n=%d\n", n );
    while( n > 0 )
      res *= n--;
    return( res );
}


I have updated the ASM source, batch file, and directory listing to reflect the changes, and here is the generated output:

346     130     10982   1090    11656   7117    17595   6415    22948   31126
9004    14558   3571    22879   18492   1360    5412    26721   22463   25047
27119   31441   7190    13985   31214   27509   30252   26571   14779   19816
21681   19651   17995   23593   3734    13310   3979    21995   15561   16092
18489   11288   28466   8664    5892    13863   22766   5364    17639   21151
20427   100     25795   8812    15108   12666   12347   19042   19774   9169
5589    26383   9666    10941   13390   7878    13565   1779    16190   32233
53      13429   2285    2422    8333    31937   11636   13268   6460    6458
6936    8160    24842   29142   29667   24115   15116   17418   1156    4279
15008   15859   19561   8297    3755    22981   21275   29040   28690   1401

1234h
n=5
120
eschew obfuscation