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

标签 c gcc static

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

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

我之前问过一个非常相似的问题,但由于我提出的上一个问题在评论部分有些困惑并且没有得到完全回答(但我将其标记为已回答,因为这是一项很好的努力并且至少部分回答了它) 我会问一个新问题。问题具体是如何将 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 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;
}

编辑:

我也尝试过 statifier 和 ermine,正如这个问题中所建议的:

Static link of shared library function in 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 thing 是一个聪明的特性,它允许包含一个函数的多个版本,并根据可用的硬件在运行时选择最佳版本。我不确定,但看起来此功能仅在 PIE(位置独立可执行文件)或共享库构建中可用。

为什么它会在静态 libc.a 中对我来说是个谜,但有一个简单的解决方法:实现你自己的 strcmp(一个基本的、缓慢的实现是只有几行 C),并在 before 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 文件,然后显式链接它们。

关于c - GCC 动态链接 libc static 和其他一些库,重新访问了吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26277283/

相关文章:

c - 是否可以在 GTK 中对用户隐藏 .glade 文件?

c - printf() 函数如何知道其参数的类型

visual-studio - 如何在 Visual Studio 中静态链接 VCPKG 生成的 .lib 文件

c++ - 我的静态函数的 header 和 .cpp 发生了什么?仅在 header 中定义时运行

c - 具有相同指针的指针运算(数组下标不是整数)

java - 特定于枚举常量的类主体是静态的还是非静态的?

php - 开源语言识别库?

c++ - 错误的十六进制代码

当程序被 kill 命令停止时关闭 tcp 套接字

c - 如何使用 openmp 产生一次线程