Arm Gcc 弱别名重新定义

Arm Gcc Weak Alias Redefinition

我想为几个函数创建弱别名,这样我就可以在头文件中声明它,然后在不同的文件中定义它。出于某种原因,我仍然从 gcc 收到重新定义错误。

理想情况下,对于没有实现的函数,我希望它默认返回别名。

我已经尝试删除别名 ("Default_Handler"),它似乎可以编译,但它有点破坏了我尝试编写此应用程序的意图。

vector_table.h

void __attribute__((noreturn))  Default_Handler (void);                                                  
void NMI_Handler(void) __attribute__((weak, alias("Default_Handler"))); 

startup.c

#include "vector_table.h"

void Default_Handler(void){                                                                                                                                
    for(;;);                                                                      
}                                                                               

void NMI_Handler(void){                                                         
    for(;;);                                                                      
}
arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard -Wall -Wno-unused -Wextra -pedantic -H -g3 -gdwarf-2 -O0 -std=c90 -ffreestanding -c startup.c

startup.c:93:6: error: redefinition of 'NMI_Handler'
 void NMI_Handler(void){
      ^
In file included from startup.c:3:0:
vector_table.h:17:6: note: previous definition of 'NMI_Handler' was here
 void NMI_Handler(void) __attribute__((weak, alias("Default_Handler")));

TL;DR:不要将 __weak____alias__ 放入 .h 文件中。将 __weak____alias__ 放入 .c 文件。

弱符号理论上是这样工作的:

  • 有一个 .o 文件带有 __weak__ 符号。
  • 还有一个 .o 文件具有正常的符号。
  • 链接器看到两个符号并选择 non-weak 符号。

.o object 个文件是从 .c 个文件生成的。 .c里面的符号定义应该是weak.

应用于声明的属性也应用于看到它的定义。在声明中的 header 中执行 __weak__ 标记 all 定义,这些定义将此符号的声明视为 __weak__.

alias 的工作方式就像您会做的那样:

static inline void NMI_Handler(void) {
     Default_Handler();
}

它的工作原理与 as-if 相同,但没有分支(并且输入更少)。而且无论如何,因为 alias 创建了符号,所以它充当定义 - 它也属于 .c 文件。这就是您出现多重定义错误的原因 - __alias__ 定义了符号 NMI_Handler,您稍后又定义了 void NMI_Handler(void) {}

你想做的我想是这样的:

// vector_table.h
void __attribute__((noreturn))  Default_Handler (void);                                                  
void NMI_Handler(void);

// startup.c     
void Default_Handler(void){                                                                                                                                
    for(;;);                                                                      
}   

__attribute__((__weak__, __alias__("NMI_Handler")))
void  NMI_Handler(void);

这与 gcc documentation about function attributes 中解释的示例用法相同。文档指出,必须在同一个事务单元中定义另一个别名的符号(读作:在同一个 .c 文件中)。

请记住,将符号声明为弱并不意味着链接器会达到强符号的峰值 - 当使用静态库进行编译时,有时会发生奇怪的事情。仅使用 object 编译或使用 -Wl,-start-group 链接器选项。我认为 infocenter.arm 对此有最好的解释。