Linux x86_64汇编调用printf触发段错误,未修改栈也可复现
x86_64汇编调用printf段错误修复方案
问题根因
- 栈对齐不符合ABI规范:x86_64 Linux的System V ABI要求,调用函数前栈指针
rsp必须16字节对齐。进入main函数时,因上层调用main时压入了8字节返回地址,rsp对齐偏移为8;你后续先后压入rbx、rbp两个8字节寄存器,又申请了32字节栈空间,最终执行call printf前rsp对齐偏移为8,不符合要求,当printf内部用到16字节对齐的SSE指令时就会触发段错误。 - 格式字符串定义错误:你用
dd定义字符串,dd是定义4字节单元的伪指令,会自动补零填充,导致格式串存储内容不符合预期,存在潜在风险。 - 格式符与参数不匹配:你用
%i(对应32位int)打印64位寄存器rbx的值,斐波那契数超过32位范围时会出现输出错误。 - 循环次数设置错误:
rcx初始值设为1,循环只会执行1次,无法打印多个斐波那契数。
修复方法
- 调整栈空间申请大小,保证
call printf前rsp16字节对齐,可将原来的sub rsp,32改为sub rsp,40 - 用
db伪指令定义格式字符串,格式符改为%ld匹配64位整数 - 根据需要打印的数量设置
rcx初始值
修正后完整代码
global main extern printf section .data formatStr: db "%ld",0xA,0 section .text main: push rbx ; 保存被调用者保护寄存器 push rbp mov rbp,rsp sub rsp,40 ; 申请40字节栈空间,保证后续call前rsp16字节对齐 mov rax,0 ; A mov rbx,1 ; B mov rcx,20 ; 计数器,打印20个斐波那契数 fib: mov rdx,rbx ; Temp = B add rbx,rax ; B += A mov rax,rdx ; A = 原B mov QWORD[rbp-8],rax mov QWORD[rbp-16],rbx mov QWORD[rbp-24],rcx mov rdi,formatStr mov rsi,rbx xor rax,rax call printf mov rax,QWORD[rbp-8] mov rbx,QWORD[rbp-16] mov rcx,QWORD[rbp-24] dec rcx jnz fib ; 退出程序 mov rsp,rbp pop rbp pop rbx ret
编译运行命令不变
nasm -felf64 fib.asm && gcc -no-pie fib.o && ./a.out
内容的提问来源于stack exchange,提问作者Yukera
相关产品推荐
相关产品推荐

