首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ldd -版本的输出与ldd -r -v a.out的不匹配

ldd -版本的输出与ldd -r -v a.out的不匹配
EN

Stack Overflow用户
提问于 2021-12-18 15:29:04
回答 1查看 305关注 0票数 1

我想弄清楚ldd --versionldd -v a.out的输出

我有下面的简单程序

代码语言:javascript
复制
#include <iostream>
#include <string>
#include <cstring>

int main()
{
    std::cout << "Hello world" << std::endl;
    std::string a = "Test string";
    char b[15] = {};
    memcpy(b, a.c_str(), 15);
    std::cout << b << std::endl;
    return 0;
}

我用以下命令编译它

g++ --std=c++17 test.cpp

我想知道这个程序在运行memcpy时将使用哪个glibc版本。

ldd --version在该系统上的输出如下:

代码语言:javascript
复制
ldd --version
ldd (Ubuntu GLIBC 2.31-0ubuntu9.2) 2.31
Copyright (C) 2020 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.

ldd -v a.out的输出是

代码语言:javascript
复制
ldd -v a.out 
    linux-vdso.so.1 (0x00007ffe7d3f3000)
    libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f050bb2f000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f050bb14000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f050b922000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f050b7d3000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f050bd3a000)

    Version information:
    ./a.out:
        libgcc_s.so.1 (GCC_3.0) => /lib/x86_64-linux-gnu/libgcc_s.so.1
        libc.so.6 (GLIBC_2.4) => /lib/x86_64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.2.5) => /lib/x86_64-linux-gnu/libc.so.6
        libstdc++.so.6 (GLIBCXX_3.4.21) => /usr/lib/x86_64-linux-gnu/libstdc++.so.6
        libstdc++.so.6 (CXXABI_1.3) => /usr/lib/x86_64-linux-gnu/libstdc++.so.6
        libstdc++.so.6 (GLIBCXX_3.4) => /usr/lib/x86_64-linux-gnu/libstdc++.so.6
    /usr/lib/x86_64-linux-gnu/libstdc++.so.6:
        libm.so.6 (GLIBC_2.2.5) => /lib/x86_64-linux-gnu/libm.so.6
        ld-linux-x86-64.so.2 (GLIBC_2.3) => /lib64/ld-linux-x86-64.so.2
        libgcc_s.so.1 (GCC_4.2.0) => /lib/x86_64-linux-gnu/libgcc_s.so.1
        libgcc_s.so.1 (GCC_3.4) => /lib/x86_64-linux-gnu/libgcc_s.so.1
        libgcc_s.so.1 (GCC_3.3) => /lib/x86_64-linux-gnu/libgcc_s.so.1
        libgcc_s.so.1 (GCC_3.0) => /lib/x86_64-linux-gnu/libgcc_s.so.1
        libc.so.6 (GLIBC_2.14) => /lib/x86_64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.6) => /lib/x86_64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.4) => /lib/x86_64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.18) => /lib/x86_64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.16) => /lib/x86_64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.3) => /lib/x86_64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.3.4) => /lib/x86_64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.17) => /lib/x86_64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.3.2) => /lib/x86_64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.2.5) => /lib/x86_64-linux-gnu/libc.so.6
    /lib/x86_64-linux-gnu/libgcc_s.so.1:
        libc.so.6 (GLIBC_2.14) => /lib/x86_64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.2.5) => /lib/x86_64-linux-gnu/libc.so.6
    /lib/x86_64-linux-gnu/libc.so.6:
        ld-linux-x86-64.so.2 (GLIBC_2.3) => /lib64/ld-linux-x86-64.so.2
        ld-linux-x86-64.so.2 (GLIBC_PRIVATE) => /lib64/ld-linux-x86-64.so.2
    /lib/x86_64-linux-gnu/libm.so.6:
        ld-linux-x86-64.so.2 (GLIBC_PRIVATE) => /lib64/ld-linux-x86-64.so.2
        libc.so.6 (GLIBC_2.4) => /lib/x86_64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.2.5) => /lib/x86_64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_PRIVATE) => /lib/x86_64-linux-gnu/libc.so.6

