静态库中中断向量的弱函数定义优于强函数定义
Weak function definitions for interrupt vector in a static library are preferred over strong ones
简介
- arm-none-eabi-gcc 版本 10.3-2021.10 20210824
- 设备:北欧nRF52840/nRF52832/nRF52833
- 受影响的库:Nordic NRF5 SDK 17.1.0 - 自定义构建系统 (CMake)
我为 Nordic NRF5 SDK 编写了 CMake 构建系统(它本身只支持 makefile)。构建系统有一个可执行文件(应用程序)和多个底层静态库。依赖关系是这样的:
application
...
- NordicAl (abstraction layer)
- nrf5_sdk
...
//root/CMakeLists.txt
add_executable(application)
...
add_subdirectory(lib/NordicAl)
...
target_link_libraries(application PRIVATE
nordic_al
...)
....
//root/lib/NordicAl/CMakeLists.txt
add_library(nordic_al)
...
add_subdirectory(lib/nrf5_sdk)
target_link_libraries(nordic_al PRIVATE
nrf5_sdk
...)
...
//root/lib/NordicAl/lib/nrf5_sdk/CMakeLists.txt
add_library(nrf5_sdk)
...
target_sources(nrf5_sdk PRIVATE
...
${NRF5_SDK_ROOT}/modules/nrfx/mdk/gcc_startup_${PLATFORM_MCU_FAMILY}.S
${NRF5_SDK_ROOT}/components/libraries/hardfault/nrf52/handler/hardfault_handler_gcc.c
)
问题
我已经在 Nordic nRF5 SDK 之上创建了一个自定义 C 硬故障处理程序。它适用于以前的构建系统(makefile 构建系统)。必须注意的是,以前的构建系统不会像新的 CMake 系统那样创建静态库。它只是 link 无条件地提供所有内容。
在完美世界中,SDK 的用户(即我)应该定义一个回调(HardFault_c_handler),并且在发生硬故障时由中断向量调用。
在nRF5 SDK库中,目标nrf5_sdk(静态库)中包含一个启动文件(modules/nrfx/mdk/gcc_startup_nrf52840.S)。本题相关代码:
__isr_vector:
.long __StackTop /* Top of Stack */
.long Reset_Handler
.long NMI_Handler
.long HardFault_Handler
...
.weak HardFault_Handler
.type HardFault_Handler, %function
HardFault_Handler:
b .
.size HardFault_Handler, . - HardFault_Handler
另外,在一个c文件中有一个HardFault_Handler
的强定义,应该优先于这个弱定义。文件 (components/libraries/hardfault/nrf52/handler/hardfault_handler_gcc.c) 包含:
extern void HardFault_c_handler(uint32_t *);
void HardFault_Handler(void) __attribute__(( naked ));
void HardFault_Handler(void)
{
__ASM volatile(
...
" .ltorg \n"
: : "X"(HardFault_c_handler)
);
}
c 文件中的代码应该在出现硬故障时由 MCU 调用,但它不会。
我的问题是为什么?如何让它更喜欢强函数?我现在的想法,虽然我不确定。因为这个回调,即 HardFault_Handler
,在主应用程序中没有被引用(或者在到达启动文件之前),所以 linker 不需要解析它。只有当它在启动文件中看到这个符号时它才会查找它,并且因为这是一个静态库它只查找第一次出现。
我尝试过的东西
- 删除静态库,这解决了问题,
- 将
HardFault_Handler
的弱定义分离到单独的汇编文件中,这使得 linker link 成为第一个出现的文件中的函数,使用 -Wl,-trace-symbol=HardFault_Handler
I看到 linker 只寻找第一次出现而不是停止(与弱和强无关)。
- 在源代码中将 c 文件放在启动文件之前,不会改变结果。
编辑
我的 link 标记:
-mcpu=cortex-m4
-mfloat-abi=hard
-mfpu=fpv4-sp-d16
-mthumb
-mabi=aapcs
-ffreestanding
-fno-common
-finline-small-functions
-findirect-inlining
-fstack-protector-strong
-ffunction-sections
-fdata-sections
-Wl,--gc-sections
--specs=nano.specs
我发现,在使用 CMake 时,我可以为 add_library()
函数提供 OBJECT
关键字。在这种情况下,关键字会按预期工作。请注意,链接到另一个对象库的对象库无法正常工作。并且底层对象库也必须包含在 top-most(non-object 库)目标中。
简介
- arm-none-eabi-gcc 版本 10.3-2021.10 20210824
- 设备:北欧nRF52840/nRF52832/nRF52833
- 受影响的库:Nordic NRF5 SDK 17.1.0 - 自定义构建系统 (CMake)
我为 Nordic NRF5 SDK 编写了 CMake 构建系统(它本身只支持 makefile)。构建系统有一个可执行文件(应用程序)和多个底层静态库。依赖关系是这样的:
application
...
- NordicAl (abstraction layer)
- nrf5_sdk
...
//root/CMakeLists.txt
add_executable(application)
...
add_subdirectory(lib/NordicAl)
...
target_link_libraries(application PRIVATE
nordic_al
...)
....
//root/lib/NordicAl/CMakeLists.txt
add_library(nordic_al)
...
add_subdirectory(lib/nrf5_sdk)
target_link_libraries(nordic_al PRIVATE
nrf5_sdk
...)
...
//root/lib/NordicAl/lib/nrf5_sdk/CMakeLists.txt
add_library(nrf5_sdk)
...
target_sources(nrf5_sdk PRIVATE
...
${NRF5_SDK_ROOT}/modules/nrfx/mdk/gcc_startup_${PLATFORM_MCU_FAMILY}.S
${NRF5_SDK_ROOT}/components/libraries/hardfault/nrf52/handler/hardfault_handler_gcc.c
)
问题
我已经在 Nordic nRF5 SDK 之上创建了一个自定义 C 硬故障处理程序。它适用于以前的构建系统(makefile 构建系统)。必须注意的是,以前的构建系统不会像新的 CMake 系统那样创建静态库。它只是 link 无条件地提供所有内容。
在完美世界中,SDK 的用户(即我)应该定义一个回调(HardFault_c_handler),并且在发生硬故障时由中断向量调用。
在nRF5 SDK库中,目标nrf5_sdk(静态库)中包含一个启动文件(modules/nrfx/mdk/gcc_startup_nrf52840.S)。本题相关代码:
__isr_vector:
.long __StackTop /* Top of Stack */
.long Reset_Handler
.long NMI_Handler
.long HardFault_Handler
...
.weak HardFault_Handler
.type HardFault_Handler, %function
HardFault_Handler:
b .
.size HardFault_Handler, . - HardFault_Handler
另外,在一个c文件中有一个HardFault_Handler
的强定义,应该优先于这个弱定义。文件 (components/libraries/hardfault/nrf52/handler/hardfault_handler_gcc.c) 包含:
extern void HardFault_c_handler(uint32_t *);
void HardFault_Handler(void) __attribute__(( naked ));
void HardFault_Handler(void)
{
__ASM volatile(
...
" .ltorg \n"
: : "X"(HardFault_c_handler)
);
}
c 文件中的代码应该在出现硬故障时由 MCU 调用,但它不会。
我的问题是为什么?如何让它更喜欢强函数?我现在的想法,虽然我不确定。因为这个回调,即 HardFault_Handler
,在主应用程序中没有被引用(或者在到达启动文件之前),所以 linker 不需要解析它。只有当它在启动文件中看到这个符号时它才会查找它,并且因为这是一个静态库它只查找第一次出现。
我尝试过的东西
- 删除静态库,这解决了问题,
- 将
HardFault_Handler
的弱定义分离到单独的汇编文件中,这使得 linker link 成为第一个出现的文件中的函数,使用-Wl,-trace-symbol=HardFault_Handler
I看到 linker 只寻找第一次出现而不是停止(与弱和强无关)。 - 在源代码中将 c 文件放在启动文件之前,不会改变结果。
编辑
我的 link 标记:
-mcpu=cortex-m4
-mfloat-abi=hard
-mfpu=fpv4-sp-d16
-mthumb
-mabi=aapcs
-ffreestanding
-fno-common
-finline-small-functions
-findirect-inlining
-fstack-protector-strong
-ffunction-sections
-fdata-sections
-Wl,--gc-sections
--specs=nano.specs
我发现,在使用 CMake 时,我可以为 add_library()
函数提供 OBJECT
关键字。在这种情况下,关键字会按预期工作。请注意,链接到另一个对象库的对象库无法正常工作。并且底层对象库也必须包含在 top-most(non-object 库)目标中。