Home > Software design >  Using an assembly function in a C program
Using an assembly function in a C program

Time:09-18

im having a small issue with my assembly function that i made.

;  Im failing super hard at writing this
;  Function.

.MODEL c, small
    .DATA?
    .DATA
curpos_ PROTO C columns_:BYTE, rows_:BYTE
    .CODE
public curpos_
curpos_ PROC  C columns_:BYTE, rows_:BYTE
    mov dh, columns_
    mov dl, rows_
    mov     bh, 0
    mov     ah, 2
    int 10h
    ret
curpos_ ENDP
END

And my C file in which i prototype the assembly function.

#include<stdio.h>
#include<conio.h>
#include<math.h>
void clrscr(void);
extern char _columns, _rows;
extern void _curpos(char _columns, char _rows);
void arcradius() {
    float w;
    float h;
    float radi = w / 2.0;
    float value;
    clrscr();

  ...

_curpos(20,40);
getch();
arcradius();

}

The issue im having is that my C program is not giving the assembly function the right arguments, in my C file i use _curpos(20,40) but it doesn't use the values in the parentheses. Instead it uses some garbage number from the previous scanf(); input.

Is there something im mis-declaring, prototyping incorrectly, or forgot?

I'm using OpenWatcom and MASM 6.11.

Thanks, Noah "MadDog" Buzelli

EDIT: Here is the fixed assembly function

;  Im failing super hard at writing this
;  Function.
.MODEL small
.DATA?
.DATA
curpos PROTO C _columns:BYTE, _rows:BYTE
.CODE
public curpos
curpos PROC  C _columns:BYTE, _rows:BYTE
    push     bx
    mov dh, BYTE PTR _columns
    mov dl, BYTE PTR _rows
    mov     bh, 0
    mov     ah, 2
    int 10h
    pop     bx
    ret 4
curpos ENDP
END

And here is my C prototype

extern void __stdcall curpos(char columns, char rows);

Thank you Mgetz :)

CodePudding user response:

So you need to specify the Calling convention for the assembly method. By default open watcom uses __stdcall

So it should look something like this:

extern void __stdcall curpos(char _columns, char _rows);

This asm is probably right, but untested. We're doing everything manually, not relying on MASM's magic to set up BP and calculate the position of args on the stack.

_columns$ = 4                                       ; size = 1
_rows$ = 6         ; offsets relative to the frame pointer
                   ; saved-BP at [bp 0], ret addr at [bp 2], first arg at [bp 4]
_curpos@4 PROC                                      ; COMDAT
        push    bp
        mov     bp, sp        ; for access to args on the stack, [sp] isn't valid
        push    bx            ; save/restore the caller's BX
        mov     dh, BYTE PTR _columns$[bp]
        mov     dl, BYTE PTR _rows$[bp]
        mov     bh, 0         ; page=0
        mov     ah, 2
        int     10h           ; int 10h / AH=2 - BIOS Set cursor position   
        pop     bx
        pop     bp          ; no  mov sp,bp  needed, SP is already good
        ret     4           ; pop ret addr, then SP =4
_curpos@4 ENDP

For what it's worth it may be better to use inline assembly for this instead of doing a full implementation in asm. If you use inline asm the compiler takes care of all of this, you just have to get the inputs into registers, not write code that returns.

  • Related