我正在尝试使用参数创建一个简单的控制台程序集程序。这是代码:
.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位对齐 进程。
我错过了什么?
答案 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