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 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 static和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 #include int main(int argc, char **argv) { int i; int result; for(i = 0; i < 65535; i++) { result = sin(i); } return 0; }
编辑:
我也试过statifier和ermine,正如这个问题所示:
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
是一个聪明的function,允许包含多个版本的函数,并且是最优的一个根据可用的硬件在运行时选择。 我不确定,但看起来此function仅在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 math 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)
所以除非你设法在不依赖libc的情况下编译libm,否则在没有链接libc.so的情况下链接到libm.so是不可能的。