Search code examples
csymbolsfirmwareweakcmsis

Can weak symbol be resolved among libraries during linking?


My scenario is about cross-compiling to a Arduino Due (ARM target), but I guess it's a generic C weak symbol problem.

I want to break my firmware into 3 parts: 1. The hardware library (CMSIS, Middleware) -> libHardware.a 2. Realtime OS library -> libOS.a 3. Application code -> Output.elf linked to above.

the referenced CMSIS implementation has declared the followings:

void SysTick_Handler    ( void ) __attribute__ ((weak, alias("Dummy_Handler")));
// ...and a few dozen IRQ handler hook skipped for brevity

The idea of the CMSIS design is to have the Application Code implementing and handling some of IRQ selectively.

nm reports for libHardware.a

startup_sam3xa.o:
00000000 W SysTick_Handler
...

And in my scenario, I would like to implement theses IRQ handlers in the libOS.a.

I implement void SysTick_Handler(void), nm reports:

cortex_handlers.o:
00000000 T SysTick_Handler
....

Then I link them together, which basically boils down to

g++ -o app.elf -Wl,--start-group app.o libHardware.a libOS.a -Wl,--end-group

(Grouping is necessary because OS depends on the low level Hardware function. And Hardware need to calls the IRQ/main() function provdided by the OS)

nm reports:

...
00080124 W SysTick_Handler
...

It's still weak! I expect it to be using the strong symbol defined in the libOS.a. At the end, SysTick isn't handled, which of course leads to catastrophic failure.

On the other hand, if I don't declare them as weak in libHardware/startup_sam3xa.c, everything works fine. If I choose to implement SysTick_Handler in the app/app.c, it's strongly linked too.

So my question is: how could libOS.a implements the weak handler defined in libHardware.a? Or what would be the best practice in these firmware development scenarios?


Solution

  • When you define the SysTick_Handler in cortex_handlers.c it defines the normal entry point. But it will overwrite the weak symbol only when the linker gets a request to link the specific object file (from libOS.a).

    The libHardware.a usually defines the Interrupt vector table where the SysTick_Handler is referenced. This is the only pointer this actual name comes in the game. (For the ARM it's just an entry in the vector table.) The same library already provides a weak symbol. Therefore the linker doesn't search for that symbols anymore. When you want to overwrite the symbol in cortex_handlers.c you need to reference any symbol in that file causing the linker to use cortex_handlers.o. That will kick off the weak symbol.

    // cortex_handlers.c
    
    void SysTick_Handler()
    {
    }
    
    int link_my_cortex_handlers_file;
    

    Just reference somewhere the symbol link_my_cortex_handlers_file.