c - 为什么使用 %ebx 寄存器会导致我的汇编代码出现段错误

标签 c assembly x86 cpu-registers calling-convention

我正在处理一小段 i386 汇编代码,并在使用 %ebx 寄存器时遇到段错误。我希望能深入了解为什么会发生这种情况。

我有一个非常简单的汇编函数的两个版本。该函数的目的是将两个整数参数相加。当我使用 %ecx 寄存器时,该函数可以正常工作。但是,当我切换到使用 ebx 寄存器时,会导致段错误。这是两个版本的代码:

版本 1(导致段错误):

.globl addArgs
.text
addArgs:
    movl 4(%esp), %eax
    movl 8(%esp), %ebx
    addl %ebx, %eax
    ret

我缺少的有关 ebx 寄存器的特定信息是什么?

所以下面的版本可以完美运行。

版本 2(工作正常):

.globl addArgs
.text
addArgs:
    movl 4(%esp), %eax
    movl 8(%esp), %ecx
    addl %ecx, %eax
    ret

我正在 32 位 x86 系统上编译代码,并使用 GCC 进行编译。

如果是,这里是使用该函数的 C 代码:

#include <stdio.h>

int addArgs();

int main(){
    int a = 1, b = 2;
    printf("%d\n",  addArgs(a, b));
    return 0;
}

这就是我编译它的方式:

$ gcc -march=i386 -m32 -g  addArg_asm.s addArg.c -o addArg

最佳答案

例程如何通信和行为有一些规则,包括一个如何将参数传递给另一个,如何维护堆栈,以及它们可以自由使用哪些寄存器以及必须保留哪些寄存器。这些称为应用程序二进制接口(interface) (ABI)。 x86 架构上使用的一种 ABI 是 System V 应用程序二进制接口(interface)。您的编译器可能正在使用此 ABI 或类似的东西。

System V ABI 指定 %ebp%ebx%edi%esi%esp 必须由被调用函数保存——当它返回到调用函数时,这些寄存器必须包含与调用例程时相同的值。因此,您的编译器可能会使用 %ebx 来保存一个值,该值在调用您的函数时不会改变。当您更改 %ebx 时,您就违反了此要求。

System V ABI 指定 %ecx%edx 是临时寄存器,并且被调用的例程不必保留其值调用者,召集者。因此,您的编译器将不会依赖 %ecx 在函数调用中保存值。

这是八个通用寄存器中的七个。第八个,%eax,是一个暂存寄存器,只不过它用于返回一个值。

关于c - 为什么使用 %ebx 寄存器会导致我的汇编代码出现段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/77563848/

相关文章:

谁能解释输出 printf ("%0 %x",a);?

c# - Python或C#中的项目构想

c - 我需要为 Dirent 结构分配内存吗

linux - x86 程序集从文件读取字节到堆栈但 gdb 找不到字节

linux - 通过一条汇编指令单步执行一个过程

x86 - x86 中的 .data 和 .text 是什么?

c++ - 在 C 宏中捕获名称

gcc - 更改 GCC 的输出以进行 0-set(清除)操作

c - 有没有办法在 GCC 中编译程序而无需汇编?

assembly - 将两个x86 32位寄存器存储到128位xmm寄存器中