S E*_*S E 5 c linux gcc compilation static-linking
我想有选择libm.a地静态链接所有其他库(libc.so包括)动态链接。但如果我使用 中的数学函数math.h,它几乎总是无法正确链接。为什么?为什么有时会起作用?(例如,如果我只使用sqrt,fabs或者,奇怪的是,tanh,它似乎链接正确)
myscript.sh:
#!/bin/bash
for i in sqrt tanh sin tan
do
echo "-----$i----------"
sed "s/ciao/$i/" prova.c >provat.c
gcc provat.c -fno-builtin -l:libm.a
[[ $? -eq 0 ]] && { echo -n "$i(2.0)="; ./a.out; echo " OK!"; }
echo
done
Run Code Online (Sandbox Code Playgroud)
普罗瓦.c:
#include <stdio.h>
#include <math.h>
int main()
{
printf("%f", ciao(2.0));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果我运行myscript.sh,我可以看到这一点sqrt并且tanh不会出现任何问题。sin相反tan,无法链接:
$./myscript.sh
-----sqrt----------
sqrt(2.0)=1.414214 OK!
-----tanh----------
tanh(2.0)=0.964028 OK!
-----sin----------
/usr/lib/x86_64-linux-gnu/libm-2.27.a(s_sin.o): In function `__sin_ifunc':
(.text+0x4d42): undefined reference to `_dl_x86_cpu_features'
/usr/lib/x86_64-linux-gnu/libm-2.27.a(s_sin.o): In function `__cos_ifunc':
(.text+0x4da2): undefined reference to `_dl_x86_cpu_features'
collect2: error: ld returned 1 exit status
-----tan----------
/usr/lib/x86_64-linux-gnu/libm-2.27.a(s_tan.o): In function `__tan_ifunc':
(.text+0x5782): undefined reference to `_dl_x86_cpu_features'
collect2: error: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)
我不明白这些错误消息。有人可以解释发生了什么吗?为什么我不能libm.a静态链接(其余部分动态链接)?为什么有时会起作用?
注意:我使用-fno-builtinGCC 标志,这样 GCC 就不会使用它的任何内置函数。所以问题不存在。
(对我来说)不太清楚为什么限制(libm.a + libc.so)是必要的,所以它闻起来像XY Problem。
根据[RedHat.Bugzilla]:Bug 1433347 - glibc:由于未解析的 _dl_x86_cpu_features 符号,libm.a 的选择性静态链接失败(由 @KamilCuk 指出):
不支持此操作。
您会将静态 libm.a 与未来的 libc.so.6 和 ld.so 混合在一起,这会破坏形成“C 运行时的实现”的核心库之间的相互依赖性。
运行时的整个实现要么是静态链接的,要么都不是静态链接的。您不能选择静态链接其中的一部分而不链接其他部分,因为每个部分都依赖于另一个部分来形成完整的实现。数学库不是一个可以静态链接的库,碰巧我们有一个 libm.a,但这是一个实现细节。
请在整个应用程序中使用“-static”。
看来这是一个不受支持的配置。这是有道理的,但它也有点令人困惑:即使libc和libm是磁盘上的2 个独立文件(对于每个配置: static、共享),它们也是同一个库(g libc )的一部分,因此:
从一开始,我就怀疑这是一些代码(检测并)使用(如果存在)某些CPU功能(最有可能提高速度或准确性),即:
我使用了这个简单的程序。
主.c:
#include <stdio.h>
#include <math.h>
#if !defined(FUNC)
# define FUNC sqrt
#endif
int main() {
double val = 3.141592;
printf("func(%.06lf): %.06lf\n", val, FUNC(val));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
下面是我在调查问题时遵循的一系列步骤:
环境:
Run Code Online (Sandbox Code Playgroud)[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q056415996]> ~/sopr.sh *** Set shorter prompt to better fit when pasted in StackOverflow (or other) pages *** [prompt]> uname -a Linux cfati-ubtu16x64-0 4.15.0-51-generic #55~16.04.1-Ubuntu SMP Thu May 16 09:24:37 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux [prompt]> gcc --version gcc (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609 Copyright (C) 2015 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. [prompt]> ldd --version ldd (Ubuntu GLIBC 2.23-0ubuntu11) 2.23 Copyright (C) 2016 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Written by Roland McGrath and Ulrich Drepper. [prompt]> ls main.c
2 个库部分( libc和libm)同步时的情况:
Run Code Online (Sandbox Code Playgroud)[prompt]> gcc -fPIC main.c -DFUNC=sin -o sin_static.out -static -lm [prompt]> ll sin_static.out -rwxrwxr-x 1 cfati cfati 1007744 Jun 13 20:08 sin_static.out [prompt]> ldd sin_static.out not a dynamic executable [prompt]> ./sin_static.out func(3.141592): 0.000001 [prompt]> [prompt]> gcc -fPIC main.c -DFUNC=sin -o sin_mso.out -l:libm.so [prompt]> ll sin_mso.out -rwxrwxr-x 1 cfati cfati 8656 Jun 13 20:09 sin_mso.out [prompt]> ldd sin_mso.out linux-vdso.so.1 => (0x00007ffc80ddd000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f999636b000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9995fa1000) /lib64/ld-linux-x86-64.so.2 (0x00007f9996674000) [prompt]> ./sin_mso.out func(3.141592): 0.000001
在这两种情况下一切都工作正常。
切换到libm.a(对于sin和tanh):
Run Code Online (Sandbox Code Playgroud)[prompt]> gcc -fPIC main.c -DFUNC=sin -o sin_ma.out -l:libm.a /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libm.a(s_sin.o): In function `__cos': (.text+0x3542): undefined reference to `_dl_x86_cpu_features' /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libm.a(s_sin.o): In function `__sin': (.text+0x3572): undefined reference to `_dl_x86_cpu_features' collect2: error: ld returned 1 exit status [prompt]> ll sin_ma.out ls: cannot access 'sin_ma.out': No such file or directory [prompt]> [prompt]> gcc -fPIC main.c -DFUNC=tanh -o tanh_ma.out -l:libm.a [prompt]> ll tanh_ma.out -rwxrwxr-x 1 cfati cfati 12856 Jun 13 20:10 tanh_ma.out [prompt]> ldd tanh_ma.out linux-vdso.so.1 => (0x00007ffcfa531000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f124625c000) /lib64/ld-linux-x86-64.so.2 (0x00007f1246626000) [prompt]> ./tanh_ma.out func(3.141592): 0.996272
正如所见:
从现在开始,我将专注于不起作用的情况。
稍微玩一下链接器标志(man ld([die.linux]: ld(1) - Linux 手册页)):
Run Code Online (Sandbox Code Playgroud)[prompt]> gcc -fPIC main.c -DFUNC=sin -o sin_ma_undefined.out -l:libm.a -Wl,--warn-unresolved-symbols /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libm.a(s_sin.o): In function `__cos': (.text+0x3542): warning: undefined reference to `_dl_x86_cpu_features' /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libm.a(s_sin.o): In function `__sin': (.text+0x3572): warning: undefined reference to `_dl_x86_cpu_features' [prompt]> ll sin_ma_undefined.out -rwxrwxr-x 1 cfati cfati 104088 Jun 13 20:10 sin_ma_undefined.out [prompt]> ldd sin_ma_undefined.out linux-vdso.so.1 => (0x00007fff984b0000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f274ad00000) /lib64/ld-linux-x86-64.so.2 (0x00007f274b0ca000) [prompt]> ./sin_ma_undefined.out Segmentation fault (core dumped)
它通过了链接阶段,但在运行时出现了段错误(这是预期的)。
遇到了[Amper.Git]: open-source/glibc - 将 _dl_x86_cpu_features 添加到 rtld_global(请注意,这些都不在官方glibc 中:[GNU]: /gnu/libc 的索引)。那里有一些相当重的东西。我“借”了一些并保存起来。
_dl_x86_cpu_features.c:
#if defined(_DL_X86_CPU_FEATURES__WORKAROUND)
# define FEATURE_INDEX_MAX 1
enum {
COMMON_CPUID_INDEX_1 = 0,
COMMON_CPUID_INDEX_7,
COMMON_CPUID_INDEX_80000001, // for AMD
// Keep the following line at the end.
COMMON_CPUID_INDEX_MAX
};
struct cpu_features {
enum cpu_features_kind {
arch_kind_unknown = 0,
arch_kind_intel,
arch_kind_amd,
arch_kind_other
} kind;
int max_cpuid;
struct cpuid_registers {
unsigned int eax;
unsigned int ebx;
unsigned int ecx;
unsigned int edx;
} cpuid[COMMON_CPUID_INDEX_MAX];
unsigned int family;
unsigned int model;
unsigned int feature[FEATURE_INDEX_MAX];
};
struct cpu_features _dl_x86_cpu_features;
#endif
Run Code Online (Sandbox Code Playgroud)
#include "_dl_x86_cpu_features.c"还需要在main.c中添加:
Run Code Online (Sandbox Code Playgroud)[prompt]> gcc -fPIC main.c -DFUNC=sin -D_DL_X86_CPU_FEATURES__WORKAROUND -o sin_ma_workaround.out -l:libm.a [prompt]> ll sin_ma_workaround.out -rwxrwxr-x 1 cfati cfati 104088 Jun 13 20:13 sin_ma_workaround.out [prompt]> ldd sin_ma_workaround.out linux-vdso.so.1 => (0x00007fff17b6c000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5a992e5000) /lib64/ld-linux-x86-64.so.2 (0x00007f5a996af000) [prompt]> ./sin_ma_workaround.out func(3.141592): 0.000001
显然,它有效(至少在我的环境中)!
尽管它对我有用(并且可能在您的情况下也是如此),但我仍然认为它是一种解决方法(gainarie),并且我不知道其全部含义。
因此,我的建议是采用推荐选项(从步骤#2 开始)(其中之一)。
但是,看看其他编译器的行为方式会很有趣。
| 归档时间: |
|
| 查看次数: |
8050 次 |
| 最近记录: |