ARM Cortex-M7 长分支在编译时出现错误“relocation truncated to fit: R_ARM_PREL31”

Posted

技术标签:

【中文标题】ARM Cortex-M7 长分支在编译时出现错误“relocation truncated to fit: R_ARM_PREL31”【英文标题】:ARM Cortex-M7 long branch get error "relocation truncated to fit: R_ARM_PREL31" at compiling time 【发布时间】:2019-03-09 07:53:34 【问题描述】:

我正在使用 NXP 的 I.MXRT 系列 Cortex-M7 芯片开发嵌入式系统。我需要在 RAM(ITCM) 中重定位一些 C 函数,而不是在 Flash 中。 ITCM 的地址从 0x00000000 开始,Flash 从 0x60000000 开始。因此,位于 Flash 的函数调用位于 ITCM 的函数将执行长分支。但它得到一个编译错误

(.ARM.exidx.itcm.text+0x0):重定位被截断以适应:R_ARM_PREL31 针对 `.itcm.text'

这是我的代码

__attribute__ ((long_call,section(".itcm.text"),noinline))
int foo(int k)

     return k + 1;

我的链接脚本

MEMORY

 /*
 *  SPI Flash 
 *  
 *  
 */
ITCM(xrw) : ORIGIN = 0x00000000, LENGTH = 128K
DTCM (xrw) : ORIGIN = 0x20000000, LENGTH = 256K
RAM (xrw) : ORIGIN =   0x20200000, LENGTH = 256K
FLASH (rx) : ORIGIN =  0x60000000, LENGTH = 4096K

 /*************omit***************/
_siitcm = LOADADDR(.itcm.text);
.itcm.text : ALIGN(4)

    __itcm_start__ = .;
    *(.itcm.text .itcm.text.*)
    . = ALIGN(4);
    __itcm_end__ = .;
 >ITCM AT>FLASH

编译器标志是

arm-none-eabi-gcc -mcpu=cortex-m7 -mthumb $FP_FLAGS -std=c++11 -O3 -munaligned-access -ffunction-sections -fdata-sections -ffreestanding

链接器标志是

"arm-none-eabi-gcc -mcpu=cortex-m7 -mthumb $FP_FLAGS -std=c++11 -O3 -munaligned-access -ffunction-sections -fdata-sections -ffreestanding -T $ MEM_LD_FILE -T $LIBS_LD_FILE -T $SECTIONS_LD_FILE -nostartfiles -Xlinker -gc-sections -u _printf_float -Wl,-Map=$TARGET_MAP --specs=nano.specs"

当分支地址大于0x40000000时似乎会发生错误。那么,如何解决这个问题呢?

/* 第二版 */

我通过添加编译器标志 -fno-exceptions 解决了这个问题。但是不知道为什么?

【问题讨论】:

使用彼此靠近的虚假地址,构建它,查看它使用的地址和说明,这应该可以解释它。 或者实际上只是查看目标文件,因为它无法链接它... 您可以从Exception Handling ABI for the ARM Architecture (ARM IHI 0038B) 中获得一些关于-fno-exceptions 行为的见解,特别是第4.4.2 节“重定位”,其中提到了使用R_ARM_PREL31 进行偏移。 R_ARM_PREL31 是 31 位 2 的补码 - 注意:不是 32 位数字。见ELF for the ARM Architecture (ARM IHI 0044E) 如果您将进入 RAM(ITCM) 的 C 函数编译为 C 而不是 C++,也许会有所帮助? 嗯,31位2的补码的跳转地址确实是+- 0x40000000。但它应该使用一个长分支指令 BLX Ri,它可以根据 ARM 的手册跳转所有 32 位地址空间。其实我也不清楚什么是“搬家”?我的项目包含 C 和 C++ 文件。进入 ITCM 的函数位于外部“C”块中。但我认为链接器是 C++。 【参考方案1】:

ARM-EABI 指定异常胶合代码是 31 位相对的。这意味着所有可以抛出或捕获的 C++(即,具有 C++ 链接,而不是 -fno-exception)将需要位于内存中,距离 .ARM-extab 和 .ARM 不超过 30 位(正负) .exidx 部分或相对偏移量将不足 - 因此错误。

ARM-EABI 很可能利用了 Linux 默认用户空间,即 ARM32 地址空间的 32 位中的低 31 位。

所以,看看你的内存映射。是否有 stash +-30 位来放置 extab/exidx 以最大程度地覆盖您的 .text 内存(XIP 闪存、SDRAM、OCRAM)?您可以(通过链接器脚本)将您的 C++ 限制在所覆盖的区域吗?您可以将非文本(数据、bss 等)放在超出范围的内存中吗? (数据和非 C++ 和 C++-noexception .text 访问不是 REL31 - 只有 C++ 异常是。)

【讨论】:

以上是关于ARM Cortex-M7 长分支在编译时出现错误“relocation truncated to fit: R_ARM_PREL31”的主要内容,如果未能解决你的问题,请参考以下文章

为 ARM NEON 编译时出现未知的 GCC 错误(严重)

我的数码相框.c文件用arm-linux-gcc交叉编译时出现错误,如tgzip.c:309:undefined reference to

安装arm-linux-gcc编译器时出现错误,请大神看看怎么回事

编译linux内核时出现"mkimage" command not found - U-Boot images will not be built错误的解决办法

Swift:从 iOS 7 编译存档时出现分段错误

在ARM Cortex-M上实现FreeRTOS性能计数器