Функции gcc с атрибутом конструктора не связаны - PullRequest
9 голосов
/ 06 июля 2011

У меня есть куча статических библиотек, и они взаимозависимы. Я столкнулся с проблемами при связывании этих библиотек для моей цели из-за зависимостей. В качестве обходного пути я создал один архивный файл из всех библиотек.

Одна из статических библиотек имеет функции конструктора и деструктора, так же как и объединенный архив (проверен архив с использованием nm и objdump ) Но когда я использовал объединенный архив для своей цели, конечный двоичный файл не содержит функций конструктора и деструктора.

Я также пытался использовать --whole-archive, но мне кажется, что эта опция не работает (размер двоичного файла не увеличился).

Есть идеи, что могло пойти не так. Спасибо

1 Ответ

7 голосов
/ 06 июля 2011

Компоновщик загружает только те модули, которые он должен (т. Е. То, что вы на самом деле ссылаетесь неявно или явно ), если только вы не форсируете его.

Это и хорошая вещь и неудачная. Это ускоряет процесс линковки и предотвращает раздувание кода. Обычно это также не вызывает проблем, потому что обычно вы ссылаетесь на все модули, которые нужны каким-то образом, а то, на что вы не ссылаетесь, не нужно. Обычно.
Но это также является причиной этого тихого сбоя: компоновщик никогда не загружает модуль, содержащий ваши функции конструктора / деструктора, и никогда даже не смотрит на него . Это потому, что вы никогда не вызываете эти функции.

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

Другими словами, если функции конструктора / деструктора находятся в foo.c, добавьте -l/path/to/foo.o к параметрам своего компоновщика или просто передайте foo.o в командной строке компоновщику (в качестве дополнительного аргумента).

В любом случае, делая это, вы явно указываете компоновщику, что нужно рассмотреть этот модуль, и он заставит его найти функции конструктора и правильно вызвать их.

Альтернативой (которая не требует, чтобы вы играли с командной строкой) может быть помещение переменной или функции (которая не обязательно что-либо делает) в тот же исходный файл, что и функции конструктора / деструктора, и вызов этой переменной из любого Исходный файл в основной программе.
Это также заставит компоновщик загрузить содержащий модуль (где он найдет функции конструктора).

Обновление:
Я протестировал эту альтернативу, она отлично работает:

/* libcode.c */
void enable_constructors() { /* do nothing */ }
void __attribute__ ((constructor)) con() { __builtin_puts("construct"); }
void __attribute__ ((destructor))  des() { __builtin_puts("destruct"); }


/* main.c */
extern void enable_constructors();

int main()
{
    enable_constructors();
    __builtin_puts("main");
    return 0;
}

Вывод:

construct
main
destruct

Он также работает с глобальной переменной, к которой вы прикоснулись из исходного файла основной программы:

/* libcode.c */
int enable_constructors; /* not used for anything */

void __attribute__ ((constructor)) cons() { __builtin_puts("construct"); }
void __attribute__ ((destructor)) des() { __builtin_puts("destruct"); }


/* main.c */
extern int enable_constructors;

int main()
{
    ++enable_constructors; /* touch the other module */
    __builtin_puts("main");
    return 0;
}
...