谈谈Linux应用程序 ABI兼容性

谈谈Linux应用程序ABI兼容性

背景

最近工作中遇到个问题,就是多个系统跑着不同版本的内核,不同架构的ARM芯片,上层的业务程序能否二进制归一(共镜像)。

根据自己对Linux的了解,glibc是否可以在ABI层面做到向前兼容。那个整个系统能否做到呢?这勾起了我的分析和思考。

ABI兼容依赖什么

试想一下,一个程序从源代码到最终的二进制,有哪些组件参与了编译和链接过程,大概如下:

  • 内核导出用户态头文件
  • gcc编译器,gcc提供的静态.o/.a,以及它提供的动态库(如libgcc_s.so)
  • glibc
  • 第三方开源库

需要分析各组通能否做到二进制兼容性,以及是如何做到的。下面我对各组件,以思维导图来分析是否能满足ABI兼容性。

上面的思维导图把我想到的组件都进行细分,把每个细节都覆盖到。当然,还会有一些细节是我没有想到的。下面对不那么常见的组件进行说明:

  • 内核导出头文件: 构建过交叉编译工具链是嵌入式里面常做的事情,工具链的构建需要使用内核导出的导文件。这是内核态和用户约定好的基础类型和数据结构,比如我们常见的time_t,pid_t等等类型。整于用户态软件都以它为基石。
  • glibc版本机制:glibc对大部分符号都打上版本号,日后在高版本的glibc中,由于POSIX/LSB标准的变化,或者函数接口有变,它会创建该符号的另一新版本,但原来版本的符号仍然存在,同时语义和参数保持不变。它通过这种机制来保证ABI的向前兼容性(请注意,无法保证向后的兼容性)

从分析来看,大部分软件都是可以保持向前兼容的。这就是为什么从一台机制上的程序拷贝到另一台机制上,程序还能正常运行。

Linux standard Base(LSB)

噢,这到底是巧合呢?还是什么:所有Linux 程序都是在所有机器上运行。我也带个着这个问题去找一些资料。

想信大家听说到POSIX规范,Linux Standard Base(LSB)规范。起初,我以为LSB是API规范而非ABI规范。当我去深入分析时,发现它是一个ABI规范,它解决两方面的问题:

  • 在发行版Linux A上运行的程序,可以运行在发行版本Linux B上。
  • 应用程序在现在的机器上运行,也能在未来新系统和机器上运行。

最近Linux基金会发起LSB项目就是希望Linux发行商能做到相互兼容,并且也能向前兼容。解决Linux应用的可移植性和兼容性。

LSB实际是是一组ABI接口的定义,它规范了运行环境所需要的类型,宏,变量和函数的二进制接口。

那么,哪些东西受到LSB的制约呢?也即LSB规范约束的范围多广。刚开始,我还以为只有kernel, glibc等一些关键的组件。事实上,打开LSB官网说明会发现它包罗万象,从命令,ELF,glibc接口,到桌面,脚本语言等等都有相关的规定。

谁应该遵守LSB规范

毫无疑问,kernel, glibc等都应该遵守LSB标准。事情上,并非如此。 LSB希望Linux发布版(如Redhat, Suse, Ubuntu)能遵守LSB,因此它提供了LSB的测试套和LSB的认证服务。

那么Kernel和glibc就真的不需要考虑LSB了吧,答案是否定的。整个kernel/glibc和各大Linux知名组件都以开源方式进行开发,它里面的技术早已不是什么密秘了,各大公司都有工程师参与,所有公司都希望这些软件都是遵守LSB,使所有软件都能轻易地融合在一起,不希望让发生行商花很大力气去集成。因此所有软件都是会尽量遵守LSB规范,但无法排除有那么一两个例外的Case。

glibc是大家用得最多的组件,也算是我比较了解的组件之一,到网上找了一些它的兼容性分析,发现它也不能保证100%向前兼容。不能完全兼容的发生在2.16.0和2.13两个版本上。当前对于一般的软件,这个兼容性是完全足够了的。

“向后”兼容性

那么Linux能做到向后兼容性吗?答案是否定的,因为LSB也无法做到向后兼容。

那问题来了,如果我需要做到向后兼容呢?假如有下面这种场景:

很多服务器都是Ubuntu 7.04,算是8年前的服务器了,数量很多。同时也会有服务器使用了12.04,数量较少。但12.04上的编译器较新,支持很多安全功能。架构师的诉求就是:能否基于12.04版本运行环境做开发编译,生成的服务程序能同时运行在7.04和12.04两个服务器上。

我能想到的解决办法:

  • 找到Ubuntu 7.04和12.04两服务器运行软件,所遵守的LSB版本,服务程序只能调用这两LSB完全兼容的接口
  • 在编程和链接服务程序时,可以指定程序使用的LSB标准(Ubuntu 7.04版本的LSB)。

对于第一个方法,个人认为可行,但约束很多。方法二未知可行,后续再分析

这就是“向后”兼容性想讨论的一个问题。它不是真正的向后兼容性,完全是依赖于向前兼容来实现的。

后记

兼容性,完全不是我熟悉的东西,只是工作上遇到问题,做了初步分析。希望通过blog记录我的思考,当某一天,我对这个知识有深入的经验,再跟大家分享。如有写得不正确,或者误导的内容,请指正,谢谢!

2015/7/11 于上海 灿鸿台风来袭

