RISC-V程序调用printf后无法从print函数返回求助
问题分析与修复方案
核心问题
跳转未保存返回地址
loop中使用j print无条件跳转,j指令不会将返回地址(即loop中j print的下一条指令地址)写入ra寄存器。当print调用printf时,printf会覆盖ra的值,导致print执行完后无法回到loop的后续代码。违反RISC-V调用约定
ra属于调用者保存寄存器,被调用函数(如printf)可以随意修改它。print调用printf前未将ra保存到栈中,导致返回地址丢失。格式字符串与参数不匹配
格式串"hello, dummy! %s %d\n"要求一个字符串参数和一个整数参数,但代码中只传递了整数,printf会读取非法内存,破坏栈或寄存器状态,引发异常。loop逻辑无法正常循环
j print是无条件跳转,跳转后的slli a3, a3, 2和blt a3, a4, loop永远不会执行,即使返回正常,程序也无法实现循环逻辑。
修复后的代码
.data .align 3 format_string: .string "hello, dummy! %s %d\n" str_arg: .string "test" # 新增匹配%s的字符串参数 tmp_x: .word 0 # Initialize tmp_x with a value of 0 .set foo, 100 .text .globl main main: # 初始化栈空间,用于保存寄存器 addi sp, sp, -16 sw ra, 12(sp) li a0, 10 li a1, 20 li a2, 2 li a3, 0 li a4, foo loop: lw a5, tmp_x jal print # 用jal代替j,将返回地址存入ra # print返回后执行循环逻辑 slli a3, a3, 2 blt a3, a4, loop # 清理栈并退出 lw ra, 12(sp) addi sp, sp, 16 j exit print: # 保存ra到栈,避免被printf覆盖 addi sp, sp, -8 sw ra, 4(sp) # 传递符合格式要求的printf参数 la a0, format_string la a1, str_arg # 字符串参数对应%s mv a2, a5 # 整数参数对应%d call printf # 恢复ra并返回 lw ra, 4(sp) addi sp, sp, 8 ret # ret等价于jalr x0, 0(x1),直接使用更简洁 exit: li a0, 0 li a7, 93 ecall
验证要点
- 用GDB检查
jal print执行后,ra寄存器的值是否为loop中slli指令的地址。 - 确认
print函数中调用printf前后,ra的值被正确保存和恢复。 - 验证格式字符串与参数的数量、类型完全匹配,消除非法内存访问风险。
内容的提问来源于stack exchange,提问作者Rick Dearman
相关产品推荐
相关产品推荐

