为何链接器无法将.rodata置于.text之后?RISC-V Rust编译问题
解决.text段定位与重定位错误方案
问题根源分析
- 默认链接脚本中
.rodata段优先级高于.text,导致它抢占了0x80200000地址 - 你提供的链接脚本中
data_space起始地址写错(多了一个0,写成0x80200002c,实际应为0x8020002c),导致.rodata被放到距离.text过远的位置,触发RISC-V的R_RISCV_PCREL_HI20重定位范围限制(该重定位仅支持±512KB内的地址跳转)
修正后的链接脚本
MEMORY { kernel (rwx) : ORIGIN = 0x80200000, LENGTH = 6K } SECTIONS { .text : { /* 强制_start函数放在段最开头,保证OpenSBI能正确跳转 */ KEEP(*(.text._start)) *(.text*) } > kernel .text ALIGN(4) : { /* 确保.text段按4字节对齐,符合RISC-V指令要求 */ } > kernel .rodata : { *(.rodata*) } > kernel /* 保留其他必要段的定义 */ .comment : { *(.comment) } .riscv.attributes : { *(.riscv.attributes) } }
关键调整说明
- 合并内存区域:不需要拆分
kernel_space和data_space,.text和.rodata属于同类型只读段,放在同一连续内存区域即可,避免跨区域远距离跳转 - 强制_start位置:用
KEEP(*(.text._start))确保入口函数_start位于.text段最开头(即0x80200000地址),匹配OpenSBI的加载预期 - 对齐修正:给
.text段添加4字节对齐,符合RISC-V 32/64位指令的对齐要求,避免地址偏移引发异常 - 调整段顺序:将
.text放在.rodata之前,确保链接器优先为.text分配指定起始地址
编译配置补充
在Rust的.cargo/config.toml中添加以下编译参数,适配内核场景:
[target.riscv-unknown-kadrix] rustflags = [ "-C", "link-arg=-Tlinker.ld", "-C", "relocation-model=static", "-C", "code-model=medium" ]
relocation-model=static:禁用动态重定位,适合无OS的内核环境code-model=medium:支持更大范围的地址访问,规避小代码模型的跳转限制
验证方法
编译完成后,执行以下命令查看段信息:
riscv64-unknown-elf-readelf -S target/riscv-unknown-kadrix/release/kadrix
确认:
.text的VMA和LMA均为0x80200000.rodata紧跟在.text之后,地址连续
内容的提问来源于stack exchange,提问作者CocytusDEDI
相关产品推荐
相关产品推荐

