1

Introduction

  • arm-none-eabi-gcc version 10.3-2021.10 20210824
  • device: nordic nRF52840/nRF52832/nRF52833
  • library affected: Nordic NRF5 SDK 17.1.0 - custom build system (CMake)

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

  • removing static libraries, this fixes the problem,
  • separating weak definition of the HardFault_Handler into separate assembly file, this makes the linker link the function from the file that appears first, using -Wl,-trace-symbol=HardFault_Handler I see that the linker only looks for the first occurence and than stops (irrelevant of weak and strong).
  • putting c file before the startup file in the sources, does not change the result.

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
Dino Saric
  • 107
  • 7
  • https://stackoverflow.com/questions/51656838/attribute-weak-and-static-libraries/51894960#51894960 https://stackoverflow.com/questions/66656557/linking-multiple-static-libraries/66659384#66659384 https://stackoverflow.com/questions/64501446/how-to-change-cmake-linking-order/64502052#64502052 – KamilCuk Jan 12 '22 at 12:04
  • There are nuances about weak symbols inside static libraries and linking ordering, see e.g. [this question](https://stackoverflow.com/questions/13089166/how-to-make-gcc-link-strong-symbol-in-static-library-to-overwrite-weak-symbol) or [that one](https://stackoverflow.com/questions/23079997/override-weak-symbols-in-static-library). CMake is not a "magic" tool: it just calls the compiler for create a library and the linker for link the executable. With `make VERBOSE=1` you could examine exact compiler and linker command lines produced by CMake. – Tsyvarev Jan 12 '22 at 12:04
  • As I states in my original post, ``` My question is why? How to make it prefer the strong function? ``` I am familiar with the theory behind the weak and static library, so those links are not helpful, but thank you for your comments. But I posted this question to have someone confirm that this is impossible to solve without editing the startup assembly file (i.e., removing the weak definition). @Tsyvarev I know CMake. I have used verbose build system. It was not that helpful, the most helpful thing was the tracing of symbols, as described in the original post. – Dino Saric Jan 12 '22 at 14:55
  • To continue, can anyone sure in their abilities around this confusing `weak` subject, confirm that the solution for this problem (with keeping the static libraries) is removing the weak implementation from the startup assembly file. My conclusions till now, are in the original post. – Dino Saric Jan 12 '22 at 14:59
  • Or if someone who is smarter about this than me, can suggest a more elegant solution (I do not want to edit external code). – Dino Saric Jan 12 '22 at 15:06
  • "I posted this question to have someone confirm that this is impossible to solve ...". Probably, you think: "There is high chance that someone has already successfully used weak symbols with CMake, so he/she could give me a receipt". But with weak symbols almost **every case is unique**: receipt, which works in one case, could fail with with very similar, but different case. For find working receipt in your case, one should examine **all details** of your case. Not sure whether someone want to do that. Taking into account that your post doesn't provide all these details. – Tsyvarev Jan 12 '22 at 17:00
  • Isn't that what stack overflow is for? Examining the question, discuss it, and in the end reaching an conclusion? Unfortunately, this problem is complex to me to explain and therefor I do not know what details to give, and which to omit. I am open to questions about the details of my problem. I am sorry but you assumed incorectly here: "There is high chance that someone has already successfully used weak symbols with CMake, so he/she could give me a receipt". This is not a CMake problem, CMake is just a "wrapper" over the compiler/linker. This is a gcc linking problem. – Dino Saric Jan 13 '22 at 07:15

1 Answers1

1

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.

Dino Saric
  • 107
  • 7