链接错误:GCC中libm.a的选择性静态链接 [英] Linking error: selective static linking of libm.a in GCC

查看:244
本文介绍了链接错误:GCC中libm.a的选择性静态链接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想静态地选择性地链接 libm.a ,所有其他库(包括 libc.so )都动态地链接.但是,如果我使用 math.h 中的数学函数,则几乎总是无法正确链接.为什么?为何有时会起作用?(例如,如果我仅使用 sqrt fabs 或奇怪的是 tanh ,它似乎可以正确链接)

I want to selectively link libm.a statically, all the other libraries (libc.so included) dinamically. But if I use the math functions from math.h, it almost always fails to link correctly. Why? And why does it work sometimes? (For example if I only use sqrt, fabs or, strangely, tanh, it seems to link correctly)

myscript.sh:

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

prova.c:

#include <stdio.h>
#include <math.h>
int main()
{
    printf("%f", ciao(2.0));
    return 0;
}

如果运行 myscript.sh ,我可以看到 sqrt tanh 没有问题.相反, sin tan 无法链接:

If I run myscript.sh, I can see that sqrt and tanh give no problems. sin and tan, instead, fail to link:

$./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

我不理解这些错误消息.有人可以解释会发生什么吗?为什么我不能静态地链接 libm.a (其余都动态链接)?为何有时会起作用?

I don't understand these error messages. Can somebody explain what happens? Why can't I link libm.a statically (and the rest dinamically)? And why does it work sometimes?

注意::我对GCC使用了 -fno-builtin 标志,因此GCC不使用其任何内置功能.因此问题不存在.

Note: I use the -fno-builtin flag to GCC, so that GCC doesn't use any of its builtin functions. So the problem is not there.

推荐答案

(对我而言)尚不清楚为什么限制( libm.a + libc.so )是必需的,因此它闻起来像是 XY问题.

It's not very clear (to me) why the restriction (libm.a + libc.so) is necessary, so it smells like an XY Problem.

根据 [RedHat.Bugzilla]:错误1433347-glibc:的选择性静态链接libm.a因未解析的_dl_x86_cpu_features符号而失败(由@KamilCuk指出):

According to [RedHat.Bugzilla]: Bug 1433347 - glibc: Selective static linking of libm.a fails due to unresolved _dl_x86_cpu_features symbol (pointed out by @KamilCuk):

不支持此操作.

您将静态libm.a与将来的libc.so.6和ld.so混合在一起,这将破坏形成"C运行时的实现"的核心库之间的相互依赖性.

You would be mixing a static libm.a with future libc.so.6 and ld.so and that breaks the interdependencies between the core libraries which form "the implemetnation of the C runtime."

要么运行时的整个实现是静态链接的,要么都不是静态链接的.您不能选择静态链接它的一部分,而不能选择静态链接,因为每个部分都依赖于另一个来形成完整的实现.数学库不是可以静态链接的瘦库,它恰好有一个libm.a,但这是一个实现细节.

Either the entire implementation of the runtime is statically linked or none of it is statically linked. You can't choose to link parts of it statically and not others because each part depends on the other to form a complete implementation. The math library is not a thin you can link against statically, it happens we have a libm.a, but that's an implementation detail.

请在整个应用程序中使用"-static".

Please use '-static' for the entire application.

似乎是不受支持的配置.这是有道理的,但也有些令人困惑:即使 libc libm 是磁盘上的 2个独立文件(对于每种配置, static shared ),它们是同一库的一部分( g libc ),所以:

it seems like it's an unsupported configuration. That makes sense, but it's also a little bit confusing: even if libc and libm are 2 separate files on disk (for each configuration: static, shared), they are part of the same library (glibc), so:

  • 使用静态构建的库的一半,而将另一半用作共享库,这不是确定(我想到的一些事情是: gcc -fPIC 标志,以及库的初始化)
  • 当然,在大多数情况下,库由单个文件组成,因此上述项目符号将不适用(这是造成混淆的地方)
  • It's not OK to use half of a library statically built, and the other half as a shared object (some things that come into my mind are: gcc's -fPIC flag, and also library's initialization)
  • Of course, most of the times, a library consists of a single file, so the above bullet wouldn't apply (there's where the confusion comes from)

从一开始,我就怀疑这是一些(检测并)使用(如果存在)某些 CPU 功能(最有可能提高速度或准确性)的代码,

From the beginning, I suspected that it's some code that (detects and) uses (if present) some CPU capabilities (most likely to improve speed or accuracy), that:

  • 仅由某些(三角函数)使用(例如 sin cos ,但 tanh )-我只是在这里猜测:基于函数值的计算方式(例如 Taylor系列)
  • 只有在 libc ( libm )同步时才会发生
  • Is only used by some of the (trigonometric) functions (like sin, cos, but not tanh) - I'm just guessing here: based on how the function values are computed (e.g. Taylor series)
  • It only happens when libc (libm) are in sync

我用了这个简单的程序.

I used this simple program.

main.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;
}

下面是调查问题时遵循的一系列步骤:

Below it's a series of steps that I followed when looking into the problem:

  1. 环境:

  1. Environment:

[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

  • 两个库部分( libc libm )同步的情况:

    [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
    

    在两种情况下一切正常.

    Everything works fine in both cases.

    切换到 libm.a (用于 sin tanh ):

    [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
    

    如图所示:

    • 对于 sin ,链接器抱怨(甚至没有 -fno-builtin )
    • 对于 tanh ,一切都很好
    • For sin, the linker complained (even without -fno-builtin)
    • For tanh, things went fine

    从现在开始,我将集中讨论无法解决的情况.

    From now on, I'm going to focus on the case that doesn't work.

    使用链接器标志( man ld (

    Play a bit with the linker flags (man ld ([die.linux]: ld(1) - Linux man page)):

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

    它已经通过了链接阶段,但是在运行时出现了 segfault (这是我们所期望的).

    It passed the link phase, but segfaulted at runtime (which was kind of expected).

    遍历 [Amper.Git]:打开-source/glibc-将_dl_x86_cpu_features添加到rtld_global (请注意,其中的 none 都不在官方 glibc 中: [GNU]:/gnu/libc的索引).那是一些很重的东西.我借用"了一些并保存了.

    Came across [Amper.Git]: open-source/glibc - Add _dl_x86_cpu_features to rtld_global (note that none of that is in the official glibc: [GNU]: Index of /gnu/libc). It's some pretty heavy stuff there. I "borrowed" some and saved it.

    _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
    

    #include"_dl_x86_cpu_features.c" 也需要添加到 main.c 中:

    [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
    

    显然,它可以工作(至少在我的环境中有效)!

    Apparently, it works (at least in my environment)!!!

    尽管它对我有用(可能与您的情况相同),但我仍然认为它是一种解决方法( gainarie ),并且我不知道完整的含义.
    因此,我的建议是使用推荐的选项之一(从步骤 #2. ).
    但是,看看其他编译器的行为会很有趣.

    Although it did the trick for me (and probably it will be the same in your case), I still consider it a workaround (gainarie), and I'm not aware of the full implications.
    So, my advice is to go with (either one of) the recommended options (from step #2.).
    But, it would be interesting to see how other compilers behave.

    这篇关于链接错误:GCC中libm.a的选择性静态链接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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