GCC связывает статическую libc и некоторую другую библиотеку динамически, пересматривается?

следующие вопросы актуальны, но не отвечают на мой вопрос:

связывание частично статическое и частично динамическое в GCC

связывание динамической библиотеки со статической библиотекой, которая связывается с другими статическими библиотеками

GCC: статическое связывание только некоторых библиотек

статическая ссылка функции общей библиотеки в gcc

Я задал очень похожий вопрос ранее, но так как предыдущий вопрос, начатый мной, был несколько загроможден в разделе комментариев и не полностью ответил (но я отметил его как ответ, так как это было хорошее усилие и, по крайней мере, частично ответил на него), я задам новый вопрос. Вопрос в том, как связать libc как статический, при этом динамически связывая некоторую другую библиотеку (например, libm). Это было предложено, что не может быть сделано в первом вопросе, это правда? Если так было бы очень интересно узнать, почему не.

возможно ли это сделать? Кто-то сделал комментарий (который был удален по какой-то причине, может быть, это было неправильно?) что можно, но надо тогда и существует динамически связанная версия libc, так как она потребуется динамической библиотеке (например, dynamic libm потребует динамического libc (?)).

это хорошо для меня, но мне не очевидно, как сказать GCC сделать это, т. е. ссылка в libc как статическая, так и динамическая. Как мне быть? это (я сделал пару попыток, некоторые показаны позже в вопросе)? Или есть другой способ сделать то, что я хочу?

сначала мы видим это, просто запустив тест gcc.c-lm, все связано динамически, следующим образом:

$ gcc test.c -lm
$ ldd a.out 
        linux-vdso.so.1 (0x00007fffb37d1000)
        libm.so.6 => /lib64/libm.so.6 (0x00007f3b0eeb6000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f3b0eb10000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f3b0f1b0000)

чтобы связать только libm как статический, позволяя libc оставаться динамическим, мы можем сделать (как указал Z бозон в одном из вышеупомянутых вопросов):

$ gcc test.c /usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libm.a

$ ldd a.out 
        linux-vdso.so.1 (0x00007fff747ff000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f09aaa0c000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f09aadb2000)

однако попытка той же процедуры связать libc static и libm dynamic, похоже, не работает:

$ gcc test.c /usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.a -lm
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: dynamic STT_GNU_IFUNC symbol `strcmp' with pointer equality in `/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.a(strcmp.o)' can not be used when making an executable; recompile with -fPIE and relink with -pie
collect2: error: ld returned 1 exit status

что означает это сообщение об ошибке означает?

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

$ gcc test.c /usr/lib64/libc.a
linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: dynamic STT_GNU_IFUNC symbol `strcmp' with pointer equality in `/usr/lib64/libc.a(strcmp.o)' can not be used when making an executable; recompile with -fPIE and relink with -pie
urned 1 exit status
$ gcc test.c -Wl,-Bdynamic -lm -Wl,-Bstatic -lc
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lgcc_s
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lgcc_s
collect2: error: ld returned 1 exit status
$ gcc -Wl,-Bdynamic -lm -Wl,-Bstatic -lc test.c
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lgcc_s
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lgcc_s
collect2: error: ld returned 1 exit status
$ gcc -Wl,-Bstatic -lc -Wl,-Bdynamic -lm test.c
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: dynamic STT_GNU_IFUNC symbol `strcmp' with pointer equality in `/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.a(strcmp.o)' can not be used when making an executable; recompile with -fPIE and relink with -pie
collect2: error: ld returned 1 exit status
$ gcc test.c /usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.a /usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.so -lm
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: dynamic STT_GNU_IFUNC symbol `strcmp' with pointer equality in `/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.a(strcmp.o)' can not be used when making an executable; recompile with -fPIE and relink with -pie
collect2: error: ld returned 1 exit status
$ gcc test.c /usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.so /usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.a -lm

обратите внимание, что последний составлен и успешно связаны. Однако libc не был связан статически, только динамически, поэтому это еще одна неудачная попытка.

