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

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

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

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

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

Статическая ссылка функции разделяемой библиотеки в gcc

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

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

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

Сначала мы видим, что просто запустив gcc test.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 boson в одном из вышеупомянутых вопросов):

$ 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 и динамическую libm одной и той же процедурой, похоже, не работает:

$ 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;
}

Редактировать:

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

Статическая ссылка функции разделяемой библиотеки в gcc

Ни то, ни другое не работает.

3 ответа

Решение

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

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): STT_GNU_IFUNC вещь - это умная функция, которая позволяет включать несколько версий функции и выбирать наиболее оптимальную во время выполнения в зависимости от того, какое оборудование доступно. Я не уверен, но похоже, что эта функция доступна только в PIE (Position Independent Executable) или сборке общей библиотеки.

Почему это было бы в статике 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 файл, а затем связывает их явно.

Основываясь на ответе Амс, я сделал следующее

mystrcmp.c

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

компилировать

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 математика crt1.o crti.o test.o mystrcmp.o libc.a libgcc_eh.a libc.a libm.so -dynamic-linker /lib64/ld-linux-x86-64.so.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.so сообщает

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.so без ссылки на libc.so, если вам не удастся скомпилировать libm без зависимости от libc.

просто используйте

      gcc sample_uart.c -static  -static-libgcc -static-libstdc++

# lddtree a.out
a.out => ./a.out (interpreter => none)


#################### test ############################
ar x /usr/lib/arm-linux-gnueabihf/libc.a



-rw-r--r--  1 root root   792 Oct 28 00:38 wmemset.o
-rw-r--r--  1 root root  2456 Oct 28 00:38 wmemstream.o
-rw-r--r--  1 root root  1616 Oct 28 00:38 wordcopy.o
-rw-r--r--  1 root root 18544 Oct 28 00:38 wordexp.o
-rw-r--r--  1 root root  1384 Oct 28 00:38 wprintf_chk.o
-rw-r--r--  1 root root  1088 Oct 28 00:38 wprintf.o
-rw-r--r--  1 root root   884 Oct 28 00:38 write_nocancel.o
-rw-r--r--  1 root root  1368 Oct 28 00:38 write.o
-rw-r--r--  1 root root  1340 Oct 28 00:38 writev.o
-rw-r--r--  1 root root  1084 Oct 28 00:38 wscanf.o
-rw-r--r--  1 root root  3924 Oct 28 00:38 wstrops.o
-rw-r--r--  1 root root  2112 Oct 28 00:38 xcrypt.o
-rw-r--r--  1 root root  1504 Oct 28 00:38 xdr_array.o
-rw-r--r--  1 root root   836 Oct 28 00:38 xdr_float.o
-rw-r--r--  1 root root  2344 Oct 28 00:38 xdr_intXX_t.o
-rw-r--r--  1 root root  1740 Oct 28 00:38 xdr_mem.o
-rw-r--r--  1 root root  4696 Oct 28 00:38 xdr.o
-rw-r--r--  1 root root  3880 Oct 28 00:38 xdr_rec.o
-rw-r--r--  1 root root  1640 Oct 28 00:38 xdr_ref.o
-rw-r--r--  1 root root  1556 Oct 28 00:38 xdr_sizeof.o
-rw-r--r--  1 root root  2464 Oct 28 00:38 xdr_stdio.o
-rw-r--r--  1 root root  1688 Oct 28 00:38 xlocale.o
-rw-r--r--  1 root root   936 Oct 28 00:38 xmknodat.o
-rw-r--r--  1 root root   944 Oct 28 00:38 xmknod.o
-rw-r--r--  1 root root  1052 Oct 28 00:38 xpg_basename.o
-rw-r--r--  1 root root  1640 Oct 28 00:38 xpg-strerror.o
-rw-r--r--  1 root root   900 Oct 28 00:38 xstat64.o
-rw-r--r--  1 root root  1184 Oct 28 00:38 xstatconv.o
-rw-r--r--  1 root root  1196 Oct 28 00:38 xstat.o
root@hi3798mv100:~/sample/uart#
root@hi3798mv100:~/sample/uart#
root@hi3798mv100:~/sample/uart# gcc sample_uart.c -lm
root@hi3798mv100:~/sample/uart# gcc sample_uart.c *.o -lm
/usr/bin/ld: dso_handle.o:(.data.rel.ro.local+0x0): multiple definition of `__dso_handle'; /usr/lib/gcc/arm-linux-gnueabihf/9/crtbeginS.o:(.data.rel.local+0x0): first defined here
/usr/bin/ld: rcmd.o: in function `__validuser2_sa':
(.text+0x418): warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
collect2: error: ld returned 1 exit status


Другие вопросы по тегам