繁体   English   中英

程序集分段错误: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 $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上的汇编编程更加困难,尤其是对于初学者。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM