From: s1110238@giaeb.cc.monash.edu.au (Lee Hollingworth)
Subject: Re: Help with ASM/C interface
Organization: Monash University, Melb., Australia.
Date: Sat, 21 Nov 1992 23:32:00 GMT

curtisn@SAS (Curtis Nelson) writes:

>I have a question I hope one of you can help me with.  I'm using Borland C++
>3.0 and I am trying to write a simple assembly language routine in my code.

Embedded assembly code in a C function?

If so there is no problem, you simply use your C variables.

Example (written in MSC format BC should not be too different);

int write_port(unsigned char ch, int port)
{
    _asm {
        mov     ah, 01h
        mov     ah, ch
        mov     dx, port
        int     14h
    }
}

The return value of the int 14h function is in AX, and is automatically
returned by the asm code.  You can be more explicit by adding in a variables.

int write_port(unsigned char ch, int port)
{
    int status;

    _asm {
        mov     ah, 01h
        mov     ah, ch
        mov     dx, port
        int     14h
        mov     status, ax
    }

    return status & 0x80;   /* status of write */
}

>My question is, how do I pass vaues back and forth?  For example, if I push
>a value onto the stack in assembly, how con I retrieve that value from C?  I
>know I can use the stack, but how do I access an item on the stack?  I've
>looked at 'pop', but that appears to only work in C++, and I'm writing this
>in straight C.

If you are interfacing with assembly code in a mixed language environment
you access parameters passed to the asm code by calculating the offset from
bp.  Generally this is equal to 2 + size of return address + total size of
parameters between bp and the parameter you are trying to access.

Eg, a FAR procedure that has received one parameter with a four-byte address.

    displacement = 2 + size of return address
                 = 2 + 4
                 = 6

To load the parameter into a register you then would use,

        mov     bx, [bp+6]

or you can define your own parameter names in your code such as,

    foo     EQU     [bp+6]

then to access foo it is simply,

        mov     bx, foo

Returning values from asm code is simple if the return data type size is
four bytes or less.

    Data Size       Returned in
       1               AL
       2               AX
       4               High byte DX  Low byte AX

If the value to be returned is greater than 4 bytes, your C function must
allocate space for the return value, and place the address of that space
in DX:AX.

Here is a simple source file for some C - ASM interface code...

;--------------------------------------------------------------------------
key_ready   equ     11h             ; function K_READY

            .model small
            .code
public      _prnwrite
;------------------------- prnwrite ----------------------------------------
;   call    unsigned int prnwrite(ch, port);
;           unsigned char ch
;           unsigned int port
;               refer to biosibm.h for defines
;  returns  status in ah
;----------------------------------------------------------------------------
_prnwrite   proc
            push    bp
            mov     bp, sp              ; mov stack pointer to base pointer
            push    si
            push    di

            mov     al, [bp+4]          ; get character to print
            mov     dx, [bp+6]          ; get port number
            mov     ah, 00h
            int     17h
            xor     al, al              ; clear al, ah returned

            pop     di
            pop     si
            pop     bp
            ret
_prnwrite   endp

            end
;-------------------------------------------------------------------------

>I would appreciate any help!

I think you would get more help if you used the comp.os.msdos.programmer
newsgroup.

Lee Hollingworth
s1110238@giaeb.cc.monash.edu.au