Linux开发中,新旧版本不同的系统会遇到的一个很大问题是--兼容性。一般情况是旧系统编译的程序可以在新系统中运行,但是反过来新系统中编译的程序在旧系统中就不行了。
最明显的现象是高版本编译的程序在低版本系统中出现错误: /lib64/libc.so.6: version `GLIBC_2.7' not found 当然这个版本号码不一定是本文中的7 还有14也是个新版本,这要看你编译时的系统的版本了。
出现这个问题后我们首先需要确定是那些函数在当前系统(低版本的)中找不到,此处使用 objdump 命令,此处假设我们的应用程序名称为app,则
objdump -T app | grep GLIBC_2.7 (这个号码是上面出错的号码),得到了如下结果
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.7 __isoc99_sscanf
然后根据这个我们再看看当前系统有这个函数的哪个版本,命令如下
objdump -T /lib64/libc.so.6 | grep sscanf 得到如下结果
0000003e3685f050 g DF .text 0000000000000090 GLIBC_2.2.5 _IO_sscanf
0000003e3685f050 g DF .text 0000000000000090 GLIBC_2.2.5 sscanf
0000003e36863d10 w DF .text 000000000000009d GLIBC_2.2.5 vsscanf
0000003e36863d10 w DF .text 000000000000009d GLIBC_2.2.5 __vsscanf
也就是说关于sscanf这个函数当前(低版本)系统只有这几个函数可用,所以我们的软件想在该系统上运行也只能用这些函数,再高级的那就不支持了。
我们再去编译程序的环境下看看它关于这个函数都有那些
objdump -T /lib64/libc.so.6 | grep sscanf
000000335c264ca0 g DF .text 0000000000000090 GLIBC_2.7 __isoc99_sscanf
000000335c264d30 g DF .text 00000000000000a2 GLIBC_2.7 __isoc99_vsscanf
000000335c2639a0 g DF .text 0000000000000090 GLIBC_2.2.5 _IO_sscanf
000000335c2639a0 g DF .text 0000000000000090 GLIBC_2.2.5 sscanf
000000335c269950 w DF .text 000000000000009d GLIBC_2.2.5 vsscanf
000000335c269950 w DF .text 000000000000009d GLIBC_2.2.5 __vsscanf
很明显,前两行正是高版本系统多出来的,也是低版本系统中没有的,也恰恰是程序需要的,
此时,我们在高版本编译时,要指定对于sscanf这个函数就使用GLIBC_2.2.5 sscanf 这个版本就行了,高低版本中都有该函数,而且我们使用的更多的是sscanf的基础功能至于高版本的那个特性,其实我们真的没有用到。
所以我们找到我们程序中包含sscanf的调用的文件,在其前面写上如下汇编
__asm__(".symver __isoc99_sscanf,sscanf@GLIBC_2.2.5");
意思是遇到__isoc99_sscanf 直接变成sscanf@GLIBC_2.2.5就可以了。
如果有sscanf的地方都写这个还太麻烦,针对我们的应用,我们是有一个公共框架的,所以我把这句话写在了这个公用的头文件中,
这样所有包含它的程序都会被编译成低版本的了。
另外一个常见的关于版本的函数问题,大概就是 memcpy了
同样的,我们也写下了这句话:
__asm__(".symver memcpy,memcpy@GLIBC_2.2.5");
编译之后高低版本都没有问题了。免除了非得安装个低版本系统的尴尬。
总结起来就是两步
1. 用 objdump -T 查看程序哪个函数有版本问题;
2.用 __asm__(".symver ..."); 让程序链接旧符号,并编译之。
参考:
http://stackoverflow.com/questions/8823267/linking-against-older-symbol-version-in-a-so-file
http://doudouclever.blog.163.com/blog/static/1751123102014112963416312/