Dino Saric
Dino Saric

Reputation: 127

Weak function definitions for interrupt vector in a static library are preferred over strong ones

Introduction

I wrote the CMake build system for Nordic NRF5 SDK (natively it only supports makefiles). The build system has a executable (application) and multiple underlying static libraries. The dependencies go like this:

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
)

Problem

I have created a custom C hard-fault handler on top of the Nordic nRF5 SDK. It works with the previous build system (makefile build system). It must be noted that the previous build system does not create the static libraries, as does the new CMake system. It just links everything unconditionally.

In the perfect world, the user of the SDK (i.e., I) should define a callback (HardFault_c_handler) and it will be called by the interrupt vector in case of a hard-fault.

In the nRF5 SDK library, a startup file (modules/nrfx/mdk/gcc_startup_nrf52840.S) is included in the target nrf5_sdk (static library). The relevant code for this problem:

__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

Additionally, there is a strong defition of HardFault_Handler in a c file that should take precedence over this weak definition. The file (components/libraries/hardfault/nrf52/handler/hardfault_handler_gcc.c) contains:

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)
    );
}

The code from the c file should be called by the MCU in a case of the hard-fault, but it does not.

My question is why? How to make it prefer the strong function? My thinking now, although I am not sure. Because this callback, i.e., HardFault_Handler, is not referenced in the main application (or before getting to the startup file) the linker does not need to resolve it. Only when it sees this symbol in the startup file it looks for it, and because this is a static library it only looks for the first occurrence.

Things I tried

Edit

My linker flags:

-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

Upvotes: 1

Views: 1376

Answers (1)

Dino Saric
Dino Saric

Reputation: 127

I figured out, as I am using CMake, that I can supply OBJECT keyword with the add_library() function. In that case the keyword works as expected. Take note that object library linked to another object library does not work properly. And the underlying object library must, also, be included in the top-most (non-object library) target.

Upvotes: 3

Related Questions