用函数B覆盖弱函数A

问题描述 投票:0回答:3

对于嵌入式设备,我有一个包含数组的文件,其中的函数指针存储中断处理程序,像这样定义(我无法修改它):

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,
    ...
}

我有第二个文件,它定义了一些我无法修改的函数。这个文件就像:

void blinkLed(void)
{ ... }

最后,我有一个主源文件,其中包含

main
功能和设备配置。在中断 78 上,我想让 LED 闪烁。所以我写了一个强大的函数
ISR78
,就像这样:

void ISR78(void)
{
    blinkLed();
}

我想知道是否有一种解决方案可以直接通过

ISR78
覆盖弱函数
blinkLed
ie
blinkLed
的地址存储在
__vector_table
内部而不修改它或重命名函数?


编辑:

我实际上使用 GNU gcc 4.9.3 和相关的链接器(GNU ld 2.24.0)。我可以修改与项目关联的

main.c
和Makefile。

c ld weak-linking
3个回答
2
投票

我认为实现您想要做的事情的唯一方法是用

blink
符号修补包含
ISR78
符号的目标文件的符号表。

objcopy [...] --redefine-sym 闪烁=ISR78

应该这样做。然后,链接器应自动将前一个

blink
的地址插入到向量表中。显然,您的
blink
符号在那之后就消失了,不应该从其他地方调用。

但是,我认为这是一种黑客行为。

如果

_vector_table
是全局可访问的并且在可写内存中(不假设,这可能太简单了......),您可以简单地通过

从您自己的代码中修补它
_vector_table [0x78] = blink;

在运行时。


2
投票

tl;dr:您已经有了一个可行的解决方案,这似乎是首先明确支持和鼓励使用弱符号的解决方案。您期望不同的解决方案有何改进?


链接器符号是按名称查找的,因此使用预期名称的唯一替代方法是:

  1. tofro的建议直接修改链接步骤
  2. 自己修改函数指针表

首先使 ISR78 成为弱符号的全部目的是允许您已经使用过的覆盖(按符号名称)。

我看不出有什么方法修改中断向量表比直接使用预期的函数名称更好,即使这是可能的。


0
投票

您可以使用

__asm("symbolname")
来执行此操作。这使您可以将目标文件中使用的符号名称更改为特定字符串。 gcc 和 clang 都支持这一点。

示例:

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

在您的代码中,所有内容都可以使用名称

blinkLed
。但在目标文件中,名称将为
ISR78
,它将覆盖弱版本并用作中断向量。

这也可以作为避免 C++ 名称修改的一种方法,即使您无法使用

extern "C"

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

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

上面我们有一个带有 ISR 的类模板,blinkled(),作为静态方法。然后,我们为两个不同的定时器定义该 ISR 的两个专门化,并为其所在的中断向量指定每个正确的名称。

© www.soinside.com 2019 - 2024. All rights reserved.