与静态库链接不等同于与对象的链接 [英] Linking with static library not equivalent to linking with its objects

查看:321
本文介绍了与静态库链接不等同于与对象的链接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题:



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



两个固件映像链接无错误,并成功加载到微控制器。



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



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



说明:



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



由于我希望使用相同的驱动程序开发多个应用程序HAL(都是完整和测试的,所以不会经常改变),我希望编译&将HAL和驱动程序分发为一个静态库,然后可以与应用程序源相关联。



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



具体来说:



当使用静态库链接时,创建的二进制文件不起作用:

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

当使用以下方式链接从静态库提取的对象时,创建二进制文件:

  @cd Library& $(AR)x libtest.a&&& cd .. 
$(CC)$(CFLAGS)$(LDFLAGS)-o $ @ $(APPOBJECTS)库/ *。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 ,无效。



两个固件映像的code> arm-none-eabi-size 是:

 文本数据bss dec十六进制文件名
43464 76 8568 52108 cb8c workingapp.elf

文本数据bss dec十六进制文件
17716 44 8568 26328 66d8 brokenapp.elf

在不使用 -Wl, - gc-sections



使用 arm-none-eabi-gdb 来调试微控制器的执行,故障的固件映像当发生WWDG中断时,进入无限循环。该中断在固件中未启用,因此中断处理程序默认为 Default_Handler (无限循环)。



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



- Mike

解决方案

strong>



问题是,静态库中并非所有对象都包含在固件映像中。通过使用 - 整个存档 - no-whole-archive 链接器围绕静态库来解决这个问题标志:

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

问题是因为如果链接器包含具有弱符号定义的库对象,则它会定义这些符号,并且不再搜索它们的(强)定义。因此,根据搜索顺序和其定义的其他符号,具有强定义的对象可能包含或可能不包括在内。



解决方案路径: / p>

使用 arm-none-eabi-gdb 进行调试,似乎禁用发生WWDG中断,并调用 Default_Handler 。这原来是一个红色的鲱鱼,它经常发生,这导致我通过STM32 WWDG中断未配置时触发 stackoverflow post。



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

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



然后我检查哪些对象文件实际链接到固件映像( perl -n -e'/libtest\.a\((.*? )\)/&&打印$ 1\\\
'app.map | sort -u
),并发现只有一个对象的子集被链接。



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

  .weak TIM2_IRQHandler 

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



我猜测发生了什么是连接器在 startup_stm32f407xx.o 中找到了一个未定义的符号,并包含该对象。它认为所有IRQHandler符号都由其中的弱定义来定义。对象 stm32f4xx_it.o 从未包含,因为它没有定义任何未定义的符号。这发生了很多次,有不同的目标文件;有时包含强符号,有时候包含弱符号,具体取决于首先搜索哪个对象。有趣的(还不足为奇)的是,如果删除弱定义,则包含强定义的对象被包含在内,并且该文件中的所有强定义(正确地)覆盖了已经包含的弱定义。 p>

解决问题后,我不知道从哪里走。这是一个链接器错误吗?


Problem:

The firmware image generated when linking with a static library is different to the firmware image generated when linking with the objects directly extracted from the static library.

Both firmware images link without error and load successfully onto the microcontroller.

The latter binary (linked with objects) executes successfully and as expected, while the former (linked to the static library) does not.

The only warnings during compilation are unused-but-set-variable in the manufacturer-supplied HAL, which due to various macro definitions are not necessary for the compiled implementation; and unused-parameter in various weak functions, also within the manufacturer-supplied HAL.

Description:

I am developing an embedded application for the STM32F407. Until now I have been working with one code base including the microprocessor's HAL & setup code, a driver for a specific peripheral, and an application utilizing the former two.

Since I wish to develop multiple applications using the same driver & HAL (both are complete and tested, so won't change often), I wish to compile & distribute the HAL and driver as a static library, which can then be linked with the application source.

The problem is that when linking the application and static library, the firmware image does not execute correctly on the microprocessor. When linking the application and the object files directly extracted from the static library, the firmware image executes as expected.

Specifically:

Created binary does not work when linking with static library using:

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

Created binary works when linking with objects extracted from static library using:

@cd Library && $(AR) x libtest.a && cd ..
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(APPOBJECTS) Library/*.o

In both cases:

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

I have compared the outputs of -Wl,--print-gc-sections as well as the app.map file, but enough is different between the two builds that no one thing jumps out as being wrong. I have also tried without -Wl,--gc-sections, to no avail.

The output of arm-none-eabi-size of the two firmware images is:

 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

A similar size discrepancy can be seen when compiling without -Wl,--gc-sections

Using arm-none-eabi-gdb to debug the microcontroller's execution, the faulty firmware image enters an infinite loop when the WWDG interrupt occurs. This interrupt is not enabled in the firmware and thus the interrupt handler defaults to the Default_Handler (an infinite loop). This interrupt does not occur when running the working firmware image.

The WWDG interrupt occurring is actually a red herring, as described in the accepted answer

--Mike

解决方案

Summary:

The issue was that not all objects from the static library were being included in the firmware image. This is solved by surrounding the static library with the --whole-archive and --no-whole-archive linker flags:

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

The issue arises because if the linker includes a library object with weak symbol definitions, it considers these symbols defined, and no longer searches for their (strong) definitions. Hence the object with strong definitions may or may not be included, depending on search order and what other symbols it defines.

Solution path:

Using arm-none-eabi-gdb to debug, it appeared that the disabled WWDG interrupt was occurring and calling the Default_Handler. This turned out to be a red herring... which has occured often enough that it led me to the answer via the "STM32 WWDG interrupt firing when not configured" stackoverflow post.

Upon reading this post and learning that the gdb function name reporting is often inaccurate for functions that share the same memory address, I checked the generated .map file for the faulty firmware image and confirmed that the WWDG_IRQHandler was located at the same memory address as the majority of IRQHandlers including the IRQHandlers for interrupts that are defined and used by the system (eg. some timer interrupts).

Furthermore, all interrupts defined in the stm32f4xx_it.o object (which defines the IRQHandlers for interrupts used by the system, and which is included in the static library) pointed to the memory address of the Default_Handler, and the respective IRQHandler symbols were listed as being supplied by startup_stm32f407xx.o.

I then checked which object files were actually linked into the firmware image (perl -n -e '/libtest\.a\((.*?)\)/ && print "$1\n"' app.map | sort -u) and found that only a subset of objects were linked.

Further inspection of startup_stm32f407xx.s showed that it defines many weak symbols, eg:

.weak TIM2_IRQHandler

During the process of linking a static library, the linker searches the library for undefined symbols and includes the first object it finds to define these symbols. It then removes the symbol from the undefined list, as well as any other undefined symbols that are defined by the included object.

My guess as to what happened is that the linker found an otherwise-undefined symbol in startup_stm32f407xx.o and included the object. It considered all IRQHandler symbols to be defined by the weak definitions therein. The object stm32f4xx_it.o was never included since it did not define any undefined symbols. This happened a number of times, with a number of different object files; sometimes the strong symbols were included, sometimes the weak symbols were included, depending on which object was searched first. Interesting (yet unsurprising) is that if the weak definition is removed, the object containing the strong definition is included, and all strong definitions from that file (correctly) override the already-included weak definitions.

Having solved the problem, I'm not sure where to go from here. Is this a linker bug?

这篇关于与静态库链接不等同于与对象的链接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