我的场景是关于交叉编译到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。
nm报告libHardware.a
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
(分组是必要的,因为OS依赖于低级硬件功能。硬件需要调用操作系统提供的IRQ / main()函数)
nm报告:
...
00080124 W SysTick_Handler
...
它仍然很弱!我希望它使用libOS.a中定义的强符号。 最后,SysTick没有得到处理,这当然会导致灾难性的失败。
另一方面,如果我没有在libHardware / startup_sam3xa.c中将它们声明为弱,那么一切正常。 如果我选择在app / app.c中实现SysTick_Handler,它也会强烈关联。
所以我的问题是:libOS.a如何实现libHardware.a中定义的弱处理程序? 或者这些固件开发场景中的最佳实践是什么?
答案 0 :(得分:2)
在 cortex_handlers.c 中定义SysTick_Handler
时,它会定义正常的入口点。但只有当链接器获取链接特定目标文件的请求时,它才会覆盖弱符号(来自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
。
答案 1 :(得分:0)
感谢harper的上述回答,我发现Arduino通过将所有弱定义从startup_sam3xa.c移动到他们的cortex_handlers.c文件来解决了这个问题,以便弱defs属于“OS” “而不是硬件(使用OP的语言)。
答案 2 :(得分:0)
另一个解决方案是将处理程序(或其他)的源代码分开,但是将#include到源文件中,在使用库时必须始终引用该文件(如果您的库有这样的东西而且不是全部可选的)。 )使用不同于另一个答案的单词,链接器在检查库时.a以目标文件为单位工作.o:如果目标文件具有任何符号,当链接器在.o单元上传递时解析未解析的符号存档(以及链接器可以进行多次传递),链接器将目标文件中的所有符号放入链接的二进制文件中,解析未解析的符号并覆盖弱定义。链接命令中的库顺序很重要,您可能需要一个库在链接命令中出现两次。链接器标志整个存档也可以解决问题。我的回答很简洁,但可能是错的。