【问题标题】:Segfault with pop/push in x86/OSX在 x86/OSX 中弹出/推送的 Segfault
【发布时间】:2015-01-09 02:21:50
【问题描述】:

我很难理解为什么这个 x86 汇编代码在 OSX 上用 gcc 4.2.1 (llvm) 编译得很好,但是在运行可执行文件时会出现分段错误:

    .globl  _main
_main:
        push    %rbp
        mov     %rsp, %rbp
        mov     $1, %rbx
        push    %rbx
        lea     L_.str0(%rip), %rdi
        mov     %rbx, %rsi
        call    _printf
        pop     %rbx
        pop     %rbp
        ret

        .section        __TEXT,__cstring,cstring_literals
L_.str0:
        .asciz  "%d \000"

我观察到如果pop %rbx 行移动到call _printf 之前,那么程序可以正常运行。但是为什么它会以原来的形式失败呢?

【问题讨论】:

  • 你需要对齐堆栈...
  • @Macmade 是正确的,我相信 - 我编译并运行了您的代码,崩溃日志甚至说这是堆栈未对齐(不是 16 字节对齐)。
  • @PaulR - 谢谢。有没有办法通过指令来做到这一点?还是我必须撒上代码才能手动对齐?
  • How to print argv[0] in NASM? 的可能重复项
  • 同样的问题...请参阅我刚才提到的帖子上的答案,以了解如何做到这一点。

标签: macos assembly


【解决方案1】:

此问题由How to print argv[0] in NASM?x86 Assembly on a Mac 详细回答。在 MacOSX 上编程汇编时,它本质上是一个陷阱。

总结一下:

  • 此段错误是由于堆栈未对齐造成的。
  • 这仅发生在使用 System V 调用约定(包括 MacOSX,但不包括 Linux)的操作系统上,该约定坚持在进行函数调用之前堆栈指针必须是 16 的倍数(例如对printf)。

一个简单的解决方案是在调用之前对齐堆栈指针(即,根据 Sys V 要求对齐到 16 个字节的倍数),并在调用后恢复它:

.globl  _main
_main:
        push    %rbp
        mov     %rsp, %rbp
        mov     $1, %rbx
        lea     L_.str0(%rip), %rdi
        mov     %rbx, %rsi
        push    %rbx

    mov %rsp, %rax   ; Save copy of the stack pointer (SP)
    and $-16, %rsp   ; Align the SP to the nearest multiple of 16.
    sub $8, %rsp     ; Pad the SP by 8 bytes so that when we ...  
    push %rax        ; push the saved SP (=8 bytes on a 64-bit OS), 
                     ; we remain aligned to 16 bytes (8+8 = 16).

        call    _printf

    pop %rax         ; retrieve the saved SP
    mov %rax, %rsp   ; restore SP using saved value. 

        pop     %rbx
        pop     %rbp
        ret

        .section        __TEXT,__cstring,cstring_literals
L_.str0:
        .asciz  "%d \000"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-30
    • 2010-11-02
    • 2017-09-27
    • 2012-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多