我想弄清楚ldd --version和ldd -v a.out的输出
我有下面的简单程序
#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在该系统上的输出如下:
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的输出是
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.4和GLIBC_2.2.5 for a.out。
了解这一点的正确方法是什么?
如果我在一个具有旧版本libc.so的系统上编译了一个二进制文件(假设GLIBC的最高版本为2.17),然后在一个新版本的libc.so系统上运行这个二进制文件(假设GLIBC的最高版本为2.31)呢?
谢谢
发布于 2021-12-18 20:01:45
您应该阅读这个答案,并查看来自readelf -V a.out的输出。
当程序被链接时,它会记录链接时使用的符号版本。
您的程序使用的许多符号自GLIBC_2.2.5以来都没有改变,因此ldd说:您至少需要版本GLIBC_2.2.5 (对于这些符号)。您使用的一些符号在GLIBC-2.16、GLIBC-2.17和GLIBC-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.out在GLIBC-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)上:
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表示,程序调用的实际函数将取决于处理器功能。可能是其中的任何一种:
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_backhttps://stackoverflow.com/questions/70404688
复制相似问题