链接器重定位被截断以适合:R_ARM_THM_JUMP11 错误和 gcc 输出太大

Linker relocation truncated to fit: R_ARM_THM_JUMP11 error and gcc output too big

我从 4 年来一直是一名嵌入式程序员。我一直在使用微芯片 PIC 和 ST STM32,但我从来没有做过真正的裸机编程,因为我一直使用 Microchip 代码配置或 ST CubeMX 来为我完成工作。

但是,作为对该领域感兴趣的人,我想尝试在 NUCLEO-F072RB 上进行一些裸机编程,例如,了解编译器如何知道将每一位程序放在哪里。

作为教程,我关注了这个博客 https://vivonomicon.com/2018/04/02/bare-metal-stm32-programming-part-1-hello-arm/ 并进行了必要的修改以适应我的硬件。

在变得更加自信并开始我自己的 GPIO 外设驱动程序的“HAL”实现之后,我很快就遇到了 linker 错误:

startup_stm32f072rb.o: in function reset_bss_loop: (.text.default_interrupt_handler+0x2c): relocation truncated to fit: R_ARM_THM_JUMP11 against symbol `main' defined in .text section in main.o

我已经对此类错误进行了研究,据我了解,编译器似乎在告诉 linker [=40= 中有一个名为 main 的符号]... 文件并且相同的符号也在主文件中。然而,linker 告诉这两个符号的地址不匹配,或者有一个必须在内存的最大地址之外。

在调试了一下之后,我有了提高优化级别的想法。它工作正常,源代码相同。

所以现在,我假设问题出在我的编译方式和 link 生成的可执行文件对我的硬件来说太大了。但是考虑到我的项目相对较小,我真的不明白这怎么可能。

所以,我真正的问题是:我怎样才能理解这里发生的事情?有没有办法在不使用 -O1 的情况下编译相同的源代码?这对我来说似乎不是正确的解决方案(只是掩盖潜在问题的技巧)。

我使用的源代码位于此处https://github.com/FlorianRemy/bare_metal_part3。 有几段代码(启动、makefile 和 linker 脚本)几乎是从教程中复制的,寄存器操作的宏定义(在 misc_definition.h 中)来自老师。

编辑

如已接受的答案中所述,问题出在 B(ranch) 指令中,该指令的宽度不足以解决主标签所在的位置。 但是,B.W 指令不受 cortex-m0 架构的支持。根据 STM32F072 编程手册(第 59 和 60 页),在这种情况下使用的正确指令似乎是 BL,这解决了我的问题。

问题出在您的启动代码上。正如链接器错误告诉您的那样,在您“调用” main (实际上只是分支到它)的重置向量末尾存在问题;也就是说,您用来分支到 main 的分支指令在其标签字段中没有足够的位来满足链接器最终放置 main.

所需的偏移量

因此,这并不是真正的硬件限制,而是您使用的指令的限制 (B main),因为在 ARM Thumb16 中,您可以分支的距离非常有限。优化代码有帮助的原因是现在代码整体更小(当你的代码整体更少时就是这种情况)所以 main 的开始和重置向量末尾的分支之间的闪存距离足够小,可以与 Thumb16 版本的分支一起工作。您是正确的,您只是在掩盖问题,并且随着您进一步推进并添加更多代码,即使在您的编译中进行了优化,问题也可能会再次出现。

要解决这个问题,请尝试强制汇编器对分支指令使用 32 位编码,这样您就有了更大范围的偏移量,因此总能从您的分支指令到达 main

B.W main /* instead of B main at the end of reset_handler */

编辑:

如前所述,由于此指令集不支持 B.W,因此使用 BL 会导致分支所需的范围更广