在C语言中调用NASM函数

在C语言中调用NASM函数,c,gcc,assembly,segmentation-fault,nasm,C,Gcc,Assembly,Segmentation Fault,Nasm,我正在尝试学习x86汇编程序,我想用C调用NASM函数。当我运行我的程序时,我遇到以下错误: 分段故障(堆芯转储) 我尝试了几十种简单测试函数的变体,但每次都在同一位置停止 以下是我的asm和c文件: 分区asm: global _test _test: push ebp mov ebp, esp push ebx mov eax, [ebp+8] mov ebx, [ebp+12] div ebx

我正在尝试学习x86汇编程序,我想用C调用NASM函数。当我运行我的程序时,我遇到以下错误:

分段故障(堆芯转储)

我尝试了几十种简单测试函数的变体,但每次都在同一位置停止

以下是我的
asm
c
文件:

分区asm:

global _test

_test:
    push    ebp
    mov     ebp, esp
    push    ebx
    mov     eax, [ebp+8]
    mov     ebx, [ebp+12]
    div     ebx
    pop     ebp
    ret
主要条款c:

#include <stdio.h>

extern unsigned int test (unsigned int, unsigned int);

int main(void)
{
    printf("%d\n", div(85,5));
    return 0;
}
我在
虚拟机中使用
64位Linux

我的错误是什么?我该如何修复它?

您忘记弹出ebx(或者至少按顺序排列堆栈):


现在还不清楚你的问题是否解决了。除了其他问题外,还需要在
main.c
中进行函数调用,以匹配
div.asm
中的调用。例如,如果您创建了一个汇编函数
\u test
,则需要将其声明为
extern
,并实际使用
main
中的函数。e、 g:

#include <stdio.h>

extern unsigned int _test (unsigned int, unsigned int);

int main(void)
{
    printf("%d\n", _test (85,5));    /* you are calling div here, not _test */
    return 0;
}
    global _test

_test:
    push    ebp
    mov     ebp, esp
    mov     eax, [ebp+8]
    xor     edx, edx
    div     dword [ebp+12]
    mov     esp, ebp
    pop     ebp
    ret
现在,您可以编译、链接和运行测试文件:

$ nasm -f elf -o div.o div.asm
$ gcc -m32 -c -o main.o main.c
$ gcc -m32 -o run div.o main.o
$./run
17
或者对于编译/链接,只需:

$ nasm -f elf -o div.o div.asm
$ gcc -m32 -o run main.c div.o

使用调试器找出它在哪个insn上出错。你看,你有两个问题:推送/弹出不匹配,还有一个
div
问题。哦,好的一点,是的,Linux不会把名字和前导的
\ucode>弄乱。您正在调用的
test
函数甚至不是您组装的
\u test
函数!既然它是链接的,我想这个符号一定存在于某个库中吧?再说一遍,FTW。使用
-g
编译。如
gcc-m32-Wall-Wextra-Og-gmain.c div.o-o run
等一下。您调用了一个名为div的函数,但在代码的任何地方都没有定义它。您在汇编中定义的函数称为“test”,浮点异常是因为您是EBX的EDX:EAX,并且商可能不适合32位寄存器。你没有清除EDX。试着在div前面加上xor edx,edx,以确保被除数的前32位为零。@PaulOgilvie:他说的是C代码。它有一个
test()
的原型,但是调用了
div()
。您需要恢复调用方的
ebx
!最好不要首先使用保留呼叫的寄存器(例如,使用
ecx
)。更好的是,
div[ebp+12]
@PaulOgilvie:pop ebx的加载部分是必需的。当然
addesp,4
(不是
addsp,4
),或者
leave
的传统
mov-esp,ebp
部分将恢复
esp
,因此
pop-ebp
/
ret
将起作用,但仍然存在严重的重击
ebx
错误。这不是一个有效的建议。但是Paul,因为他正在Linux上创建一个32位应用程序,CDECL指定某些寄存器需要由函数保留。特别是:寄存器EAX、ECX和EDX被调用者保存,其余被调用者保存。如果EBX没有真正恢复,你以后可能会遇到一些讨厌的bug。一开始它似乎很管用,但最终那个bug会咬到你的屁股。@PeterCordes,没错,应该是
esp
,而不是'sp'。Thx。您显示堆栈错误,但您的建议(而不是pop ebx)您可以添加sp,4是错误的。函数需要保留EBX,因此必须在返回之前恢复EBX的值<代码>添加sp,4
修复堆栈,但不会按照恢复EBX。
$ nasm -f elf -o div.o div.asm
$ gcc -m32 -c -o main.o main.c
$ gcc -m32 -o run div.o main.o
$./run
17
$ nasm -f elf -o div.o div.asm
$ gcc -m32 -o run main.c div.o