程序集分段错误:11
Assembly Segmentation fault: 11
我正在尝试将此 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 [=11=]x4, %esp # int a
mov 0xC(%ebp), %eax
push 0x4(%eax) # char* argv[1]
call _atoi
add [=11=]x4, %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 [=14=]x4, %esp
行对我来说似乎非常不必要。所以我试着删除它,它编译得很好。但是当我 运行 它使用 ./math 2
而没有那条线时,它给我一个 Segmentation fault: 11
错误。
我没有看到任何看起来依赖于该行的行。所以我想知道为什么这个程序需要那一行,为什么删除它会导致那个错误?谢谢!
首先 "sub , %esp" 行与变量 "a"!
无关
“_atoi”函数正在使用 XMM 寄存器,因此某些变量必须与 16 字节边界对齐。要为堆栈上的局部变量实现此目的,有两种可能性:
调用 ("_atoi") 的函数本身必须确保堆栈对齐到 16 字节。这可以使用以下代码完成:
push %ebp
mov %esp, %ebp
and [=10=]xFFFFFFF0, %esp # <- This line here
sub [=10=]x1230, %esp
此方法由 32 位 Windows 和 Linux 程序完成,因此您的程序可以在 Windows 和 Linux 上正常工作(我在 Windows)!
在 MacOS X 下,第二种可能性用于 32 位程序 - 这也用于大多数操作系统的 64 位程序:
调用函数时,堆栈必须已经对齐到 16 个字节。
您的 "sub" 行程序:
# Here esp is esp_original
call _main # 4 bytes
push %ebp # 4 bytes
sub [=11=]x4, %esp # 4 bytes
push 0x4(%eax) # 4 bytes
# Here esp must be esp_original+16*N
call _atoi
如果删除 "sub" 指令或将其替换为 "sub , %esp" 指令,则堆栈将不再对齐。如果你需要 8 个字节的堆栈,你必须做一个 "sub , %esp" 而不是 "sub , %esp" 因为那个。
遗憾的是,这一要求使得在 MacOS X 上进行汇编编程变得更加困难 - 特别是对于初学者而言。
我正在尝试将此 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 [=11=]x4, %esp # int a
mov 0xC(%ebp), %eax
push 0x4(%eax) # char* argv[1]
call _atoi
add [=11=]x4, %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 [=14=]x4, %esp
行对我来说似乎非常不必要。所以我试着删除它,它编译得很好。但是当我 运行 它使用 ./math 2
而没有那条线时,它给我一个 Segmentation fault: 11
错误。
我没有看到任何看起来依赖于该行的行。所以我想知道为什么这个程序需要那一行,为什么删除它会导致那个错误?谢谢!
首先 "sub , %esp" 行与变量 "a"!
无关“_atoi”函数正在使用 XMM 寄存器,因此某些变量必须与 16 字节边界对齐。要为堆栈上的局部变量实现此目的,有两种可能性:
调用 ("_atoi") 的函数本身必须确保堆栈对齐到 16 字节。这可以使用以下代码完成:
push %ebp
mov %esp, %ebp
and [=10=]xFFFFFFF0, %esp # <- This line here
sub [=10=]x1230, %esp
此方法由 32 位 Windows 和 Linux 程序完成,因此您的程序可以在 Windows 和 Linux 上正常工作(我在 Windows)!
在 MacOS X 下,第二种可能性用于 32 位程序 - 这也用于大多数操作系统的 64 位程序:
调用函数时,堆栈必须已经对齐到 16 个字节。
您的 "sub" 行程序:
# Here esp is esp_original
call _main # 4 bytes
push %ebp # 4 bytes
sub [=11=]x4, %esp # 4 bytes
push 0x4(%eax) # 4 bytes
# Here esp must be esp_original+16*N
call _atoi
如果删除 "sub" 指令或将其替换为 "sub , %esp" 指令,则堆栈将不再对齐。如果你需要 8 个字节的堆栈,你必须做一个 "sub , %esp" 而不是 "sub , %esp" 因为那个。
遗憾的是,这一要求使得在 MacOS X 上进行汇编编程变得更加困难 - 特别是对于初学者而言。