Почему у меня есть неопределенная ссылка на _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) {;}
Другие вопросы по тегам