GCC 动态链接 libc 静态和其他一些库,重新访问? [英] GCC linking libc static and some other library dynamically, revisited?

查看:16
本文介绍了GCC 动态链接 libc 静态和其他一些库,重新访问?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

The following questions are relevant but do not answer my question:

在 GCC 中链接部分静态和部分动态

链接一个动态库到一个链接到其他静态库的静态库

GCC:仅静态链接某些库

gcc中共享库函数的静态链接

我之前问了一个非常相似的问题,但是由于我提出的上一个问题在评论部分有些混乱并且没有得到完整回答(但我将其标记为已回答,因为这是一个很好的努力并且至少部分回答了它) 我会问一个新问题.问题具体是如何将 libc 链接为静态,同时动态链接一些其他库(例如 libm).这在第一个问题中被建议不能完成,是真的吗?如果是这样,知道为什么不这样做会很有趣.

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 将需要动态 libc (?)).

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 also exist a dynamically linked version of libc, since it will be required by the dynamic library (e.g. dynamic libm will require dynamic libc (?)).

这对我来说很好,但我不清楚如何告诉 GCC 这样做,即将 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 test.c -lm,一切都是动态链接的,如下所示:

We first see that by simply running gcc test.c -lm, everything is linked in dynamically, as follows:

$ 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 在上述问题之一中指出的那样):

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):

$ 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 似乎不起作用:

However, attempting the same procedure to link libc static and libm dynamic, does not seem to work:

$ 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

注意最后一个编译/链接成功.但是libc并没有静态链接,只有动态链接,所以又是一次失败的尝试.

Note that the last one compiled/linked successfully. However libc has not been linked in statically, only dynamically, so it is another failed attempt.

测试程序如下:

$ 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 和 ermine,正如这个问题中所建议的:

I've also tried statifier and ermine, as suggested in this question:

gcc中共享库函数的静态链接

两者都不起作用.

推荐答案

基本上,您的第一种方法是正确的方法:

Basically, your first approach is the correct way to do this:

gcc test.c libc.a -lm

在 gcc 添加隐式库之后,它看起来(概念上)是这样的:

After gcc adds the implicit libraries it'll look (conceptually) like this:

gcc crt1.o test.c libc.a -lm -lc -lgcc -lc

这意味着任何由 crt1.otest.c 调用的 libc 函数都将从 libc.a 和静态链接,而从 libmlibgcc 调用的任何 solely 函数将动态链接(但如果 libm 已经调用了某些东西,它将重用静态函数拉进来了).

So that means that any libc functions called by either crt1.o or test.c will be pulled in from libc.a and linked statically, whereas any functions called solely from libm or libgcc will be linked dynamically (but it will reuse the static functions if libm calls something already pulled in).

链接器总是从最左边的文件/库开始,向右工作;它永远不会回来..c.o 文件无条件链接,但 .a 文件和 -l 选项仅使用查找已被引用但尚未定义的函数.因此,左边的库是没有意义的(而且-lc 必须出现两次,因为-lc 依赖于-lgcc,而-lgcc 依赖于 -lc).链接顺序很重要!

The linker always starts at the left-most file/library, and works rightwards; it never goes back. .c and .o files are linked in unconditionally, but .a files and -l options are only used to find functions that are already referenced but not yet defined. Therefore, a library at the left is pointless (and -lc must appear twice because -lc depends on -lgcc, and -lgcc depends on -lc). Link order is important!

不幸的是,您似乎被 strcmp(或者更确切地说是包含 strcmp 的 libc)中的错误所挫败:STT_GNU_IFUNC thing 是一个聪明的特性,它允许包含一个函数的多个版本,并在运行时根据可用的硬件选择最优化的版本.我不确定,但看起来此功能仅在 PIE(位置独立可执行文件)或共享库构建中可用.

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_IFUNC thing 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.

为什么会在静态 libc.a 中对我来说是个谜,但有一个简单的解决方法:实现你自己的 strcmp(一个基本的、缓慢的实现是只需几行 C),并在 before libc.a 中链接.

Why that would be in a static libc.a is 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 before libc.a.

gcc test.c mystrcmp.c libc.a -lm

<小时>

或者,您可以从 libc.a 中提取您真正想要的函数,并仅静态链接那些函数:


Alternatively, you can extract the functions from libc.a that you really want, and link only those in statically:

ar x libc.a
gcc test.c somefile.o -lm

ar.a 文件,正如tar.tar 文件,虽然命令用法略有不同,因此本示例从 .a 文件中提取 .o 文件,然后显式链接它们.

ar is to .a files, as tar is to .tar files, although the command usage varies a bit, so this example extracts the .o files from the .a file, and then links them explicitly.

这篇关于GCC 动态链接 libc 静态和其他一些库,重新访问?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