Почему у меня есть неопределенная ссылка на _init в __libc_init_array?
Я пытаюсь создать простой проект с использованием Yagarto и Eclipse для платформы микроконтроллера ARM. В моем коде запуска у меня есть это (которое я считаю довольно стандартным и неинтересным):
void Reset_Handler(void)
{
/* Initialize data and bss */
__Init_Data();
/* Call CTORS of static objects */
__libc_init_array();
/* Call the application's entry point.*/
main();
while(1) { ; }
}
Если я не закомментирую звонок __libc_init_array()
Я получаю следующую ошибку от компоновщика:
arm-none-eabi-g++ -nostartfiles -mthumb -mcpu=cortex-m4 -TC:/Users/mark/workspace/stm32_cpp_test/STM32F40x_1024k_192k_flash.ld -gc-sections -Wl,-Map=test_rom.map,--cref,--no-warn-mismatch -o stm32_cpp_test "system\\syscalls.o" "system\\startup_stm32f4xx.o" "system\\mini_cpp.o" "system\\cmsis\\system_stm32f4xx.o" main.o
d:/utils/yagarto/bin/../lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/lib/thumb/v7m\libg.a(lib_a-init.o): In function `__libc_init_array':
C:\msys\1.0\home\yagarto\newlib-build\arm-none-eabi\thumb\v7m\newlib\libc\misc/../../../../../../../newlib-1.20.0/newlib/libc/misc/init.c:37: undefined reference to `_init'
collect2.exe: error: ld returned 1 exit status
Почему я получаю эту ошибку "неопределенная ссылка"? Что мне не хватает? Я предполагаю, что есть какой-то флаг компоновщика, который мне не хватает, но я не могу понять, на что я способен.
3 ответа
Я не эксперт, но:
Вероятно, _init (обычная точка входа во время выполнения) ссылается на код, который выполняет таблицы ctor и dtor.
Вы используете -nostartfiles, поэтому избегайте стандартного запуска, и, вероятно, весь стартовый код удаляется с помощью --gc-section. Явный вызов снова добавляет ссылку.
Если пропуск --gc-section не решает эту проблему, это может также быть пропущенная инструкция keep() в вашем (встроенном) компоновочном скрипте, которая постоянно сохраняет код входа, или ваш собственный код запуска (startup_*) должен ссылаться Это
Старый вопрос, но я столкнулся с подобной проблемой, и решение было, как указал Марко ван де Воорт, если вы собираетесь использовать __libc_init_array
Вы должны опустить -nostartfiles
опция компоновщика, чтобы включить нормальные функции libc init. Дубликат ответа.
Во-вторых, я бы предложил включить --specs=nano.specs
флаг при соединении с gcc-arm (я считаю, что yargarto - это форк или даже просто прекомпиляция gcc-arm), так как это уменьшает потребление кода libc и т. д.
Функция __libc_init_array из stdlib заботится о вызове всех инициализаторов или конструкторов C++, зарегистрированных в preinit_array и init_array . Между preinit и init он вызывает функцию extern _init . Код выглядит очень просто:
#include <sys/types.h>
/* These magic symbols are provided by the linker. */
extern void (*__preinit_array_start []) (void) __attribute__((weak));
extern void (*__preinit_array_end []) (void) __attribute__((weak));
extern void (*__init_array_start []) (void) __attribute__((weak));
extern void (*__init_array_end []) (void) __attribute__((weak));
extern void _init (void);
void __libc_init_array (void)
{
size_t count;
size_t i;
count = __preinit_array_end - __preinit_array_start;
for (i = 0; i < count; i++)
__preinit_array_start[i] ();
_init ();
count = __init_array_end - __init_array_start;
for (i = 0; i < count; i++)
__init_array_start[i] ();
}
См. Также: понимание __libc_init_array.
Если реализован пользовательский код запуска, необходимо выполнить эту инициализацию либо путем ссылки на « init.o », либо путем реализации чего-то похожего на фрагмент кода выше.
Если хотя бы сборка для цели arm-none-eabi ARMv7e со спецификациями newlib-nano , тогда метод _init будет связан из /lib/gcc/arm-none-eabi/10.2.1/thumb/v7e-m+dp/hard/crti.o, который предоставляет только несколько пустых заглушек для _init и _fini . Если кто-то хочет использовать __libc_init_array в сочетании с опцией компоновщика nostartfiles для этой конкретной цели ARM, было бы приемлемо предоставить свой собственный метод заглушки _init , чтобы позволить компоновщику пройти, например, например:
extern "C" void _init(void) {;}