从 NASM 调用 C 函数 _printf 导致分段错误

Calling the C-function _printf from NASM causes a Segmentation Fault

我一直在尝试使用 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 要求 stack-pointer 为 16-byte-aligned。在调用 _printf 时,stack-pointer 错位了 8 个字节。

使用 LLDB 调试二进制文件得到:

frame #0: 0x00007fff527d430a libdyld.dylib`stack_not_16_byte_aligned_error

MacOS 使用 System V AMD64 ABI,因此依赖于 stack-pointer (see this question) 的 16 字节对齐,简而言之,这意味着 stack-pointer (rsp) 调用函数时应始终能被 16 整除。

调用 _printf 时,stack-pointer (rsp) 错位了 8 个字节。这是怎么来的?

我在 this page 上找到了答案,调用 _main 函数将 return 地址(8 字节)压入堆栈,因此未对齐。

我最初的想法 - 堆栈帧的设置 - 将另一个地址压入堆栈,因此 rsp 再次被 16 整除。

然而,根据 Margaret Bloom

的建议,更简单的解决方案就是 sub rsp, 8

将您的代码更改为:

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 上测试