程序集 "Hello world" 程序段错误

Assembly "Hello world" program segmentation fault

为什么会出现错误:

Segmentation fault (core dumped)

这里是汇编代码:

.intel_syntax noprefix
    
.data

    message: .asciz "Hello World!\n"

.text

.global main

main:
    lea rdi, message
    call printf

    ret

问题

System V ABI 要求您在调用函数之前将堆栈对齐到 16 字节。为了简单起见,ABI 保证“在函数入口处,如果你用 8 * n(n 是奇数)子你的堆栈指针,你的堆栈将是 16 字节对齐的”。

如果您不遵循此调用约定,其他库可能会崩溃,因为如果它们需要使用需要特殊对齐的指令,例如 movdqa,它们将无法正确对齐堆栈帧。

解决方案

ammarfaizi2@integral:/tmp/test_asm$ cat test.S
.intel_syntax noprefix
    
.data

    message: .asciz "Hello World!\n"

.text

.global main

main:
    sub rsp, 8
    xor eax, eax
    lea rdi, [rip + message]
    call printf
    add rsp, 8
    ret
ammarfaizi2@integral:/tmp/test_asm$ gcc test.S -o test
ammarfaizi2@integral:/tmp/test_asm$ ./test
Hello World!
ammarfaizi2@integral:/tmp/test_asm$ 

推荐

如果您 call 一个函数,而您接下来要做的是 ret,您可以使用尾调用来简化代码。它使用 jmp 到要调用的目标函数。如果之前设置过,请确保在跳转之前撤消当前函数堆栈帧。

为支持PIE和PIC,考虑使用RIP相对寻址访问静态存储。它还提高了安全性。现在的编译器通常默认将目标编译为 PIE。

这部分是使用RIP相对寻址访问静态存储的例子:

lea rdi, [rip + message]

执行

ammarfaizi2@integral:/tmp/test_asm$ cat test.S
.intel_syntax noprefix
    
.data

    message: .asciz "Hello World!\n"

.text

.global main

main:
    xor eax, eax
    lea rdi, [rip + message]
    jmp printf

ammarfaizi2@integral:/tmp/test_asm$ gcc test.S -o test
ammarfaizi2@integral:/tmp/test_asm$ ./test
Hello World!
ammarfaizi2@integral:/tmp/test_asm$ 

编辑

已添加 xor eax, eax 以确保安全。参见:glibc scanf Segmentation faults when called from a function that doesn't align RSP