тестовая программа просто следующая:

$ cat test.c 
#include <stdio.h>
#include <math.h>

int main(int argc, char **argv)
{
        int i;
        int result;

        for(i = 0; i < 65535; i++) {
                result = sin(i);
        }

        return 0;
}

Edit:

Я также пробовал statifier и горностай, как подсказывает в этом вопросе:

статическая ссылка функции общей библиотеки в gcc

не работает.

2 ответов


в принципе, ваш первый подход-правильный способ сделать это:

gcc test.c libc.a -lm

после того, как gcc добавит неявные библиотеки, он будет выглядеть (концептуально) следующим образом:

gcc crt1.o test.c libc.a -lm -lc -lgcc -lc

это означает, что любые функции libc вызываются либо crt1.o или test.c будет вытащен из libc.a и связаны статически, тогда как любые функции называются исключительно С libm или libgcc будет связан динамически (но он будет повторно использовать статические функции, если вызовет libm что-то уже вытащил).

компоновщик всегда начинается с самого левого файла / библиотеки и работает вправо; он никогда не возвращается. .c и .o файлы связаны безоговорочно, но .a файлы и -l параметры используются только для поиска функций, которые уже ссылаются, но еще не определены. Поэтому библиотека слева бессмысленна (и -lc должен появиться дважды, потому что -lc зависит от -lgcc и -lgcc зависит от -lc). порядок ссылок важен!

к сожалению, вы, кажется, были сорваны тем, что может быть ошибкой в strcmp (или, скорее, в libc, который содержит strcmp): the STT_GNU_IFUNC thing-Это умная функция, которая позволяет включать несколько версий функции и выбирать наиболее оптимальную во время выполнения, основываясь на том, какое оборудование доступно. Я не уверен, но похоже, что эта функция доступна только в пироге (независимый от позиции исполняемый файл) или совместно сборка библиотеки.

почему это было бы в статике libc.a для меня загадка, но есть простой обходной путь: реализовать собственный strcmp (базовая, медленная реализация-это всего несколько строк C) и свяжите ее в до libc.a.

gcc test.c mystrcmp.c libc.a -lm

кроме того, вы можете извлечь функции из libc.a что вы хотите и только те в статически:

ar x libc.a
gcc test.c somefile.o -lm

ar это .a файлы tar это .tar файлы, хотя использование команды немного варьируется, поэтому в этом примере извлекается .o файлы .a file, а затем связывает их явно.


на основе ответа ams я сделал следующее

mystrcmp.c

int strcmp(const char *s1, const char *s2) {
}

Compile

gcc -c test.c
gcc -c mystrcmp.c

установочные файлы

ln -s `gcc -print-file-name=crt1.o`
ln -s `gcc -print-file-name=crti.o`
ln -s `gcc -print-file-name=crtn.o`
ln -s `gcc -print-file-name=libgcc_eh.a`
ln -s `gcc -print-file-name=libc.a`
ln -s `gcc -print-file-name=libm.so`

ссылке

LD-m elf_x86_64-o math crt1.o crti.тест о'.o mystrcmp.о библиотеки libc.в libgcc_eh.в библиотеку libc.в libm.так -динамического компоновщика /lib64/ЛД-ОС Linux для архитектуры x86-64.так.2 crtn.o

это ссылки и работает правильно. Однако,ldd показывает

linux-vdso.so.1 =>  (0x00007fff51911000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f8182470000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f81820a9000)
/lib64/ld-linux-x86-64.so.2 (0x00007f8182793000)

похоже, что динамический libm требует динамический libc. На самом деле, это легко показать.

ldd libm.так сообщает

linux-vdso.so.1 =>  (0x00007fff20dfe000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fcaf74fe000)
/lib64/ld-linux-x86-64.so.2 (0x00007fcaf7bed000)

таким образом, невозможно связать с libm.таким образом, не связывая libc.так же, если вам не удастся скомпилировать libm без зависимости от libc.