gpt4 book ai didi

gcc - 链接静态库不等同于链接其对象

转载 作者:行者123 更新时间:2023-12-04 19:59:38 24 4
gpt4 key购买 nike

问题:

与静态库链接时生成的固件镜像与与直接从静态库中提取的对象链接时生成的固件镜像不同。

两个固件镜像均无错误链接并成功加载到微 Controller 上。

后一个二进制文件(与对象链接)按预期成功执行,而前者(链接到静态库)不会。

编译期间唯一的警告是 unused-but-set-variable在制造商提供的 HAL 中,由于各种宏定义,编译实现不需要;和 unused-parameter在各种弱功能中,也在制造商提供的 HAL 中。

说明:

我正在为 STM32F407 开发嵌入式应用程序。到目前为止,我一直在使用一个代码库,包括微处理器的 HAL 和设置代码、特定外围设备的驱动程序以及利用前两者的应用程序。

由于我希望使用相同的驱动程序和 HAL 开发多个应用程序(两者都是完整和经过测试的,因此不会经常更改),我希望将 HAL 和驱动程序编译和分发为静态库,然后可以将其与应用程序源。

问题是当链接应用程序和静态库时,固件镜像无法在微处理器上正确执行。当链接应用程序和直接从静态库中提取的目标文件时,固件镜像按预期执行。

具体:

使用以下方法与静态库链接时,创建的二进制文件不起作用:

$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(APPOBJECTS) Library/libtest.a

创建的二进制文件在链接使用从静态库中提取的对象时有效:
@cd Library && $(AR) x libtest.a && cd ..
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(APPOBJECTS) Library/*.o

在这两种情况下:
CFLAGS = $(INCLUDES) $(DEFS) -ggdb3 -O0 -std=c99 -Wall -specs=nano.specs -nodefaultlibs
CFLAGS+= -fdata-sections -ffunction-sections -mcpu=cortex-m4 -march=armv7e-m -mthumb
CFLAGS+= -mfloat-abi=hard -mfpu=fpv4-sp-d16 -MD -MP -MF $@.d

LDFLAGS = -T$(LDSCRIPT) -Wl,-static -Wl,-Map=$(@:.elf=.map),--cref -Wl,--gc-sections

我比较了 -Wl,--print-gc-sections 的输出以及 app.map文件,但两个版本之间的差异已经足够大了,没有一件事情会因为错误而跳出来。我也试过没有 -Wl,--gc-sections ,无济于事。
arm-none-eabi-size的输出两个固件镜像中的一个是:
 text      data     bss     dec     hex filename
43464 76 8568 52108 cb8c workingapp.elf

text data bss dec hex filename
17716 44 8568 26328 66d8 brokenapp.elf

在没有 -Wl,--gc-sections 的情况下编译时可以看到类似的大小差异。

使用 arm-none-eabi-gdb为了调试微 Controller 的执行,当 WWDG 中断发生时,故障固件镜像进入无限循环。此中断在固件中未启用,因此中断处理程序默认为 Default_Handler (无限循环)。运行工作固件镜像时不会发生此中断。

发生的 WWDG 中断实际上是一个红鲱鱼,如已接受的答案 中所述。

- 麦克风

最佳答案

摘要:

问题是并非静态库中的所有对象都包含在固件镜像中。这是通过用 --whole-archive 包围静态库来解决的。和 --no-whole-archive链接器标志:

 $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(APPOBJECTS) -Wl,--whole-archive Library/libtest.a -Wl,--no-whole-archive

出现问题是因为如果链接器包含具有弱符号定义的库对象,它会认为这些符号已定义,并且不再搜索它们的(强)定义。因此,具有强定义的对象可能包含也可能不包含,这取决于搜索顺序和它定义的其他符号。

解决路径:

使用 arm-none-eabi-gdb调试时,似乎正在发生禁用的 WWDG 中断并调用 Default_Handler .结果证明这是一个红鲱鱼......这种情况经常发生,它让我通过 "STM32 WWDG interrupt firing when not configured" 找到了答案。堆栈溢出帖子。

在阅读这篇文章并了解到共享相同内存地址的函数的 gdb 函数名称报告通常不准确时,我检查了生成的 .map错误固件镜像文件并确认 WWDG_IRQHandler位于与大多数 IRQHandler 相同的内存地址,包括用于系统定义和使用的中断的 IRQHandler(例如,某些定时器中断)。

此外,在 stm32f4xx_it.o 中定义的所有中断对象(定义了系统使用的中断的 IRQHandlers,包含在静态库中)指向 Default_Handler 的内存地址。 , 并且各个 IRQHandler 符号被列为由 startup_stm32f407xx.o 提供.

然后我检查了哪些目标文件实际上链接到固件镜像 ( perl -n -e '/libtest\.a\((.*?)\)/ && print "$1\n"' app.map | sort -u ) 中,发现只有一部分对象被链接。

进一步检查 startup_stm32f407xx.s表明它定义了许多弱符号,例如:
.weak TIM2_IRQHandler

在链接静态库的过程中,链接器在库中搜索 undefined symbol ,并包括它找到的第一个定义这些符号的对象。然后它从未定义列表中删除符号,以及由包含的对象定义的任何其他 undefined symbol 。

我对发生的事情的猜测是链接器在 startup_stm32f407xx.o 中发现了一个其他 undefined symbol 。并包含对象。它认为所有 IRQHandler 符号都由其中的弱定义定义。对象 stm32f4xx_it.o从未包括在内,因为它没有定义任何 undefined symbol 。这发生了很多次,有很多不同的目标文件;有时包括强符号,有时包括弱符号,这取决于首先搜索哪个对象。有趣(但并不奇怪)是,如果弱定义被删除,包含强定义的对象将被包含在内,并且该文件中的所有强定义(正确地)覆盖已经包含的弱定义。

解决了这个问题,我不知道从哪里开始。这是链接器错误吗?

关于gcc - 链接静态库不等同于链接其对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30355013/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com