Garf365
Garf365

Reputation: 3707

override a weak function A with a function B

For an embedded device, I have file containing an array with function pointers storing interrupt handlers, define like that (I can't modify it):

typedef void (*const ISRFunction)(void);

__attribute__((weak)) void ISR0(void){ for(;;); }
__attribute__((weak)) void ISR1(void){ for(;;); }
...
__attribute__((weak)) void ISR78(void){ for(;;); }
...

ISRFunction __vector_table[0x79] = 
{
    (ISRFunction)&ISR0,
    (ISRFunction)&ISR1,
    ...
    (ISRFunction)&ISR78,
    ...
}

I have a second file which defines some functions, which I can't modify. This file is like:

void blinkLed(void)
{ ... }

Finally, I have a main source file, with main function and configuration of device. On interrupt 78, I would like to blink led. So I write a strong function ISR78 like that:

void ISR78(void)
{
    blinkLed();
}

I wondered if there was a solution to override weak function ISR78 directly by blinkLed, ie storing address of blinkLed inside __vector_table without modifying it or rename function?


EDIT:

I actually use GNU gcc 4.9.3 and associated linker (GNU ld 2.24.0). I can modify main.c and Makefile associated to project.

Upvotes: 6

Views: 7446

Answers (3)

TrentP
TrentP

Reputation: 4692

You can use __asm("symbolname") to do this. This lets you change the name of the symbol used in the object file to be a specific string. Both gcc and clang support this.

Example:

void blinkLed(void) __asm("ISR78");  // Can only be used on a prototype
void blinkLed(void)
{ ... }

In your code, everything can use the name blinkLed. But in the object file the name will be ISR78 and it will override the weak version and be used as the interrupt vector.

This also works as a way to avoid C++ name mangling, even when you can't use extern "C".

template <int id>
struct Timer {
   static void blinkled();
};

template <> Timer<1>::blinkled() __asm("ISR71");
template <> Timer<2>::blinkled() __asm("ISR72");

Above we have a class template with an ISR, blinkled(), as a static method. Then we define two specializations of that ISR for two different timers, and give each correct name for the interrupt vector it is on.

Upvotes: 2

Useless
Useless

Reputation: 67743

tl;dr: you have a working solution already, which appears to be the solution explicitly supported and encouraged by using weak symbols in the first place. What improvement do you expect from a different solution?


Linker symbols are looked up by name, so the only alternatives to using the expected name are:

  1. tofro's suggestion to modify the link step directly
  2. modify the function pointer table yourself

The whole point of making ISR78 a weak symbol in the first place is to allow exactly the override (by symbol name) you've already used.

I can't see any way modifying the interrupt vector table is better than just using the expected function name directly, even if it's possible.

Upvotes: 2

tofro
tofro

Reputation: 6063

The only way I see to achieve what you want to do is to patch the symbol table of the object file containing the blink symbol with the ISR78 symbol.

objcopy [...] --redefine-sym blink=ISR78

should do that. The linker should then automatically insert the address of the former blink into the vector table. Obviously, your blink symbol is gone after that and shouldn't be called from other places.

I would, however, consider this a hack.

In case _vector_table is globally accessible and in writable memory (not assumed, that's probably too simple...), you could simply patch it from your own code by

_vector_table [0x78] = blink;

at runtime.

Upvotes: 2

Related Questions