RISC-V大数值打印功能实现失败,请求代码问题排查指导
RISC-V大数值打印代码的问题分析
你的代码目标是打印64位无符号整数(a0存低32位、a1存高32位),但存在几个关键问题:
64位除法逻辑错误:当前代码单独拆分高、低32位做除法,没有处理64位除法的余数传递逻辑。正确的64位无符号除以10的流程应该是:
- 先将高32位除以10,得到的商作为新的高32位,余数暂存。
- 把余数左移32位(等价于乘以2^32)加上原低32位,再除以10,得到的商作为新的低32位,余数就是当前的个位数字。
你直接拆分处理的方式会导致数值计算完全错误,比如0x123456789abcdef0这类跨32位的数值,拆分处理后得到的各位数字完全不符合实际值。
违反RISC-V栈对齐约定:RISC-V的函数调用约定要求栈指针
sp始终保持16字节对齐。你的代码每次执行addi sp, sp, -1存储单个字符,会直接破坏栈对齐,可能导致后续系统调用(ecall)或函数调用出现异常。栈操作存在溢出风险:没有提前规划栈空间,直接逐字节压栈,若数值位数较多,可能会覆盖之前保存的寄存器或其他栈数据。
修改后的示例代码
.data .text .global main main: li a0, 0x12345678 li a1, 0x9abcdef0 jal print_large li a7, 10 ecall print_large: # 保存寄存器并保证栈16字节对齐 addi sp, sp, -32 sd ra, 24(sp) sd s0, 16(sp) sd s1, 8(sp) sd s2, 0(sp) mv s0, a0 # s0 = 低32位 mv s1, a1 # s1 = 高32位 li s2, 0 # s2 = 数字计数 process_digit: # 64位无符号数除以10 li t0, 10 # 处理高32位,得到商和余数 divu s1, s1, t0 mfhi t0 # 余数左移32位 + 低32位,再除以10 slli t0, t0, 32 or t0, t0, s0 divu t0, t0, 10 mfhi t1 # t1 = 当前个位数字(ASCII偏移前) mflo s0 # s0 = 新的低32位 # 转换为ASCII并存栈 addi t1, t1, 48 addi sp, sp, -1 sb t1, 0(sp) addi s2, s2, 1 # 判断是否所有位处理完成 bnez s1, process_digit bnez s0, process_digit print_digit: beqz s2, end_print addi sp, sp, 1 lb t0, 0(sp) mv a0, t0 li a7, 11 ecall addi s2, s2, -1 j print_digit end_print: # 恢复寄存器和栈 ld s2, 0(sp) ld s1, 8(sp) ld s0, 16(sp) ld ra, 24(sp) addi sp, sp, 32 ret
这个版本修复了64位除法的核心逻辑,同时严格遵守栈对齐约定,能够正确打印任意64位无符号大数值。
内容的提问来源于stack exchange,提问作者user18370758
相关产品推荐
相关产品推荐

