c-GCC动态链接libc-static和其他一些库,重新访问



以下问题是相关的,但不能回答我的问题:

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.otest.c调用的任何libc函数都将从libc.a中拉入并静态链接,而仅从libmlibgcc中调用的任何函数都将动态链接(但如果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

最新更新