【问题标题】:Using an assembly function in a C program在 C 程序中使用汇编函数
【发布时间】:2021-11-11 14:05:03
【问题描述】:

我的汇编函数有一个小问题。

;  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

还有我的 C 文件,我在其中创建了汇编函数的原型。

#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();

}

我遇到的问题是我的 C 程序没有为汇编函数提供正确的参数,在我的 C 文件中我使用 _curpos(20,40) 但它没有使用括号中的值。相反,它使用了前一个 scanf() 中的一些垃圾编号;输入。

我是否有错误声明、原型设计不正确或忘记了什么?

我正在使用 OpenWatcom 和 MASM 6.11。

谢谢,诺亚“疯狗”布泽利

编辑: 这里是固定的汇编函数

;  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

这是我的 C 原型

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

谢谢你Mgetz :)

【问题讨论】:

  • 在程序集中我看到的只是curpos_ 但在你的C 代码中你调用_curpos 这有关系吗?
  • C 编译器有哪些调用约定(寄存器、堆栈等)?如果您将参数命名为与变量相同的名称也没关系,它们仍然会有所不同。
  • cdecl 调用约定函数没有装饰器,因此您可以使用确切的名称来调用它。但是你应该在你的 C 代码中指定对流。
  • 考虑到使用的代码和编译器,我假设您的目标是旧的 16 位 DOS 平台?您可能想edit您的问题添加相应的标签。它使合适的人更容易帮助您找到问题。
  • @Someprogrammerdude 看起来是 openwatcom,默认为 __stdcall

标签: c assembly dos


【解决方案1】:

所以你需要为组装方法指定Calling convention。默认情况下 open watcom 使用__stdcall

所以它应该看起来像这样:

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

这个 asm 可能是正确的,但未经测试。我们手动完成所有操作,而不是依靠 MASM 的魔法来设置 BP 并计算 args 在堆栈中的位置。

_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

为了它的价值,最好使用内联汇编而不是在 asm 中进行完整的实现。如果你使用内联汇编,编译器会处理所有这些,你只需要将输入放入寄存器,而不是编写返回的代码。

【讨论】:

  • 谢谢,这就是我最终在我的 C 文件中使用 extern void __stdcall curpos(char columns, char rows); 的原型
  • @MadDog386 只是好奇...我的堆栈对齐是否正确?
  • 我不确定,如果我可以正确地将我的代码粘贴到评论中,我在我的汇编函数末尾添加了一个 pop bp 和 pop sp,它似乎与您的 __stdcall 结合使用
  • @MadDog386 你的程序集实际上并没有遵循调用约定是我关心的。我的答案中的版本应该。请注意,我的答案中的最终版本使用 6 个字节的堆栈,并且全部通过 push/popret inst 隐式处理。未能正确执行操作可能会导致堆栈损坏。
  • @MadDog386 你的可能已经工作了取决于很多其他的事情,但它几乎肯定会通过在返回时向堆栈指针添加太多来破坏堆栈。这意味着任何称呼它的东西都可能被破坏,这很糟糕。它会导致非常微妙和痛苦的失败
猜你喜欢
  • 1970-01-01
  • 2016-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-09
  • 2011-09-04
相关资源
最近更新 更多