我正在尝试采用此C代码并将其转换为汇编语言
#include <stdlib.h>
int sub(int x, int y) {
return 2*x+y;
}
int main(int argc, char ** argv) {
int a;
a = atoi(argv[1]);
return sub(argc,a);
}
我曾经gcc -S math.c
将它变成Assembly,最后了解了它的大部分功能。因此,我将其重写为:
.globl _main
_sub:
push %ebp
mov %esp, %ebp
mov 0x8(%ebp), %eax # int x
mov 0xC(%ebp), %ecx # int y
lea (%ecx, %eax, 2), %eax # 2 * x + y
pop %ebp
ret
_main:
push %ebp
mov %esp, %ebp
sub $0x4, %esp # int a
mov 0xC(%ebp), %eax
push 0x4(%eax) # char* argv[1]
call _atoi
add $0x4, %esp
push %eax # int y
push 0x8(%ebp) # int x/argc
call _sub
mov %ebp, %esp
pop %ebp
ret
我正在gcc -m32 -Wall math.s -o math
OS X上编译它,并且运行良好。但是这行sub $0x4, %esp
对我来说似乎是不必要的。因此,我尝试将其删除,并且可以正常编译。但是,当我不使用./math 2
该行而运行它时,会出现Segmentation fault: 11
错误。
我看不到任何依赖于该行的行。所以我想知道为什么该程序需要该行,为什么删除它会导致该错误?谢谢!
首先,“ sub $ 4,%esp”行与变量“ a”不相关!
“ _atoi”功能正在使用XMM寄存器,因此某些变量必须与16字节边界对齐。要将其归档为堆栈上的局部变量,有两种可能性:
称为(“ _atoi”)的函数本身必须确保堆栈对齐到16个字节。可以使用以下代码完成此操作:
push %ebp
mov %esp, %ebp
and $0xFFFFFFF0, %esp # <- This line here
sub $0x1230, %esp
这种方法是由32位Windows和Linux程序完成的,因此您的程序可以在Windows和Linux上正常工作(我在Windows下尝试过!)!
在MacOS X下,第二种可能性用于32位程序-在大多数OS上也用于64位程序:
调用函数时,堆栈必须已经对齐到16个字节。
您的程序带有“ sub”行:
# Here esp is esp_original
call _main # 4 bytes
push %ebp # 4 bytes
sub $0x4, %esp # 4 bytes
push 0x4(%eax) # 4 bytes
# Here esp must be esp_original+16*N
call _atoi
如果删除“ sub”指令,或将其替换为“ sub $ 8,%esp”指令,则堆栈将不再对齐。如果您还需要8个字节的堆栈,则必须执行“ sub $ 20,%esp”而不是“ sub $ 4,%esp”。
可悲的是,此要求使在MacOS X上的汇编编程更加困难,尤其是对于初学者。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句