以下问题是相关的,但不能回答我的问题:
GCC 中的部分静态和部分动态链接
将动态库链接到链接到其他静态库的静态库
GCC:只静态链接一些库
gcc 中共享库函数的静态链接
我早些时候问了一个非常类似的问题,但由于我开始的前一个问题在评论区有些混乱,没有完全回答(但我将其标记为已回答,因为这是一个很好的努力,并且至少部分回答了),我将问一个新问题。具体的问题是如何将libc链接为静态库,同时动态链接其他库(例如libm)。这在第一个问题中是不可能做到的,是真的吗?如果是这样的话,知道为什么不这样做会很有趣。
有可能做到这一点吗?有人评论说(由于某种原因被删除了,可能是不正确的?)这是可能的,但必须存在和的动态链接版本的libc,因为它将是动态库所需要的(例如,动态libm将需要动态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玻色子在上述问题中指出的那样):
$ 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;
}
编辑:
我也试过他汀类药物和貂皮胺,正如这个问题所建议的那样:
gcc 中共享库函数的静态链接
两者都不起作用。
基本上,您的第一种方法是正确的方法:
gcc test.c libc.a -lm
在gcc添加隐式库之后,它(概念上)看起来是这样的:
gcc crt1.o test.c libc.a -lm -lc -lgcc -lc
因此,这意味着crt1.o
或test.c
调用的任何libc函数都将从libc.a
中拉入并静态链接,而仅从libm
或libgcc
中调用的任何函数都将动态链接(但如果libm调用了已经拉入的东西,它将重用静态函数)。
链接器总是从最左边的文件/库开始,并向右工作;它再也回不去了。.c
和.o
文件无条件链接,但.a
文件和-l
选项仅用于查找已引用但尚未定义的函数。因此,左边的库是没有意义的(并且-lc
必须出现两次,因为-lc
依赖于-lgcc
,而-lgcc
依赖于-lc
)链接顺序很重要
不幸的是,您似乎被strcmp
(或者更确切地说是包含strcmp
的libc)中的一个错误所困扰:STT_GNU_IFUNC
是一个聪明的功能,它允许包含一个函数的多个版本,并在运行时根据可用的硬件选择最优化的版本。我不确定,但看起来这个功能只在PIE(位置独立可执行文件)或共享库构建中可用。
为什么会出现在静态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
文件一样,尽管命令用法有点不同,所以本例从.a
文件中提取.o
文件,然后显式链接它们。
根据ams的回答,我做了以下
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测试.o mystrcmp.o libc.a libgcc_eh.a libc.a librm.so-动态链接器/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)
因此,如果不链接libc.So,就不可能链接到libm.So,除非您能够在不依赖libc的情况下编译libm。
只需使用
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