美文网首页
高版本gcc编译出的程序在低版本glibc机器上运行

高版本gcc编译出的程序在低版本glibc机器上运行

作者: chnmagnus | 来源:发表于2020-03-26 14:00 被阅读0次

    比如我们用gcc 9.3.0编译程序,但需要发布的机器gcc版本是4.8.5,怎么办?

    你可能想到如下方法

    1. 静态编译
    2. 容器发布
    3. 打包依赖的so,使用本地so运行程序

    1.静态编译

    将libc和libstdc++静态编译,编译时带上如下参数。

    g++ -static-libgcc -static-libstdc++
    

    glibc并不推荐静态链接,你依赖的其他库可能依赖的了glibc,并且往往是动态链接的,可以通过nm <bin> | grep GLIBC_确定你的程序是否依赖了glibc。

    2.容器发布

    使用携带gcc9.3.0环境的容器发布程序,是可以的。但是在一些没有容器且没有sudo权限的场合,依然不太友好。

    3.打包依赖的so发布

    这个方法虽然听起来不是很优雅,但其实如果你对elf文件有一些了解,是不错的方式。下面说下具体的方法。

    3.1 方式1 在编译时设置rpath和dynamic linker

    当你有条件获得程序源码,并能够重新编译时,可以直接在编译时指定相关参数来解决。
    先说编译时要增加的参数:

    # 绝对路径
    gcc -Wl,-rpath='/my/lib',-dynamic-linker='/my/lib/ld-linux.so.2'
    

    gcc参数

    -Wl,option
    Pass option as an option to the linker.

    ld参数

    -rpath=dir
    Add a directory to the runtime library search path. This is used when linking an ELF executable with shared objects.
    --dynamic-linker=file
    Set the name of the dynamic linker.

    这两个参数分别设置的elf文件中的rpath和interpreter字段。

    rpath
    全名run-time search path,是elf文件中一个字段,它指定了可执行文件执行时搜索so文件的第一优先位置,一般编译器默认将该字段设为空。elf文件中还有一个类似的字段runpath,其作用与rpath类似,但搜索优先级稍低。搜索优先级:

    rpath > LD_LIBRARY_PATH > runpath > ldconfig缓存 > 默认的/lib,/usr/lib等
    

    如果你需要使用相对路径指定lib文件夹,可以使用ORIGIN变量,ld会将ORIGIN理解成可执行文件所在的路径。

    gcc -Wl,-rpath='$ORIGIN/../lib'
    

    interpreter
    动态库加载器,程序启动时,操作系统会先把控制权转交给ld-linux-x86-64.so.2,该so负责加载所有程序依赖的so。。这个字段在链接时会帮你自动设置,64bit程序一般为/lib64/ld-linux-x86-64.so.2。修改rpath或者LD_LIBRARY_PATH指向本地lib目录,但通过ldd程序,发现/lib64/ld-linux-x86-64.so.2这个so仍然指向系统so。原因就是这个字段是写死在elf文件中的,并不受LD_LIBRARY_PATH影响。

    编译时带上这两个参数,下面只需要将你程序依赖的so打包一份,随程序进行发布即可。

    3.2 方式2 直接修改二进制程序的rpath和interpreter

    当你无法编译程序时,也可以通过其他方式修改rpath和interpreter。这种情况需要使用到一个工具patchelf,通过dnf install patchelf即可安装。你可以通过它修改elf文件的rpath和interpreter:

    patchelf --set-rpath /my/lib your_program
    patchelf --set-interpreter /my/lib/ld-linux.so.2 your_program
    

    除了绝对路径,一种比较常见的方式是在部署前,使用pwd获取当前路径,使用相对路径指向本地lib。

    patchelf --set-rpath `pwd`/../lib your_program
    patchelf --set-interpreter `pwd`/../lib/ld-linux-x86-64.so.2 ./your_program
    

    相关文章

      网友评论

          本文标题:高版本gcc编译出的程序在低版本glibc机器上运行

          本文链接:https://www.haomeiwen.com/subject/dgzquhtx.html