Sei*_*zh7 3 c x86 assembly 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
Run Code Online (Sandbox Code Playgroud)
我缺少有关 ebx 寄存器的特定信息吗?
所以下面的版本可以完美运行。
版本 2(工作正常):
.globl addArgs
.text
addArgs:
movl 4(%esp), %eax
movl 8(%esp), %ecx
addl %ecx, %eax
ret
Run Code Online (Sandbox Code Playgroud)
我正在 32 位 x86 系统上编译我的代码并使用 GCC 进行编译。
在这种情况下,下面是使用该函数的 C 代码:
#include <stdio.h>
int addArgs();
int main(){
int a = 1, b = 2;
printf("%d\n", addArgs(a, b));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这就是我编译它的方式:
.globl addArgs
.text
addArgs:
movl 4(%esp), %eax
movl 8(%esp), %ebx
addl %ebx, %eax
ret
Run Code Online (Sandbox Code Playgroud)
例程如何通信和行为是有规则的,包括一个如何将参数传递给另一个,如何维护堆栈,以及它们可以自由使用哪些寄存器以及必须保留哪些寄存器。这些称为应用程序二进制接口 (ABI)。x86 架构上使用的一种 ABI 是 System V 应用程序二进制接口。您的编译器可能正在使用此 ABI 或类似的东西。
\nSystem V ABI 指定%ebp、%ebx、%edi、%esi、 和%esp必须由被调用函数\xe2\x80\x94 保存,当它返回到调用函数时,这些寄存器必须包含与调用例程时相同的值。因此,您的编译器可能会使用%ebx保存一个通过调用您的函数而不会改变的值。当你改变时%ebx,你就打破了这个要求。
System V ABI 指定%ecx和%edx是暂存寄存器,并且被调用的例程不必为调用者保留它们的值。因此,您的编译器将不会依赖于%ecx在函数调用中保存值。
这是八个通用寄存器中的七个。第八个,%eax,是一个暂存寄存器,只不过它用于返回一个值。