从C语言调用汇编函数导致分段错误

3
这是我的汇编程序add.s。
.globl add

add:
   movl 4(%esp), %eax
   movl 8(%esp), %ebx
   addl %ebx, %eax
   ret

这是我的 C 程序。我正在尝试从 C 程序中调用汇编程序。

#include <stdio.h>

int add(int a, int b);

int main() {
   int res = add(5,6);
   printf("%d",res);
   return 0;
}

但是上述代码给我返回了一个分段错误。导致这个错误的原因是什么,如何解决?

2
如果您在C中创建相同的函数,编译器如何为其生成代码?它是否进行一些堆栈设置,而您忽略了这些设置?它是否保存使用的寄存器以避免覆盖它们(也许它们被用于其他地方)? - Some programmer dude
2
此处标记为“x86-64”。如果是这样的话,根据我所知道的ABI,参数不会以这种方式传递。实际的操作系统和体系结构是什么?它是如何编译和链接的?(崩溃可能发生在读取(%esp)时,因为它应该是%rsp)。 - Art
我必须同意Art的观点。你是将其编译为32位还是64位代码? - Michael Petch
1个回答

4
假设使用 cdecl 调用约定,您正在使用不应被破坏的 ebx 寄存器:其值必须由被调用方保存并在修改后恢复。
调用方假定通过调用函数 ebx 不会更改。因此,如果被调用方修改 ebx,则必须首先保存它,然后在从函数返回之前将其恢复到原始值。
寄存器 eax、ecx 和 edx 可以在不必先保存再恢复的情况下使用。因此,我建议在您的代码中将 ebx 替换为 edx:
add:
   movl 4(%esp), %eax
   movl 8(%esp), %edx
   addl %edx, %eax
   ret

我曾认为ebx是一个通用寄存器(在这里阅读:http://www.eecg.toronto.edu/~amza/www.mindsec.com/files/x86regs.html),为什么它不应该被覆盖? - CIsForCookies
1
@CIsForCookies 这个可以被覆盖,但调用者假设寄存器 ebx 在调用函数后不会发生改变,因此被调用者必须先保存它,然后在返回之前恢复它。 - JFMR
2
@CIsForCookies 在返回之前执行 push ebx 然后 pop ebx 也会起到作用。 - JFMR
这是ABI相关的,它取决于操作系统。 - rustyx
@CIsForCookies 我认为,如果编译器知道 ebx 被破坏了,那么这就不会有任何问题。但是在这里似乎不可能,因为 add 函数在另一个翻译单元中。 - JFMR
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接