Arm Gcc Слабый Псевдоним Переопределение - PullRequest
1 голос
/ 05 ноября 2019

Я хотел создать слабый псевдоним для нескольких функций, чтобы я мог объявить его в заголовочном файле, но затем определить его позже в других файлах. По какой-то причине я все еще получаю ошибку переопределения от 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")));

1 Ответ

1 голос
/ 05 ноября 2019

TL; DR: не помещайте __weak__, ни __alias__ в .h файл. Поместите __weak__ и __alias__ в .c файл.

Слабые символы теоретически работают следующим образом:

  • Существует один файл .o с символом __weak__.
  • Существует еще один .o файл с нормальным символом.
  • Компоновщик видит оба символа и выбирает неслабый символ.

Объектные файлы .oгенерируются из .c файлов. Определение символа внутри .c должно быть слабым.

Атрибуты, применяемые к объявлению, применяются к определениям, которые его видят. Выполнение __weak__ в заголовке в объявлении помечает все определения, которые видят, что объявление этого символа как __weak__.

alias работает так, как если бы вы делали:

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

Работает как-будто так же, но без ветки (и меньше набирает). И в любом случае, поскольку 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 документации по атрибутам функций . В документации говорится, что другой символ с псевдонимом должен быть определен в той же единице транзакции (читается как: в том же файле .c).

Помните, что объявление символа как слабого не означаетэтот компоновщик выделит сильный символ - при компиляции со статическими библиотеками иногда происходят странные вещи. Компилируйте только с объектами или используйте опции компоновщика -Wl,-start-group. Я думаю, что infocenter.arm имеет лучшее объяснение этому.

...