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