我无法理解的是,如果ldd --version说我有GLIBC版本2.31可用,那么为什么我的可执行文件ldd输出中写着GLIBC_2.4GLIBC_2.2.5 for a.out。

了解这一点的正确方法是什么?

如果我在一个具有旧版本libc.so的系统上编译了一个二进制文件(假设GLIBC的最高版本为2.17),然后在一个新版本的libc.so系统上运行这个二进制文件(假设GLIBC的最高版本为2.31)呢?

谢谢

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-12-18 20:01:45

您应该阅读这个答案,并查看来自readelf -V a.out的输出。

当程序被链接时,它会记录链接时使用的符号版本。

您的程序使用的许多符号自GLIBC_2.2.5以来都没有改变,因此ldd说:您至少需要版本GLIBC_2.2.5 (对于这些符号)。您使用的一些符号在GLIBC-2.16GLIBC-2.17GLIBC-2.18中已经更改,因此ldd表示您也需要这些符号。

如果我在一个具有旧版本libc.so的系统上编译了一个二进制文件(假设GLIBC的最高版本为2.17),然后在一个新版本的libc.so系统上运行这个二进制文件(假设GLIBC的最高版本为2.31)呢?

记录的符号(编码到a.out中)都将是GLIBC_2.17或更旧的,程序将在较新的系统上运行良好,因为GLIBC保证向后兼容性(构建在旧系统上的程序在较新的系统上继续运行良好)。

但是,如果您在GLIBC-2.31系统上执行逆编译,并试图在GLIBC-2.17系统上运行程序,它可能(或者不可能,取决于它实际使用的符号)失败。

在您提供的示例中,GLIBC的最高要求版本是GLIBC_2.18。因此,这个特定的a.outGLIBC-2.18或较新的系统上可以正常工作,但是在GLIBC-2.17或较旧的系统上会失败。

更新:

如果在具有最高版本GLIBC_2_17的旧系统上编译的可执行文件在具有GLIBC_2_31可用的系统上运行,会发生什么情况?可执行程序会选择最新的符号(如果它们是ABI投诉的话),例如在旧系统上编译的memcpy - exec (使用GLIBC没有矢量支持),当在新系统上运行时(使用具有memcpy和向量支持的GLIBC )将从具有向量支持的新GLIBC中选择memcpy。

是的,可执行文件将获取它所链接的版本,只要给定函数的ABI没有改变,它将是最近的版本。

特别是memcpy的情况要复杂一些。在Fedora 35 x86_64 system (GLIBC-2.34)上:

代码语言:javascript
复制
nm /lib64/libc.so.6 | grep ' memcpy'
00000000000a1560 i memcpy
00000000000a1560 i memcpy@@GLIBC_2.14
00000000000b9c30 T memcpy@GLIBC_2.2.5

您可以在这里看到的是,memcpy ABI在GLIBC-2.14中发生了变化,并且变成了GNU间接函数。您可以在链接中读取详细信息,但TL;DR表示,程序调用的实际函数将取决于处理器功能。可能是其中的任何一种:

代码语言:javascript
复制
00000000001870b0 t __memcpy_avx512_no_vzeroupper
0000000000189f00 t __memcpy_avx512_unaligned
0000000000189f70 t __memcpy_avx512_unaligned_erms
00000000001828f0 t __memcpy_avx_unaligned
0000000000182960 t __memcpy_avx_unaligned_erms
000000000018b0e0 t __memcpy_avx_unaligned_erms_rtm
000000000018b070 t __memcpy_avx_unaligned_rtm
00000000000b9ca0 t __memcpy_erms
00000000001920b0 t __memcpy_evex_unaligned
0000000000192120 t __memcpy_evex_unaligned_erms
00000000000b9c30 t __memcpy_sse2_unaligned
00000000000b9d10 t __memcpy_sse2_unaligned_erms
000000000015d400 t __memcpy_ssse3
0000000000162990 t __memcpy_ssse3_back
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70404688

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档