2

我的场景是关于交叉编译到 Arduino Due(ARM 目标),但我想这是一个通用的 C 弱符号问题。

我想将我的固件分成 3 个部分: 1. 硬件库(CMSIS,中间件)-> libHardware.a 2. 实时操作系统库 -> libOS.a 3. 应用程序代码 -> 链接到上面的 Output.elf。

引用的 CMSIS 实现声明了以下内容:

void SysTick_Handler    ( void ) __attribute__ ((weak, alias("Dummy_Handler")));
// ...and a few dozen IRQ handler hook skipped for brevity

CMSIS 设计的想法是让应用程序代码有选择地实施和处理一些 IRQ。

libHardware.a 的 nm 报告

startup_sam3xa.o:
00000000 W SysTick_Handler
...

在我的场景中,我想在 libOS.a 中实现这些 IRQ 处理程序。

我实现了 void SysTick_Handler(void),nm 报告:

cortex_handlers.o:
00000000 T SysTick_Handler
....

然后我将它们链接在一起,这基本上归结为

g++ -o app.elf -Wl,--start-group app.o libHardware.a libOS.a -Wl,--end-group

(分组是必要的,因为操作系统依赖于底层硬件函数。硬件需要调用操作系统提供的 IRQ/main() 函数)

纳米报告:

...
00080124 W SysTick_Handler
...

还是很弱!我希望它使用 libOS.a 中定义的强符号。最后,没有处理 SysTick,这当然会导致灾难性的失败。

另一方面,如果我没有在 libHardware/startup_sam3xa.c 中将它们声明为弱,那么一切正常。如果我选择在 app/app.c 中实现 SysTick_Handler,它也是强链接的。

所以我的问题是:libOS.a 如何实现 libHardware.a 中定义的弱处理程序?或者在这些固件开发场景中,最佳实践是什么?

4

3 回答 3

2

当您SysTick_Handlercortex_handlers.c中定义时,它定义了正常的入口点。但只有当链接器收到链接特定目标文件(来自 libOS.a)的请求时,它才会覆盖弱符号。

libHardware.a 通常定义引用的中断向量表SysTick_Handler。这是这个实际名称出现在游戏中的唯一指针。(对于 ARM,它只是向量表中的一个条目。)同一个库已经提供了一个弱符号。因此链接器不再搜索该符号。当您想要覆盖cortex_handlers.c中的符号时,您需要引用该文件中导致链接器使用cortex_handlers.o的任何符号。这将启动弱符号。

// cortex_handlers.c

void SysTick_Handler()
{
}

int link_my_cortex_handlers_file;

只需在某处引用符号link_my_cortex_handlers_file

于 2014-03-04T17:15:53.333 回答
0

感谢 harper 的上述回答,我发现 Arduino 通过将所有弱定义从 startup_sam3xa.c 移动到他们的 cortex_handlers.c 文件中解决了这个问题,以便弱定义属于“操作系统”而不是硬件(使用 OP 的语言)。

于 2015-06-07T06:10:39.277 回答
0

另一种解决方案是将您的处理程序(或其他)的源代码分开,但将其#include 到使用库时必须始终引用的源文件中(如果您的库有这样的东西并且不是全部可选的。)使用不同的与另一个答案相比,链接器在检查库 .a 时以目标文件 .o 为单位工作:如果目标文件有任何符号可以在链接器通过存档中的 .o 单元时解析未解析的符号(并且链接器可以进行多次传递),链接器将目标文件中的所有符号放入链接的二进制文件中,解析未解析的符号并覆盖弱定义。链接命令中库的顺序很重要,您可能需要一个库在链接命令中出现两次。链接器标志whole-archive也可以解决这个问题。我的回答很简洁

于 2017-06-05T18:31:43.777 回答