版权声明:本文为博主原创文章,承蒙转载请注明作者和出处

时间: 2024-10-06 20:59:10

谈谈Linux应用程序 ABI兼容性的相关文章

谈谈Linux下动态库查找路径的问题 ldconfig LD_LIBRARY_PATH PKG_CONFIG_PATH

谈谈Linux下动态库查找路径的问题 ldconfig LD_LIBRARY_PATH  PKG_CONFIG_PATH 转载自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=23069658&id=4028681 学习到了一个阶段之后,就需要不断的总结.沉淀.清零,然后才能继续“上路”.回想起自己当年刚接触Linux时,不管是用源码包编译程序,还是程序运行时出现的和动态库的各种恩恩怨怨,心里那真叫一个难受.那时候脑袋里曾经

Linux 小知识翻译 - 「Linux和CPU的兼容性」

Linux刚开始是作为可运行在 Intel 的 「i386」CPU上,与POSIX兼容的内核来开发的. 而现在主流的Linux是指能在所谓「PC」上运行的内核.「PC」是指采用「IA(intel架构)」的机器. IA(Intel Architecture)虽然「I」是指Intel,但Linux并不是只能运行在Intel生产的CPU上.比如另一个非常大CPU生产商AMD所生产的兼容IA的CPU, 还有其他很多以省电为目的的兼容IA的CPU,这些CPU都可以被称作「IA」. 因此,Linux也就有可

谢烟客---------Linux之程序包管理基础知识

内核不提供特定的功能:功能由程序提供 程序的格式,ABI Windows:EXE Linux:ELF 程序编译的过程: 源程序 --> 编译 --> 汇编代码 --> 汇编 --> 二进制程序 --> 链接 编译的分类: 静态编译: 将程序运行时依赖的库编译进程序 动态编译:编译后需要链接库,在程序运行时,依据链接找到共享的库 程序跨平台运行 1.库虚拟化,虚拟出对应平台的库和ABI;程序运行在库之上 1).Linux上运行WINE程序,即可虚拟出Linux程序运行所依赖的库

linux之程序包管理器(rpm)

linux下的程序包可支持多种工具编写的,如C.C++.PERL等. 但是这种高级语言编写出来的代码是我们人能看懂的,但是计算机是看不懂的,那么计算机怎么执行,怎么了解人要它做什么呢? 这就需要我们做一些转换了,把人能读懂的语言让机器也能识别,这个过程就是由编译器完成的,通常是吧代码语言转换成二进制语言. 过程:预处理.编译.汇编.链接 一个程序的运行大部分时间是离不开库的. 什么是库呢?库也是一种程序,只不过与其他程序不同,库没有执行入口,不能独立运行,只能被其他独立运行的程序调用的时候才能执

谈谈Linux内存释放

上上周吧,一个朋友问我说他公司的服务器内存free 为0 是为什么,意思大概是内存去哪了,这引发了一个小小的讨论,也就是内存释放的问题… 首先我们可能会用free 去查看内存的使用率,它应该是这样的 [[email protected] ~]# free -m total used free shared buffers cached Mem: 32040 31707 332 0 498 27649 -/+ buffers/cache: 3559 28480 Swap: 16087 0 1608

Linux服务器程序规范

除了网络通信外,服务器程序还必须考虑许多其他细节问题,零碎,但基本上时模板式的. ---引 Linux服务器程序一般以后台形式运行.后台程序又称守护进程.它没有控制终端,因而也不会意外接受用户输入.守护进程的父进程一般是init进程(pid=1). Linux服务器程序通常有一套日志系统,它至少能输出日志到文件,有的高级服务器可以输出日志到专门的UDP服务器.大部分后台进程都在/var/log下有自己的日志目录. Linux服务器程序一般以某个专门的非root身份运行.mysqld, httpd

Linux C程序异常退出怎么办——core文件帮你忙

想必你一定遇到过Linux下程序异常退出的问题,异常退出貌似有一种神奇的魔力,会让你神经突然紧张.不要怕,Linux是很强大的,在程序退出的时候,会在可执行文件所在的目录生成一个core文件,它很好地记录了一些神秘而又必要的东西,帮助你定位到错误的根源,想想以前面试的时候人家闻到core文件,我答不上来,你说面试官会怎样想,那么就来说说core文件. core文件实际上就是一个内存映象同时加上一些调试信息. 首先,你得打开系统的core文件生成开关吧,终端中输入ulimit -c命令,若显示0表

linux应用程序开发-文件编程-系统调用方式

在看韦东山视频linux驱动方面有一些吃力,究其原因,虽然接触过linux应用程序编程,但是没有深入去理解,相关函数用法不清楚,正好看到国嵌视频对这一方面讲的比较透彻, 所以把学习过程记录下来,也作为linux应用程序开发的一个系列吧! 文件编程有两种方式,一是系统调用方式,二是库函数调用. 前者依赖特定的平台,后者不依赖平台. 系统调用:创建 int creat(const char *filename,mode_t mode); filename:要创建的文件名 mode:创建模式 S_IR

linux 统计 程序 运行时间

测试 代码运行时间 linux 中的 <sys/time.h> 中 有个函数可以获取当前时间,精确到 微秒 ---->  gettimeofday() 1 #include <sys/time.h>       // int gettimeofday(struct timeval *tv, struct timezone *tz); 2 /********************************************* 3 * struct timeval 4 *