Reputation: 3707
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
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
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:
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
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