Глобальный вызов конструктора не в разделе .init_array - PullRequest
9 голосов
/ 14 июня 2011

Я пытаюсь добавить глобальную поддержку конструктора для встроенной цели (ARM Cortex-M3).Допустим, у меня есть следующий код:

class foobar
{
    int i;

public:
    foobar()
    {
        i = 100;
    }

    void inc()
    {
        i++;
    }
};

foobar foo;

int main()
{
    foo.inc();
    for (;;);
}

Я скомпилирую его так:

arm-none-eabi-g++ -O0 -gdwarf-2 -mcpu=cortex-m3 -mthumb -c foo.cpp -o foo.o

Когда я смотрю на раздел .init_array с помощью objdump, он показывает, что .init_section имеетнулевой размер.

Я получаю символ с именем _Z41__static_initialization_and_destruction_0ii.Когда я разбираю объектный файл, я вижу, что глобальная конструкция выполняется в символе static_initialization_and_destruction.

Почему указатель на этот символ не добавляется в разделе .init_section?

Ответы [ 5 ]

26 голосов
/ 25 февраля 2013

Я знаю, что прошло почти два года с тех пор, как был задан этот вопрос, но мне просто нужно было разобраться в механике инициализации C ++ без метала с помощью GCC, поэтому я решил поделиться здесь деталями. Оказывается, в Интернете много устаревшей или запутанной информации. Например, часто упоминаемая оболочка collect2, по-видимому, не используется для целей ARM ELF, поскольку ее поддержка произвольных секций обеспечивает подход, описанный ниже.

Во-первых, когда я компилирую приведенный выше код с заданной командной строкой с использованием Sourcery CodeBench Lite 2012.09-63, я вижу правильный .init_array размер раздела 4:

$ arm-none-eabi-objdump -h foo.o

foo.o:     file format elf32-littlearm

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
...
 13 .init_array   00000004  00000000  00000000  0000010c  2**2
                  CONTENTS, ALLOC, LOAD, RELOC, DATA
...

Когда я смотрю на содержание раздела, оно просто содержит 0:

$ arm-none-eabi-objdump -j .init_array -s foo.o
Contents of section .init_array:
 0000 00000000                             ....

Тем не менее, есть также секция перемещения, которая правильно устанавливает _GLOBAL__sub_I_foo:

$ arm-none-eabi-objdump -x foo.o
...
RELOCATION RECORDS FOR [.init_array]:
OFFSET   TYPE              VALUE
00000000 R_ARM_TARGET1     _GLOBAL__sub_I_foo

Как правило, .init_array указывает на все ваши заглушки инициализатора _GLOBAL__sub_I_XXX, каждая из которых вызывает свою собственную копию _Z41__static_initialization_and_destruction_0ii (да, она многократно определена), которая вызывает конструктор с соответствующими аргументами.

Поскольку я использую -nostdlib в своей сборке, я не могу использовать __libc_init_array CodeSourcery для выполнения .init_array для меня, поэтому мне нужно самому вызывать статические инициализаторы:

extern "C"
{
    extern void (**__init_array_start)();
    extern void (**__init_array_end)();

    inline void static_init()
    {
        for (void (**p)() = __init_array_start; p < __init_array_end; ++p)
            (*p)();
    }
}

__init_array_start и __init_array_end определяются сценарием компоновщика:

. = ALIGN(4);
.init_array :
{
__init_array_start = .;
KEEP (*(.init_array*))
__init_array_end = .;
}

Похоже, что этот подход работает как с кросс-компилятором CodeSourcery, так и с собственным ARM GCC, например в Ubuntu 12.10 для ARM. Поддержка обоих компиляторов является одной из причин использования -nostdlib и не полагается на поддержку чистого кода CodeSourcery CS3.

4 голосов
/ 18 августа 2015

Timmmm,

У меня просто была такая же проблема с nRF51822, и я решил ее, добавив KEEP () вокруг пары строк в стандартном файле Nordic .ld:

KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))

Пока я делал то же самое в области fini_array. Решил мою проблему, и компоновщик все еще может удалить другие неиспользуемые разделы ...

3 голосов
/ 14 июня 2011

Вы создали только объектный файл из-за аргумента -c для gcc. Я считаю, что для создания раздела .init вам нужно связать этот .o с реальным исполняемым файлом или разделяемой библиотекой. Попробуйте удалить аргумент -c и переименовать выходной файл в «foo», а затем проверить полученный исполняемый файл с помощью дизассемблера.

2 голосов
/ 24 марта 2015

У меня была похожая проблема, когда мои конструкторы не вызывались (nRF51822 Cortex-M0 с GCC). Проблема оказалась из-за этого флага компоновщика:

 -Wl,--gc-sections

Не спрашивайте меня, почему! Я думал, что это только удаляет мертвый код.

2 голосов
/ 18 ноября 2011

Если вы посмотрите внимательно, _Z41__static_initialization_and_destruction_0ii будет вызван внутри глобального конструктора.Какой inturn будет связан в разделе .init_arrayarm-none-eabi- от CodeSourcery.) Или в какой-либо другой функции (__main(), если вы используете Linux g ++).() Это должно быть вызвано при запуске или в main().См. Также эту ссылку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...