Linux 链接到旧版本的 libc 以提供更大的应用程序覆盖范围

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4032373/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 23:48:32  来源:igfitidea点击:

Linking against an old version of libc to provide greater application coverage

linuxlinkerlibc

提问by Gearoid Murphy

Linux binaries are usually dynamically linked to the core system library (libc). This keeps the memory footprint of the binary quite small but binaries which are dependent on the latest libraries will not run on older systems. Conversely, binaries linked to older libraries will run happily on the latest systems.

Linux 二进制文件通常动态链接到核心系统库 (libc)。这使二进制文件的内存占用非常小,但依赖于最新库的二进制文件不会在旧系统上运行。相反,链接到旧库的二进制文件将在最新系统上愉快地运行。

Therefore, in order to ensure our application has good coverage during distribution we need to figure out the oldest libc we can support and link our binary against that.

因此,为了确保我们的应用程序在分发过程中具有良好的覆盖率,我们需要找出我们可以支持的最旧的 libc,并将我们的二进制文件与之链接。

How should we determine the oldest version of libc we can link to?

我们应该如何确定我们可以链接到的最旧版本的 libc?

采纳答案by Sam Morris

Work out which symbols in your executable are creating the dependency on the undesired version of glibc.

找出您的可执行文件中的哪些符号正在创建对不需要的 glibc 版本的依赖。

$ objdump -p myprog
...
Version References:
  required from libc.so.6:
    0x09691972 0x00 05 GLIBC_2.3
    0x09691a75 0x00 03 GLIBC_2.2.5

$ objdump -T myprog | fgrep GLIBC_2.3
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.3   realpath

Look within the depended-upon library to see if there are any symbols in older versions that you can link against:

在依赖库中查看旧版本中是否有任何可以链接的符号:

$ objdump -T /lib/libc.so.6 | grep -w realpath
0000000000105d90 g    DF .text  0000000000000021 (GLIBC_2.2.5) realpath
000000000003e7b0 g    DF .text  00000000000004bf  GLIBC_2.3   realpath

We're in luck!

我们很幸运!

Request the version from GLIBC_2.2.5in your code:

GLIBC_2.2.5您的代码中请求版本:

#include <limits.h>
#include <stdlib.h>

__asm__(".symver realpath,realpath@GLIBC_2.2.5");

int main () {
    realpath ("foo", "bar");
}

Observe that GLIBC_2.3 is no longer needed:

观察到不再需要 GLIBC_2.3:

$ objdump -p myprog
...
Version References:
  required from libc.so.6:
    0x09691a75 0x00 02 GLIBC_2.2.5

$ objdump -T myprog | grep realpath
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 realpath

For further information, see http://web.archive.org/web/20160107032111/http://www.trevorpounds.com/blog/?p=103.

有关更多信息,请参阅http://web.archive.org/web/20160107032111/http://www.trevorpounds.com/blog/?p=103

回答by Douglas Leeder

glibc 2.2 is a pretty common minimum version. However finding a build platform for that version may be non-trivial.

glibc 2.2 是一个非常常见的最低版本。然而,为该版本找到一个构建平台可能并非易事。

Probably a better direction is to think about the oldest OS you want to support and build on that.

可能更好的方向是考虑您想要支持的最古老的操作系统并以此为基础。

回答by nicky_zs

Unfortunately, @Sam's solution doesn't work well in my situation. But according to his way, I found my own way to solve that.

不幸的是,@Sam 的解决方案在我的情况下效果不佳。但是按照他的方式,我找到了自己的解决方法。

This is my situation:

这是我的情况:

I'm writing a C++ program using the Thrift framework(it's an RPC middleware). I prefer static link to dynamic link, so my program is linked to libthrift.astatically instead of libthrift.so. However, libthrift.ais dynamically linked to glibc, and since my libthrift.ais build on my system with glibc 2.15, my libthrift.auses memcpyof version 2.14(memcpy@GLIBC_2.14) provided by glibc 2.15.

我正在使用 Thrift 框架(它是一个 RPC 中间件)编写一个 C++ 程序。我更喜欢静态链接到动态链接,所以我的程序是静态链接到libthrift.a而不是libthrift.so。但是,libthrift.a是动态链接到 glibc 的,并且由于我的libthrift.a是使用 glibc 2.15 在我的系统上构建的,因此我的libthrift.a使用由 glibc 2.15 提供的2.14 版(memcpy@GLIBC_2.14)的memcpy

