普通的macOS程序集64位程序具有不正确的堆栈对齐

时间:2017-09-19 20:13:55

标签: macos assembly

我正在尝试使用参数创建一个简单的控制台程序集程序。这是代码:

.section __TEXT,__text

.globl _main

_main:

    movl    $0, %edi
    callq   _exit

这是编译和链接脚本:

as test.s -o test.o
ld test.o -e _main -o test -lc 

现在程序要么失败,要么出现分段错误,要么执行没有错误,具体取决于参数计数:

$ ./test
Segmentation fault: 11
$ ./test 1
$ ./test 1 2
$ ./test 1 2 3
Segmentation fault: 11
$ ./test 1 2 3 4
$ ./test 1 2 3 4 5
Segmentation fault: 11

等等。

在LLDB下,我看到了一个更具信息性的错误:

Process 16318 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
    frame #0: 0x00007fffad14b2fa libdyld.dylib`stack_not_16_byte_aligned_error
libdyld.dylib`stack_not_16_byte_aligned_error:
->  0x7fffad14b2fa <+0>: movdqa %xmm0, (%rsp)
    0x7fffad14b2ff <+5>: int3   

libdyld.dylib`_dyld_func_lookup:
    0x7fffad14b300 <+0>: pushq  %rbp
    0x7fffad14b301 <+1>: movq   %rsp, %rbp

实际上,如果我在程序的第一行停止执行,我会看到堆栈对于某些参数计数不是16字节对齐,而是为另一个对齐。虽然System V ABI for AMD64表示:

  

堆栈指针保存具有最低地址的字节的地址   这是堆栈的一部分。保证在16位对齐   进程。

我错过了什么?

1 个答案:

答案 0 :(得分:2)

我想在OS X上,内核在进入main时不保证堆栈对齐。您必须手动对齐堆栈。幸运的是,这很容易,只需将堆栈指针的至少四位清零。如果您需要获取参数向量或其他数据,请确保将原始堆栈指针存储在某处:

_main:
    mov %rsp,%rax    # copy original stack pointer
    and $-16,%rsp    # align stack to 16 bytes
    push %rax        # save original stack pointer
    push %rbp        # establish...
    mov %rsp,%rbp    # ...stack frame
    ...              # business logic here
    leave            # tear down stack frame
    pop %rsp         # restore original stack pointer
    ...              # exit process

您还需要在心理上跟踪堆栈对齐情况。让main除了堆栈对齐之外什么都不做,然后调用你的实际主函数可能更容易,因此你可以在其中使用普通的堆栈框架:

_main:
    mov %rsp,%rbx    # save original stack pointer
    and $-16,%rsp    # align stack to 16 bytes
    call _my_main    # call actual main function
    mov %rbx,%rsp    # restore original stack pointer
    ...              # exit process

对于您的特定示例程序,您只需使用此最小代码:

_main:
    and $-16,%rsp    # align stack to 16 bytes
    xor %edi,%edi    # set exit status to zero
    call _exit       # exit program