Как я могу сделать псевдоним на внешней определенной функции в C?
Во время компиляции этого кода C
extern void Default_Handler(void);
void NMI_Handler(void) __attribute__ ((weak, alias ("Default_Handler")));
Я получил это
error: 'NMI_Handler' aliased to undefined symbol 'Default_Handler'
Как я могу сделать псевдоним на внешней определенной функции?
Составитель:
gcc version 7.2.1 20170904 (release) [ARM/embedded-7-branch revision 255204] (GNU Tools for Arm Embedded Processors 7-2017-q4-major)
4 ответа
Чтобы создать псевдоним внешней функции, вы можете использовать objcopy
. Вот пример:
Скажем, у меня есть определение функции и я присвоил ему псевдоним, как в следующей программе (называемой myimp.c
):
// myimp.c
int
myadd(int x, int y)
{
return x+y;
}
int
coolguy (int x, int y) __attribute__((alias("myadd")));
Если мы скомпилируем это (но не будем связывать), мы получим объектный файл и сможем проверить его символы:
# compile
$ cc -c myimp.c
# look at the symbols
$ nm myimp.o
0000000000000000 T coolguy
0000000000000000 T myadd
Итак, мы видим, что __attribute__((alias("myadd"))
просто добавляет символ coolguy
с тем же значением 0000000000000000, что и myadd
. Если вы посмотрите вman
страница для нм, будет сказано, что T
означает, что это глобальный символ в .text
раздел. Это имеет смысл, потому что функция неstatic
и содержит инструкции (в отличие от данных).
Итак, если у нас есть объектный файл, но нет источника, и мы хотим добавить псевдоним функции, мы можем сделать это, используя objcopy --add-symbol
.
Скажем, у нас есть объектный файл, полученный в результате компиляции этого исходного кода:
// myimp2.c
int
myadd(int x, int y)
{
return x+y;
}
Компилируя, как указано выше, мы получим myimp2.o
, чьи инструменты таблицы символов такие:
# look at the symbols
$ nm myimp2.o
0000000000000000 T myadd
Итак, мы хотим добавить coolguy
символ, который мы делаем следующим образом
# objcopy --add-symbol coolguy=.text:0000000000000000,global myimp2.o myimp2_augmented.o
Посмотрите документацию на --add-symbol
в objcopy
man
страница. В основном.text
указывает раздел, после двоеточия значение, а затем global
Я обнаружил, передав плохой тип и objcopy
не удалось и сообщил мне список допустимых типов, из которых я выбрал global
.
Попробуйте бежать nm
на myimp2_augmented.o
, вы увидите, что мы добавили символ.
Теперь у вас должна быть возможность установить связь с myimp2_augmented.o
вместо того myimp.o
и ваша программа может вызывать coolguy
без ошибок связывания.
Как предлагается здесь, добавьте в командный файл компоновщика следующее:
PROVIDE(NMI_Handler = Default_Handler);
(И удалите объявление слабого псевдонима из кода C.)
Здесь NMI_Handler имеет слабый атрибут определения, что означает, что если NMI_Handler не определен, то определение Default_Handler будет использоваться для NMI_Handler. как правило, для прерываний, таких как NMI_Handler или Default_Handler, доступно строгое определение. Вам может понадобиться добавить этот файл в свою компиляцию для удаления ошибки. Если вы хотите обрабатывать NMI_Handler по-своему, тогда вы можете определить его где-нибудь, и это определение будет включено вместо слабого.
Для сотрудников очень популярны атрибуты weak и alias для реализации механизма переопределения для собственного проекта C, особенно в случае проектов прошивки.
И декларацию, и определение можно отметить
__attribute__((weak))
и его правила приоритета связывания связаны с тем, существует ли какое-либо объявление в файле заголовка.
Было бы неплохо просто закодировать и скомпилировать его. Затем посмотрите, что произойдет при создании ссылки, поищите ее определение. Я обычно проверяю символы по
-Wl,-trace,-trace-symbol=ANY_FUNCTION_NAME_YOU_WANT
и
nm OBJECT_FILE_NAME
.
Обычно я просто создаю определение функции слабого атрибута и позволяю другим объектам переопределять его. Пример показан ниже:
In C file:
//non-exported weak attribute definition
__attribute__((weak)) void startup_handler_dummy(void) {
printf("[%s][%s]Entry (NO OVERRIDE HANLDER COMES HERE)\n", __FILE__, __func__);
}
//weak and alias attribute declaration
void startup_handler_dummy_impl(void) __attribute__((weak, alias("startup_handler_dummy")));
//exported weak attribute definition
__attribute__((weak)) void startup_handler(void) {
startup_handler_dummy_impl();
}
In header file:
#ifndef _BOARD_H_
#define _BOARD_H_
#define STARTUP_HANDLER startup_handler //to export symbol
#endif
Надеюсь, мой код поможет :)
А более подробную информацию и скриншоты программы вы можете увидеть на MyGitHub.