解决RISC-V linker fail, relocation truncated to fit: R_RISCV_HI20

RISC-V linker fail, relocation truncated to fit: R_RISCV_HI20

问题描述

尝试将源程序放在ddr内存空间中运行,修改LDS文件,将地址映射从ram空间更改为DDR空间时,编译报错:

uart.c: (.text +0x68): relocation truncated to fit : R_RISCV_PCREL_HI20 against symbol `j’ defined in .bss section in .//drivers/uart.o

riscv64-unknown-elf-ld: warning: /home/ubuntu/nuttxSpace/nuttx/nuttx has a LOAD segment with RWX permissions
/opt/riscv/lib/gcc/riscv64-unknown-elf/12.2.0/libgcc.a(_clzsi2.o): in function __clzdi2': /home/ubuntu/riscv-gnu-toolchain/build-gcc-newlib-stage2/riscv64-unknown-elf/libgcc/../../.././gcc/libgcc/libgcc2.c:690:(.text+0x18): relocation truncated to fit: R_RISCV_HI20 against symbol __clz_tab’ defined in .rodata section in /opt/riscv/lib/gcc/riscv64-unknown-elf/12.2.0/libgcc.a(_clz.o)
编译条件:

CFLAGS + = -I $ (DIR_INC)
CFLAGS + = -D_RISCV64
CFLAGS + = --specs=nano.specs -MD
tookchain: riscv64-unknown-elf-gcc (g2ee5e430018) 12.2.0
解决:
CFLAGS + = -I$(DIR_INC)
CFLAGS + = -D_RISCV64
CFLAGS + = --specs=nano.specs -MD -mcmodel=medany
tookchain: riscv64-unknown-elf-gcc (g2ee5e430018) 12.2.0

解决方法

基准测试/common/test.ld链接器脚本将代码放在0x80000000处。这就是芯片放置DDR DRAM的地方。在0x80000000加载的代码只有在编译 -mcmodel=medany 时才能工作。如果指定了-mcmodel=medlow,这将不起作用。此外,如果您正在链接任何预编译的库,如C库,那么工具链必须已经配置好了-cmodel=medany,否则C库将是medlow代码,无法工作。

分析

源: RISC-V Large Code Model Software Workaround Version 1.0.
RISC-V大代码模型软件解决方案(个人翻译,如有笔误请指出,谢谢)

简介

RISC-V代码模型在构建软件程序时使用,它们定义了一种方法生成指令组合以访问全局符号。目前在RISC-V架构上使用的代码模型有两种:-mcmodel=medlow和-mcmodel=medany。这两个代码模型将生成的代码限制为2GiB或更少。此外,这两种代码模型要求全局符号位于生成的符号的+/- 2GiB(32位 带符号 偏移量)内代码。下面的示例显示了这个范围如何在32位体系结构上使用x0-relative工作寻址。
32位架构寻址使用-mcmodel=medlow
对于使用-mcmodel=medlow的32位架构,可以访问完整的32位地址范围编译和链接您的程序。

对于使用-mcmodel=medany的64位架构,代码可以链接到任何基址,但链接的全局符号遵循类似的+/- 2GiB范围限制。取决于代码在某些情况下,通常不使用负范围。

64位架构寻址使用-mcmodel=medany
总结
 -mcmodel=medlow -用于32位体系结构,此代码模型要求程序及其静态定义的符号必须位于绝对地址-2 GiB和 +2 GiB,它覆盖了整个32位地址范围。代码通常是围绕地址链接的 0x00000000和指令对lui和ld用于为全局生成地址符号。
 -mcmodel=medany -用于64位体系结构,此代码模型也生成32位带符号的偏移量以引用全局符号。链接代码可以驻留在任何地址,指令对auipc和ld用于在+/- 2GiB窗口中生成全局符号地址从代码区。
这两种代码模型都限制了链接符号可以驻留的地址范围,但这不是一个 32位架构的问题。这引入的唯一限制是在64位架构上使用 -mcmodel=medany,其中链接符号需要在+/- 2GiB之外从代码区。
注意:
请注意作为一种优化,如果一个地址在auipc的范围之外,但在零基范围内寻址,然后链接器将auipc转换为lui。这主要是为了使未定义的弱引用工作,因为这些引用在链接结束时总是为零当使用-mcmodel=medany时,通常不在auipc范围内。
在这篇博文中有更多的细节,以及对RISC-V代码模型的精确描述: RISC-V 代码模型

RISC-V auipc指令:
RISC-V的auipc指令是一条伪指令,它用于将一个20位的立即数符号扩展为32位,然后将其加到PC的高20位中,生成一个32位的地址。 auipc指令的操作码是0000001,其立即数位于指令的低12位。
具体地,auipc rd,imm指令的语法如下:
auipc rd,imm
其中,rd是目标寄存器的编号,imm是一个20位的有符号立即数。该指令的执行过程如下:
1.将imm符号扩展为32位,记为se_imm。
2.将PC的高20位左移12位,得到一个32位的地址高20位,记为pc_hi。
3.将se_imm和pc_hi相加,得到一个32位的地址,并将其存入rd寄存器中。
例如,执行auipc x1,0x12345指令时,如果当前的PC值为0x80000000,那么该指令的执行结果为:
1.se_imm的值为0xfffff234。
2.pc_hi的值为0x80000000的高20位0x80000左移12位后得到的值0x80000000。
3.将se_imm和pc_hi相加,得到的结果为0x800ffff4,并将其存入x1寄存器中。
因此,执行完该指令后,x1寄存器中的值为0x800ffff4。

链接器文件选项

在我们深入研究示例之前,有必要注意不同的链接器组合可在freedom-e-sdk存储库中为risc-v的核心提供。选项通过使用来选择 LINK_TARGET选项,在存储库README文件中描述。
 metal.default.lds这个链接器选项将代码和数据映射到Flash,除了未初始化的RAM section .bss,以及堆栈和堆,它们总是驻留在RAM中;
 metal.ramrodata.lds这个链接器选项映射只读数据节.rodata和.rdata 到RAM,除了.bss,堆栈和堆,将可执行代码放在Flash
 metal.scratchpad.lds -此链接选项将所有内容映射到RAM,不使用Flash

4.1标准链接器选项
下面的链接器文件示例表示了一些的示例内存映射配置 SiFive的32位和64位标准内核。

  • 8
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值