linux 高版本gcc兼容低版本系统的方法
3、使用musl-gcc的静态编译二进制,这个只要代码能编译出来,就基本能拿到各个系统下去运行,但源码中应该不能包含系统调用,缺少之类的内核相关的头文件,猜测需要把buildroot放在一起编译才行。我们不能在低版本的系统上去运行只有高版本实现的功能,只能运行两者有相同签名实现且结果是相同的,才能做版本替换,否则是需要自行去实现功能的,无论是静态还是这些方法,都不能去绕开这个最基本的问题。以下是两
在ubuntu22上编译的程序无法拿到centos5上去运行,想必大家都知道是因为gcc版本的原因。追究其本质,是因为编译出来的二进制的符号,与目标机器上libc.so里面符号的版本不同的原因。甚至连最简单的main函数__libc_start_main,也有2.2.5和2.34两个版本,所以gcc11编译出来的二进制拿到centos5上一运行,就会报
/lib64/libc.so.6: version `GLIBC_2.34' not found (required by ./main)
先看下网上一些人给出的方法(不靠谱的):
1、直接拷贝动态库,这个用脑子想想都知道是有问题的,libc.so里面的函数是在用户态下对内核调用的封装,版本跨度稍微大一点就对不齐,肯定跑不起来
2、编译成静态二进制,编译时指定-static,经测试无效,在源码中调用某些系统函数后,仍然有libc.so.6的链接
3、使用musl-gcc的静态编译二进制,这个只要代码能编译出来,就基本能拿到各个系统下去运行,但源码中应该不能包含系统调用,缺少<linux/version.h> <asm/signal.h> 之类的内核相关的头文件,猜测需要把buildroot放在一起编译才行
4、安装低版本gcc,这个办法太过愚笨和麻烦了,且不具有代表性,另外gcc11是没法编译gcc4.1的,要先安装gcc6以下的,才能去编译gcc4.1
以下是两种方案是合理、可行的
5、在源码中添加函数的实现,并在链接时通过wrap覆盖,指向自己的函数。个人认为这种方式可靠性是最高的,也是真正意义上的兼容,可以自行实现或替换版本,缺点就是非常麻烦,还有需要源码才能编译
https://blog.mewwoof.cn/tech/cs-os/1716/
6、直接修改elf中的版本信息,这个与上面方法互补,不需要源码,简单粗暴。网上有很多手动修改的方法,例如:
https://zohead.com/archives/mod-elf-glibc/
看一下原理,肯定有自动化的办法,找到了lief这个库。适用于不需要自行实现的情况,只是替换glibc的版本信息,调用这个sdk,可以快速实现替换。顺便说一句,替换了如果没有glibc没有符号,程序也是无法运行的,需要配合patchelf,把自己写的函数实现的so添加进来
https://lief-project.github.io/
#!/usr/bin/env python3
# coding=utf-8
import lief
if __name__ == "__main__":
bi = lief.parse('main')
print(bi)
# 经测试,不改符号表里的版本信息也是可以运行的,可能是只在加载elf的时候判断libc.so的版本信息
# for _ in bi.symbols:
# if _.symbol_version:
# if 'start_main' in _.name:
# # 修改高版本方法符号表对应的版本,
# _.symbol_version.value = 2
glibc_2_2_5 = None
# 查看 .gnu.version_r 信息
for _ in bi.symbols_version_requirement:
print(_.name, _.version)
for _s in _.get_auxiliary_symbols():
print('\t', _s)
print('\t', _s.flags, _s.hash, _s.name, _s.other)
if _s.name == 'GLIBC_2.2.5':
glibc_2_2_5 = _s
break
for _ in bi.symbols_version_requirement:
if 'libc.so.6' in _.name or "libm.so.6" in _.name:
for _v in _.get_auxiliary_symbols():
if "GLIBC_2.34" == _v.name:
_v.flags = glibc_2_2_5.flags
_v.hash = glibc_2_2_5.hash
_v.name = glibc_2_2_5.name
_v.other = glibc_2_2_5.other
bi.write('main_new')
再回过头来总结一下,兼容所解决的问题,是具有局限性的。我们不能在低版本的系统上去运行只有高版本实现的功能,只能运行两者有相同签名实现且结果是相同的,才能做版本替换,否则是需要自行去实现功能的,无论是静态还是这些方法,都不能去绕开这个最基本的问题。
更多推荐
所有评论(0)