使用riscv32/64-unknown-elf-gcc编译时如何删除栈指针相关操作?
问题根源说明
你遇到的两个故障本质是两个独立问题:
- 栈指针相关操作报错:编译选项强制开启了栈帧保留,且裸机环境没有初始化SP,默认SP为0时栈操作访问了非法地址
- 0x4000005c地址跳转故障:O0优化级别下编译器为switch生成了跳转表,跳转表被链接到了你预留的指令存储区外的地址,读取跳转表项后跳转到了非法位置
方案1:让SP相关操作正常运行(更推荐,兼容性强)
你不需要删掉SP操作,只要提前初始化SP到合法的RAM区域即可:
在_start函数的最开头插入内嵌汇编设置SP,地址选你可用RAM的高地址即可(RISC-V栈向下增长,避开数据段、BSS段即可,比如你数据段从0x70000100开始,可以把SP设为0x71000000):
void _start (void) { // 加在所有代码的最前面 __asm__ __volatile__("li sp, 0x71000000"); int irq; IRQ0 = 0; DMEM_ROM4 = 0; // 剩余原有代码保持不变 }
该方案不需要修改编译选项,后续新增其他C代码也能正常运行,不会出现栈相关的兼容性问题。
方案2:完全删除生成代码中的SP相关操作
你当前的编译选项里有多个参数会强制生成栈操作,修改编译参数即可:
- 删掉
-fno-omit-frame-pointer参数:该参数会强制保留栈帧指针,必然生成SP操作 - 删掉
-funwind-tables参数:该参数用于生成栈回溯信息,依赖栈结构 - 把
-O0替换为-O2或-Os:开启优化后,你的简单逻辑代码不需要用到栈,编译器会自动消除所有不必要的栈操作 - 新增
-ffreestanding参数:告诉编译器当前是无操作系统的裸机环境,减少不必要的默认生成逻辑
修改后的编译命令参考:
riscv64-unknown-elf-gcc -march=rv32im -mabi=ilp32 -nostartfiles -fno-toplevel-reorder -fomit-frame-pointer -O2 -ffreestanding -x c -Ttext 40000000 -Tdata 70000100 -Tbss 70000200 -o main.o main.c
开启优化后,编译器也会把switch语句转换成直接的分支比较跳转,不会生成跳转表,也能同步解决0x4000005c的跳转故障。
内容的提问来源于stack exchange,提问作者doldooly
相关产品推荐
相关产品推荐