But the problem is that our server machines have only the glibc version 2.5 which has only memcpy@GLIBC_2.2.5. It is much lower than memcpy@GLIBC_2.14. So, of course, my server program can't run on those machines.

但问题是我们的服务器机器只有 glibc 2.5 版,只有memcpy@GLIBC_2.2.5。它远低于memcpy@GLIBC_2.14。所以,当然,我的服务器程序不能在那些机器上运行。

And I found this solusion:

我找到了这个解决方案:

  1. Using .symver to obtain the ref to memcpy@GLIBC_2.2.5.

  2. Write my own __wrap_memcpyfunction which just calls memcpy@GLIBC_2.2.5directly.

  3. When linking my program, add -Wl,--wrap=memcpyoption to gcc/g++.

  1. 使用 .symver 获取对memcpy@GLIBC_2.2.5的引用。

  2. 编写我自己的__wrap_memcpy函数,它直接调用memcpy@GLIBC_2.2.5

  3. 链接我的程序时,将-Wl,--wrap=memcpy选项添加到 gcc/g++。

The code involved in steps 1 and 2 is here: https://gist.github.com/nicky-zs/7541169

步骤 1 和 2 中涉及的代码在这里:https: //gist.github.com/nicky-zs/7541169

回答by patstew

To do this in a more automated fashion, you can use the following script to create a list of all the symbols that are newer in your GLIBC than in a given version (set on line 2). It creates a glibc.hfile (filename set by the script argument) which contains all the necessary .symverdeclarations. You can then add -include glibc.hto your CFLAGS to make sure it gets picked up everywhere in your compilation.

要以更自动化的方式执行此操作,您可以使用以下脚本创建 GLIBC 中比给定版本(在第 2 行设置)中更新的所有符号的列表。它创建一个glibc.h包含所有必要.symver声明的文件(由脚本参数设置的文件名)。然后您可以添加-include glibc.h到您的 CFLAGS 以确保它在您的编译中随处可见。

This is sufficient if you don't use any static libraries that were compiled without the above include. If you do, and you don't want to recompile, you can use objcopyto create a copy of the library with the symbols renamed to the old versions. The second to bottom line of the script creates a version of your system libstdc++.athat will link against the old glibc symbols. Adding -L.(or -Lpath/to/libstdc++.a/) will make your program statically link libstdc++ without linking in a bunch of new symbols. If you don't need this, delete the last two lines and the printf ... redeffline.

如果您不使用在没有上述包含的情况下编译的任何静态库,这就足够了。如果这样做,并且不想重新编译,则可以使用objcopy来创建库的副本,并将符号重命名为旧版本。脚本的倒数第二行创建了一个系统版本,该版本libstdc++.a将链接到旧的 glibc 符号。添加-L.(或-Lpath/to/libstdc++.a/) 将使您的程序静态链接 libstdc++ 而不链接一堆新符号。如果您不需要这个,请删除最后两行和该printf ... redeff行。

#!/bin/bash
maxver=2.9
headerf=${1:-glibc.h}
set -e
for lib in libc.so.6 libm.so.6 libpthread.so.0 libdl.so.2 libresolv.so.2 librt.so.1; do
objdump -T /usr/lib/$lib
done | awk -v maxver=${maxver} -vheaderf=${headerf} -vredeff=${headerf}.redef -f <(cat <<'EOF'
BEGIN {
split(maxver, ver, /\./)
limit_ver = ver[1] * 10000 + ver[2]*100 + ver[3]
}
/GLIBC_/ {
gsub(/\(|\)/, "",$(NF-1))
split($(NF-1), ver, /GLIBC_|\./)
vers = ver[2] * 10000 + ver[3]*100 + ver[4]
if (vers > 0) {
    if (symvertext[$(NF)] != $(NF-1))
        count[$(NF)]++
    if (vers <= limit_ver && vers > symvers[$(NF)]) {
        symvers[$(NF)] = vers
        symvertext[$(NF)] = $(NF-1)
    }
}
}
END {
for (s in symvers) {
    if (count[s] > 1) {
        printf("__asm__(\".symver %s,%s@%s\");\n", s, s, symvertext[s]) > headerf
        printf("%s %s@%s\n", s, s, symvertext[s]) > redeff
    }
}
}
EOF
)
sort ${headerf} -o ${headerf}
objcopy --redefine-syms=${headerf}.redef /usr/lib/libstdc++.a libstdc++.a
rm ${headerf}.redef