конструктор разделяемой библиотеки не работает - PullRequest
10 голосов
/ 28 февраля 2012

В моей общей библиотеке я должен выполнить определенную инициализацию во время загрузки. Если я определяю функцию с атрибутом GCC __attribute__ ((constructor)), она не работает, то есть она не вызывается, когда загружена программа, связывающая мою общую библиотеку.

Если я изменю имя функции на _init(), оно будет работать. Очевидно, что использование _init() и _fini() функций не рекомендуется сейчас.

Есть идеи, почему __attribute__ ((constructor)) не сработает? Это с Linux 2.6.9, gcc версия 3.4.6

Edit:

Например, скажем, код библиотеки следующий:

#include <stdio.h>

int smlib_count;

void __attribute__ ((constructor)) setup(void) {
    smlib_count = 100;
    printf("smlib_count starting at %d\n", smlib_count);
}

void smlib_count_incr() {
    smlib_count++;
    smlib_count++;
}

int smlib_count_get() {
    return smlib_count;
}

Для построения .so я делаю следующее:

gcc -fPIC -c smlib.c
ld -shared -soname libsmlib.so.1 -o libsmlib.so.1.0 -lc smlib.o
ldconfig -v -n .
ln -sf libsmlib.so.1 libsmlib.so

Поскольку .so не находится в одном из стандартных мест, я обновляю LD_LIBRARY_PATH и связываю .so из другой программы. Конструктор не вызывается. Если я изменю его на _init(), он будет работать.

Ответы [ 2 ]

4 голосов
/ 09 марта 2012

Хорошо, поэтому я посмотрел на это, и похоже, что происходит то, что ваш промежуточный шаг gcc (с использованием -c) вызывает проблему.Вот моя интерпретация того, что я вижу.

Когда вы компилируете как .o с setup(), gcc просто обрабатывает это как нормальную функцию (так как вы не компилируете как .so так что все равно)Затем ld не видит _init() или что-либо подобное DT_INIT в динамическом разделе ELF и предполагает, что конструкторов нет.

Когда вы компилируете как .o с _init(), gcc также рассматривает это как нормальную функцию.На самом деле, мне кажется, что объектные файлы идентичны , за исключением имен самих функций!Итак, еще раз, ld смотрит на файл .o, но на этот раз видит функцию _init(), которую он знает, что ищет, и решает, что это конструктор, и соответственно создает запись DT_INIT в новом .so.

Наконец, если вы выполняете компиляцию и компоновку за один шаг, например:

gcc -Wall -shared -fPIC -o libsmlib.so smlib.c

Тогда происходит то, что gcc видит и понимает __attribute__ ((constructor)) вконтекст создания общего объекта и соответственно создает запись DT_INIT.

Краткая версия: используйте gcc для компиляции и компоновки за один шаг.Вы можете использовать -Wl (см. Справочную страницу) для передачи дополнительных параметров, таких как -soname, если требуется, например, -Wl,-soname,libsmlib.so.1.

2 голосов
/ 14 февраля 2014

С по этой ссылке :

«Общие библиотеки не должны компилироваться с аргументами gcc -nostartfiles '' или-nostdlib ''. Если эти аргументы используются, подпрограммы конструктора / деструктора не будут выполняться (если не будут приняты специальные меры)."

gcc / ld не устанавливает бит DT_INIT в заголовке elf, когда используется -nostdlib. Вы можете проверить objdump -p и найти раздел INIT в обоих случаях. В случае атрибут ((конструктор)) вы не найдете этот раздел INIT. Но для случая __init вы найдете раздел INIT в общей библиотеке.

...