在WSL的x86-64汇编中调用printf触发段错误,求原因
x86-64汇编代码触发段错误的原因分析
问题描述
以下是编写的x86-64汇编代码:
.intel_syntax noprefix .data b: .byte 9 s: .word 0 l: .long 0 q: .quad 0 format: .asciz "%s" text: .asciz "Hello world!" .text .global main main: push rbx /* stack needs to be 16 bytes aligned */ mov rdi, format /* first argument to printf */ mov rsi, text /* second argument to printf */ mov rax, 0 /* no parameters in a vector register */ call printf pop rbx /* restore stack pointer */ ret
运行环境:Windows 11 + WSL
编译命令:gcc -g -no-pie -O0 -o sandbox.elf ./sandbox.s
运行命令:./sandbox.elf
运行结果:Segmentation fault
疑问:代码遵循了System V ABI规范,为何会触发段错误?
错误原因及解决方法
问题出在栈对齐上。System V AMD64 ABI明确要求:在执行call指令调用函数之前,栈指针rsp必须保持16字节对齐。
当程序进入main函数时,rsp指向的是调用main时被压入栈的返回地址(8字节),此时rsp的地址是16N + 8,本身就未满足16字节对齐。你代码中push rbx(8字节)后,rsp变为16N,看似对齐,但执行call printf时,call指令会自动将返回地址(8字节)压入栈,导致rsp变成16N - 8,直接破坏了对齐要求——printf内部依赖对齐的栈进行内存操作,最终触发段错误。
修正方案
只需在push rbx后额外调整8字节栈空间,确保调用printf前rsp处于16字节对齐状态即可,以下两种方式都可行:
方式1:直接调整栈空间
.intel_syntax noprefix .data b: .byte 9 s: .word 0 l: .long 0 q: .quad 0 format: .asciz "%s" text: .asciz "Hello world!" .text .global main main: push rbx sub rsp, 8 /* 额外调整8字节,确保调用printf前rsp对齐 */ mov rdi, format mov rsi, text mov rax, 0 call printf add rsp, 8 /* 恢复栈空间 */ pop rbx ret
方式2:建立栈帧
.intel_syntax noprefix .data b: .byte 9 s: .word 0 l: .long 0 q: .quad 0 format: .asciz "%s" text: .asciz "Hello world!" .text .global main main: push rbp mov rbp, rsp /* 建立栈帧,自动满足栈对齐要求 */ mov rdi, format mov rsi, text mov rax, 0 call printf pop rbp ret
内容的提问来源于stack exchange,提问作者Korsarq
相关产品推荐
相关产品推荐

