从 NASM 调用 C 函数 _printf 会导致分段错误 [英] Calling the C-function _printf from NASM causes a Segmentation Fault

查看:103
本文介绍了从 NASM 调用 C 函数 _printf 会导致分段错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试使用 NASM 在 Mac-OS 和 Windows 上学习 64 位汇编.

I've been trying to learn 64-bit assembly on both Mac-OS and Windows using NASM.

我的代码是

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 时,出现错误

While trying to call _printf, I got the error

分段错误:11

当我删除对 _printf 的调用时,我的代码运行良好.为什么调用 _printf 会导致分段错误?

When I remove the call to _printf, my code runs fine. Why does the call to _printf cause a segmentation fault?

我在此处找到了 ABI 调用约定,但没有成功调用 C 函数.

I have found the ABI Calling Convention here, but had no luck successfully calling a C-function.

我希望打印 Hello World!,但我得到的是Segmentation Fault: 11".

I would expect Hello World! to be printedd, however I get 'Segmentation Fault: 11' instead.

推荐答案

~~调用_printf

TL;DR: System V AMD64 ABI 要求堆栈指针按 16 字节对齐.到调用 _printf 时,堆栈指针错位了 8 个字节.

TL;DR: The System V AMD64 ABI requires the stack-pointer to be 16-byte-aligned. By the time of calling _printf, the stack-pointer is misaligned by 8 bytes.

使用 LLDB 调试二进制文件给出:

Debugging the binary with LLDB gives:

第 0 帧:0x00007fff527d430a libdyld.dylib`stack_not_16_byte_aligned_error

frame #0: 0x00007fff527d430a libdyld.dylib`stack_not_16_byte_aligned_error

MacOS 使用 System V AMD64 ABI,因此堆栈指针依赖于 16 字节对齐(见这个问题),简而言之,这意味着堆栈指针(rsp)应该总是被整除16 调用函数时.

MacOS uses the System V AMD64 ABI and therefore relies on 16-byte alignment for the stack-pointer (see this question), in short this means the stack-pointer (rsp) should always be divisible by 16 when calling a function.

到调用 _printf 时,堆栈指针 (rsp) 错位了 8 个字节.这是怎么来的?

By the time of calling _printf, the stack-pointer (rsp) is misaligned by 8 bytes. How did this come?

我在此页面上找到了答案,调用了_main 函数将返回地址(8 个字节)压入堆栈,因此未对齐.

I found the answer on this page, calling the _main function pushes the return address (8 bytes) on the stack and therefore misaligns it.

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

My initial idea - the setup of the stack frame - pushed another address on the stack and therefore rsp was divisible by 16 again.

然而,更简单的解决方案是 sub rsp, 8 正如 Margaret Bloom 所建议的一个>

However an easier solution would be just sub rsp, 8 as suggested by 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 上测试

Tested on macOS 10.13.6

这篇关于从 NASM 调用 C 函数 _printf 会导致分段错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