C语言 GCC 动态链接 libc static 和其他一些库,重新访问?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26277283/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
GCC linking libc static and some other library dynamically, revisited?
提问by AttributedTensorField
The following questions are relevant but do not answer my question:
以下问题是相关的,但不能回答我的问题:
Linking partially static and partially dynamic in GCC
Linking a dynamic library to a static library that links to other static libraries
GCC: static linking only some libraries
Static link of shared library function in gcc
I asked a very similar question earlier, but since the previous question started by me got somewhat cluttered in the comment section and not fully answered (but I flagged it as answered since it was a good effort and did at least partially answer it) I will ask a new question. The question is specifically how to link libc as static, while linking some other library (e.g. libm) dynamically. This was suggested that cannot be done in the first question, is that true? If so it would be very interesting to know why not.
我之前问了一个非常相似的问题,但是由于我提出的上一个问题在评论部分有些混乱并且没有得到完整回答(但我将其标记为已回答,因为这是一个很好的努力并且至少部分回答了它)我会问一个新问题。问题具体是如何将 libc 链接为静态,同时动态链接一些其他库(例如 libm)。这在第一个问题中被建议不能完成,是真的吗?如果是这样,知道为什么不这样做会非常有趣。
Is it even possible to do this? Someone made a comment (which was removed for some reason, maybe it was incorrect?) that it is possible, but there must then alsoexist a dynamically linked version of libc, since it will be required by the dynamic library (e.g. dynamic libm will require dynamic libc (?)).
甚至有可能做到这一点吗?有人发表了意见(这是出于某种原因删除,也许这是不正确的?),这是可能的,但那么一定还存在libc中的动态链接的版本,因为它会通过动态库需要(如动态的libm会需要动态 libc (?))。
This is fine for me, but it is not obvious to me how to tell GCC to do this, i.e. link in libc as both static and dynamic. How do I do this (I made a couple attempts, some are shown later in the question)? Or is there some other way to do what I want?
这对我来说很好,但我不清楚如何告诉 GCC 这样做,即在 libc 中链接静态和动态。我该怎么做(我做了几次尝试,有些在问题后面显示)?或者有其他方法可以做我想做的事吗?
We first see that by simply running gcc test.c -lm, everything is linked in dynamically, as follows:
我们首先看到,通过简单地运行 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)
To link only libm as static, while allowing libc to remain dynamic, we can do (as Z boson pointed out in one of the aforementioned questions):
仅将 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)
However, attempting the same procedure to link libc static and libm dynamic, does not seem to work:
但是,尝试使用相同的过程链接 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
What does this error message mean?
这个错误信息是什么意思?
Some other attempts (most were also included in my first question):
其他一些尝试(大多数也包含在我的第一个问题中):
$ 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
Note that the last one compiled/linked successfully. However libc has not been linked in statically, only dynamically, so it is another failed attempt.
请注意,最后一个编译/链接成功。然而,libc 并没有静态链接,而是动态链接,所以这是另一个失败的尝试。
The test program is simply the following:
测试程序如下:
$ 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;
}
Edit:
编辑:
I've also tried statifier and ermine, as suggested in this question:
我也试过 statifier 和 ermine,正如这个问题中所建议的:
Static link of shared library function in gcc
Neither works.
两者都不起作用。
回答by ams
Basically, your first approach is the correct way to do this:
基本上,您的第一种方法是执行此操作的正确方法:
gcc test.c libc.a -lm
After gcc adds the implicit libraries it'll look (conceptually) like this:
在 gcc 添加隐式库之后,它看起来(概念上)是这样的:
gcc crt1.o test.c libc.a -lm -lc -lgcc -lc
So that means that any libc functions called by either crt1.oor test.cwill be pulled in from libc.aand linked statically, whereas any functions called solelyfrom libmor libgccwill be linked dynamically (but it will reuse the static functions if libm calls something already pulled in).
因此,这意味着,任何由两种称为libc函数crt1.o或test.c将在从拉libc.a和静态链接,而称为任何功能仅仅从libm或libgcc将动态链接(但如果调用的libm已经拉的东西它会重复使用静态函数)。
The linker always starts at the left-most file/library, and works rightwards; it never goes back. .cand .ofiles are linked in unconditionally, but .afiles and -loptions are only used to find functions that are already referenced but not yet defined. Therefore, a library at the left is pointless (and -lcmust appear twice because -lcdepends on -lgcc, and -lgccdepends on -lc). Link order is important!
链接器总是从最左边的文件/库开始,向右工作;它永远不会回来。.c和.o文件是无条件链接的,但.a文件和-l选项仅用于查找已引用但尚未定义的函数。因此,左侧的库毫无意义(并且-lc必须出现两次,因为-lc取决于-lgcc和-lgcc取决于-lc)。链接顺序很重要!
Unfortunately, you appear to have been foiled by what might be a bug in strcmp(or rather in the libc that contains strcmp): the STT_GNU_IFUNCthing is a clever feature that allows multiple versions of a function to be included, and the most optimal one to be selected at runtime, based on what hardware is available. I'm not sure, but it looks like this feature is only available in a PIE (Position Independent Executable) or shared library build.
不幸的是,您似乎被strcmp(或者更确切地说是包含 的 libc 中的错误)所挫败strcmp:这STT_GNU_IFUNC是一个聪明的功能,它允许包含一个函数的多个版本,并选择最优化的一个在运行时,基于可用的硬件。我不确定,但看起来此功能仅在 PIE(位置独立可执行文件)或共享库构建中可用。
Why that would be in a static libc.ais a mystery to me, but there's an easy workaround: implement your own strcmp(a basic, slow implementation is only a few lines of C), and link it in beforelibc.a.
为什么这将是一个静态libc.a是一个谜给我,但有一个简单的解决方法:实现你自己的strcmp(一个基本的,缓慢的实现是C的只有几行),并链接它之前libc.a。
gcc test.c mystrcmp.c libc.a -lm
Alternatively, you can extract the functions from libc.athat you really want, and link only those in statically:
或者,您可以从中提取libc.a您真正想要的功能,并仅静态链接这些功能:
ar x libc.a
gcc test.c somefile.o -lm
aris to .afiles, as taris to .tarfiles, although the command usage varies a bit, so this example extracts the .ofiles from the .afile, and then links them explicitly.
ar是.a文件,tar也是.tar文件,虽然命令用法略有不同,因此本示例.o从.a文件中提取文件,然后显式链接它们。
回答by Z boson
Based on the answer by ams I did the follow
根据 ams 的回答,我做了以下操作
mystrcmp.c
mystrcmp.c
int strcmp(const char *s1, const char *s2) {
}
Compile
编译
gcc -c test.c
gcc -c mystrcmp.c
Setup files
安装文件
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`
Link
关联
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
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
This links and runs correctly. However, lddshows
这链接并正确运行。然而,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)
It appears that dynamic libmrequires dynamic libc. Actually, that's easy to show
看来 dynamiclibm需要 dynamic libc。其实这很容易显示
ldd libm.so reports
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)
So it's impossible to link to libm.so without linking libc.so as well unless you manage to compile libm without the dependency on libc.
因此,除非您设法在不依赖 libc 的情况下编译 libm,否则在不链接 libc.so 的情况下链接到 libm.so 是不可能的。

