Сначала называются функции раздела init или функции конструктора? - PullRequest
0 голосов
/ 23 июня 2018

Рассмотрим следующий код:

#include <iostream>
#include <stdio.h>

void preinit_void();
void init_void();

__attribute__((section(".init_array")))
    void (*p_init)(void) = &init_void;

void constructor_void() __attribute__((constructor));
void constructor_void() {
    printf(__FUNCTION__);
}

__attribute__((section(".preinit_array")))
    void (*p_preinit)(void) = &preinit_void;


void preinit_void() {
    printf(__FUNCTION__);
}

void init_void() {
    printf(__FUNCTION__);
}

int main() {
    std::cout << __FUNCTION__ << '\n';
}

При запуске кода вывод будет

preinit_voidinit_voidconstructor_voidmain

Если бы я изменил код на:

#include <iostream>
#include <stdio.h>

void preinit_void();
void init_void();

void constructor_void() __attribute__((constructor));
void constructor_void() {
    printf(__FUNCTION__);
}

__attribute__((section(".init_array")))
    void (*p_init)(void) = &init_void;

__attribute__((section(".preinit_array")))
    void (*p_preinit)(void) = &preinit_void;


void preinit_void() {
    printf(__FUNCTION__);
}

void init_void() {
    printf(__FUNCTION__);
}

int main() {
    std::cout << __FUNCTION__ << '\n';
}

Выходные данные изменяются на:

preinit_voidconstructor_voidinit_voidmain

Я не понимаю, какой раздел инициализируется первым.Выходные данные изменяются просто из-за синтаксического анализа компилятором (что он сначала обнаружил секцию .init_array вместо constructor), или для него существует правильная последовательность инициализации?

1 Ответ

0 голосов
/ 24 июня 2018

В современных (GNU) системах ссылки на функции конструктора ELF помещаются в раздел .init_array, как и записи, добавляемые вами вручную.Вот почему порядок выполнения изменился, когда вы изменили порядок исходного кода.GCC и binutils имеют расширение языка для использования отдельных разделов на основе приоритета, а редактор ссылок будет сериализовать все в окончательный раздел .init_array для каждого приложения / общего объекта (на основе исходного кода и порядка ссылок после сортировки по приоритету).

Массивы конструктора для различных общих объектов выполняются после выполнения топологической сортировки на основе зависимостей между объектами (как выражено через тег DT_NEEDED), так что объекты инициализируются после их зависимостей.

Это выходит далеко за рамки того, что требуется C ++ для инициализации, но оно более или менее указано в различных (GNU) документах, связанных с ABI, и не собирается изменяться.Некоторые аспекты могут измениться из-за введения новых функций (например, нескольких объектов DF_1_INITFIRST, хотя этот объект немного сбивает с толку), но, надеюсь, они будут влиять только на процессы, которые фактически используют эти функции.

...