我一直在尝试使用 NASM 在 Mac-OS 和 Windows 上学习 64 位汇编。
我的代码是
extern _printf
section .data
msg db "Hello World!", 10, 0
section .text
global _main
_main:
mov rax, 0
mov rdi, msg
call _printf
mov rax, 0x2000001
mov rdi, 0
syscall
然后我编译它
nasm -f macho64 -o main.o main.asm
gcc -o main main.o
尝试调用 _printf
时,出现错误
Segmentation fault: 11
当我删除对 _printf
的调用时,我的代码运行正常。
为什么调用 _printf
会导致段错误?
我找到了 ABI 调用约定 here , 但没有成功调用 C 函数。
我希望打印 Hello World!
,但我得到的却是“Segmentation Fault: 11”。
最佳答案
~~你需要在调用之前设置栈帧_printf
TL;DR:System V AMD64 ABI 要求堆栈指针为 16 字节对齐。在调用 _printf
时,堆栈指针错位了 8 个字节。
使用 LLDB 调试二进制文件会得到:
frame #0: 0x00007fff527d430a libdyld.dylib`stack_not_16_byte_aligned_error
MacOS 使用 System V AMD64 ABI,因此堆栈指针 ( see this question ) 依赖于 16 字节对齐,简而言之,这意味着堆栈指针 (rsp
) 应该始终是调用函数时可被 16 整除。
在调用 _printf
时,堆栈指针 (rsp
) 错位了 8 个字节。这是怎么来的?
我在 this page 上找到了答案,调用 _main
函数将返回地址(8 字节)压入堆栈,因此使其不对齐。
我最初的想法 - 堆栈帧的设置 - 将另一个地址压入堆栈,因此 rsp
再次被 16 整除。
然而,一个更简单的解决方案是 sub rsp, 8
,如 Margaret Bloom 所建议的那样
将您的代码更改为:
extern _printf
section .data
msg: db "Hello World!", 10, 0
section .text
global _main
_main:
;; Fix the stack alignment
sub rsp, 8
mov rax, 0
mov rdi, msg
call _printf
mov rax, 0x2000001
mov rdi, 0
syscall
在 macOS 10.13.6 上测试
关于从 NASM 调用 C 函数 _printf 导致段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56991218/