APP下载

软硬件集成过程输出的评审分析方法

2018-06-14

软件 2018年5期
关键词:源文件编译器源代码

陈 鑫

(航空工业西安航空计算技术研究所,陕西 西安 710068)

0 引言

随着ARJ21、C919等多个民用飞机型号的相继研制,通用航空领域的不断发展,我国机载软件研制过程中,越来越广泛地认可和使用代表国际先进水平的、来自美国和欧洲等航空发达国家的 RTCA DO-178B[1]/C[2]适航标准。该标准规定了软件研制过程中的各项活动和多个目标,但没有给出如何完成这些活动,也没有说明如何达到这些目标。经过技术人员的不断努力,国内已能应对标准中的大部分要求,但对标准中提到的软硬件集成过程输出的验证、以及编译链接过程和目标码等内容,仍有不少困惑。

本文在简述DO-178B/C标准对软硬件集成过程输出验证的要求的基础上,指出了该活动与目标码覆盖分析(OCA)活动的差别,并以GCC编译器为例,结合国产机载嵌入式操作系统TM2,提出了一个软硬件集成过程输出验证的详细解决方案。

1 适航要求

根据适航要求,机载软件作为高安全高可靠软件,软件开发过程应该确保源代码被正确编译和链接、没有引入错误[3];从验证角度讲,就是要对软硬件集成过程的输出进行评审和分析。DO-178B/C的6.3.5节提出应该检查下列缺陷:

(1)编译器告警[2];

(2)硬件地址错误[1,2];

(3)软件部件遗漏[1,2];

(4)内存重叠[1,2];

考虑到目前软件开发过程一般会采用集成开发环境(IDE),因此,验证人员应该关注IDE提供的软件编译、链接和加载过程,要评审和分析编译器、链接器和加载器等的参数和默认配置。

2 与OCA活动的差异

由于对软硬件集成过程输出的评审和分析活动与OCA活动都涉及目标码,导致两者容易混淆,实际上两者差异很大。

软硬件集成过程输出的评审和分析活动的目标是确保该过程是完整的和正确的;活动针对 A、B和C级软件,关心编译器、链接器和加载器等的使用情况;对目标码来说,该活动考虑的是目标码文件中的各种符号(全局变量、函数等),并不考虑编译过程中生成的无法追溯到源代码的目标码;该活动的具体细节在后文讨论。

OCA活动的目标是确保编译生成的目标码序列的正确性;当软件是 A级、软件结构覆盖分析(SCA)在源代码级进行、且编译过程生成了无法追溯到源代码的目标码时,才需要进行OCA;该活动先识别出哪些目标码不能追溯到源代码,然后再通过附加验证来确认这些额外的目标码能够正确地运行、并且不会引入异常行为[4]。

下面先简要介绍机载软件开发常用的交叉编译工具 GCC,再结合国产机载嵌入式操作系统 TM2(它使用GCC 3.4.4工具链),详细讨论软硬件集成过程输出的评审和分析活动的7个子活动。

3 GCC 编译链接的基本过程

GCC是一套面向嵌入式领域的交叉编译工具,支持多种编程语言、多种优化选项、多种调试信息格式、多种反汇编方式、以及分步编译,支持X86、ARM7、StrongARM、PPC4XX、MPC8XX、MIPS R3000等多种CPU[5]。

GCC编译程序的基本过程见图1所示。首先,core-gcc根据输入文件的后缀来确定文件的类型,然后根据用户的编译选项(包括优化选项、调试信息选项等)将其编译成相应的汇编临时文件(后缀为.s);接着,dcore-as将该汇编文件编译成目标文件(后缀为.o);最后,dcore-ld根据用户的链接选项(包括指定链接命令文件等)将目标文件和各种库链接起来生成可执行文件[5]。

图1 GCC 编译链接的基本过程Fig.1 Basic process of the GCC compilation and link

4 解决方案

4.1 验证思路

从图1可以看出,在源代码到可执行码的转换过程中,交叉编译和汇编、交叉链接等步骤均可能引入错误[3]。但是,由于编译链接工具本身的复杂性,目前对它的完全验证还存在非常困难的技术问题[6];因此工程项目中通常不对编译链接工具做正确性假设,而是通过检查编译链接活动的输入与输出来确保该过程的完整性和正确性;对加载可执行码到目标机这个步骤的验证思路也是如此。换句话说,对软硬件集成过程输出的验证可以通过评审和分析软件编译信息、代码源文件、工程文件(MakeFile)、内存配置文件、目标文件、可执行文件等来进行。在这个活动中,主要应该检查下列7类缺陷,其中,前4类对应DO-178B/C适航标准,后3类是对前4类的补充,对后3类的要求大多来自于项目经验。

4.2 编译器告警

编译器输出的告警信息代表软件源代码在编译过程中出现了故障[3]。检查告警信息分下面两步。

第一步:设置编译器选项,输出所有告警信息,方法是:在 TM2开发环境中,选择“产生所有警告信息(-Wall)”;

第二步:重新构建 OS项目,人工分析所有构建输出信息,确认编译过程中不存在编译错误和告警信息;如果有告警信息,开发方应提供解释,验证方需判断解释是否合理;最好由开发方修改源代码以消除告警信息。

4.3 硬件地址错误

开发方提供硬件设备地址,验证方检查源代码中的硬件地址是否与开发方提供的一致;不一致的,开发方需要改成一致。

4.4 软件部件遗漏

软件部件的评审和分析用于确认各个源文件(*.c、*.h)不多不少的被编译成目标文件(*.o),又不多不少地被链接到可执行文件(*.elf、*.bin)中,主要检查下列内容:

(1)正确的源文件是否被包含在工程文件(MakeFile)中;

(2)源代码文件之间的依赖关系是否正确;

(3)所有源文件是否都生成目标文件;

(4)所有目标文件是否都连接到可执行文件中。

第1项检查方法:根据开发方提供的源文件列表,在 TM2开发环境中查看工程文件(例如:makefile、source.mk、v_makefile.mk等),检查源文件是否已经不多不少地包含在这些工程文件中。

第2项检查方法:在TM2开发环境的make/src目录中,查看subdir.mk文件,该文件中有进行编译的每个源文件对应的目录文件(*.d)和目标文件(*.o)的列表;根据 subdir.mk文件,依次查看每个.d文件,一个.d文件中列出了某个源文件编译时编译器使用的所有依赖文件;根据这个依赖文件列表,结合开发方提供的文件调用关系树和源文件中的#include语句,检查该源文件的依赖关系是否正确。

需要说明的是:

· *.d文件中的依赖文件列表有前后顺序,这是由C语言本身的要求决定的;

· 编译器自己使用的头文件,在源文件中会用#include语句列出,但在*.d文件中不会列出;

· 根据开发方提供的文件调用关系树,可以在代码审查时先检查一下文件依赖关系是否正确;

· 检查依赖关系时,依次查看源文件中的每个#include语句,并查看每个被包含文件内再次包含的文件,以此类推,类似于深度优先算法,这样就可以从源文件中的各个#include语句得到该源文件的完整的依赖文件列表;把这个列表和开发方提供的文件调用关系树、以及*.d文件中的依赖文件列表进行比较,三者应该一致。

第3项检查方法:根据开发方提供的源文件列表,检查源文件与目标文件是否一一对应。

第4项检查方法:在TM2开发环境中,查看工程文件 makefile,查找以“dcore-ld”开头的链接器命令。一个链接器命令后面包括有链接了的*.o文件,多个链接器命令之间没有直接关联,链接器工作时顺序执行这些命令。检查所有链接器命令,列出命令后面包括的所有*.o文件,这些*.o文件与第3项得到的目标文件列表应该一致。

4.5 内存重叠

4.5.1 段间重叠检查

检查开发方提供的内存分配表和编译器实际需要的各段的大小,要求分配的内存应大于或等于实际需要的内存,以此验证内存各个段之间是否重叠。

在 TM2开发环境中,查看配置项目下的configRecord.xml文件,里面有为项目“.text”、“.rodata”、“.data”和“.bss”等段分配的内存空间的大小,这个分配应该和开发方提供的内存分配表一致;项目目录下的catlinkcmds文件里面是编译器实际需要的各段的大小;检查这两个文件中各段的空间大小,验证各段之间是否重叠。

4.5.2 段内重叠检查

可执行文件中的地址,即链接后产生的地址,是加载到目标机的地址(绝对地址)。验证方通过反汇编的方法,列出可执行文件中各个符号(全局变量、函数等)的地址,检查一个段内各个符号的地址之间是否重叠。

TM2开发环境在链接后可以生成两种可执行文件:*.elf和*.bin。*.elf可以解析成文本文件,*.bin则只能是二进制文件;两者只是格式差异,内容是一致的。验证方可以从*.elf中抽出每个符号的一些信息,命令是:dcore-nm -s os.elf > osMap.txt;该命令从 os.elf文件中抽出数据并存到 osMap.txt文件中,其中的信息包括:符号名、类型、占用空间的大小(size)、起始地址、符号所在文件和行号等,见图2所示。验证方检查这些数据,判断一个段内各个符号的地址之间是否重叠。

需要说明的是:在TM2开发环境make目录下的map.txt文件(内存映像文件)中有更多有关符号的信息。

4.6 内存动态分配失控

验证方检查源代码中是否存在内存动态分配(例如malloc()语句)。如果没有内存动态分配,内存重叠的可能性较小;如果有内存动态分配,应检查是否对动态分配空间的大小进行了约束,或者释放了前面分配的内存空间(例如 free()语句);如果即没有约束,也没有释放,则可能在软件运行过程中出现内存重叠,这是不安全的。

需要说明的是:本项活动可以在代码审查时进行。

4.7 编译链接选项错误

开发方应该明确本项目的编译链接选项,验证方检查开发环境中的编译链接选项与开发方提供的是否一致;不一致的,开发方需要改成一致。

需要说明的是:

· 本项活动可以作为对软硬件集成过程输出的评审和分析活动的第一项子活动;

· 目前,还没有针对某一个编译器链接器各个选项在特定情况下是否适用的规范性或指导性文件,因此,这一步主要依据是开发方提供的编译链接选项,只要开发环境中的编译链接选项与其一致即可。

4.8 加载过程错误

加载过程检查可用于确认可执行文件被正确地加载到目标机中的正确位置,主要检查下列内容:

(1)加载器对加载的数据是否进行了有效性检查(例如CRC校验);

(2)可执行文件是否被加载到目标机的正确位置;

(3)无效的软件是否没有被加载到目标机;

(4)数据加载过程是否没有出现错误;

(5)数据加载后软件是否正常运行;

(6)加载的软件版本是否正确。

第1项检查方法:验证方了解加载过程,再判断是否有安全保证。TM2开发环境的加载过程是把可执行文件分解成若干包,然后与目标机上的常驻代理软件通信,一包一包地传到目标机上的特定地址;在此过程中,使用CRC校验保证通信正确。

需要说明的是:对于其他加载器,需要开发方或加载器提供方先说明加载器如何加载,以及加载时如何进行有效性检查,验证方再进行分析检查。

第2项检查方法:重新加载一次可执行文件,检查可执行文件的加载起始地址是否与开发方给出的起始地址一致。

第3项检查方法:在重新加载过程中,检查加载了的可执行文件是否与开发方给出的需要加载的文件一致。

第4项检查方法:在重新加载过程中,检查数据加载过程是否正常结束,没有出现错误。

第5项检查方法:加载完毕后,启动目标机,检查软件是否正常启动和运行。TM2加载到目标机、目标机启动后,能够传回版本信息和知识产权信息,并在宿主机端完整显示出来,就可以认为软件已经正常启动和运行。

需要说明的是,本项活动不需要运行测试用例,只要目标机上的软件能够正常启动,进入初始状态即可。

第6项检查方法:启动目标机,检查软件显示的版本信息是否与开发方提供的被测件版本信息一致。

如果上述6项检查均通过,表明软件可执行码加载到目标机过程是正确的;如果有某项检查没有通过,验证方应会同开发方再次验证。

4.9 小结

表1把上面7个子活动中开发方和验证方的工作进行了小结。

表1 开发方需要提供的信息和验证方检查的缺陷对应表Tab.1 Information afforded by developer anddefects checked by verifier

5 结束语

在机载嵌入式设备开发过程中,为了满足 DO-178B/C适航标准提出的、验证软硬件集成过程输出的要求,本文详细讨论了对编译器告警、硬件地址错误、软件部件遗漏、内存重叠、内存动态分配失控、编译链接选项错误、加载过程错误等7类缺陷的检查方法和注意事项。文中提到了国产机载嵌入式操作系统TM2,只是为了说明方便;实际上,只要使用了GCC交叉编译工具,不同项目在编译器、链接器和加载器的使用方面差别不大,均可参考本文讨论的方法进行软硬件集成过程输出的验证活动。

[1] RTCA/DO-178B Software Considerations in Airborne Systems and Equipment Certification[S]. 1992.

[2] RTCA/DO-178C Software Considerations in Airborne Systems and Equipment Certification[S]. 2011.

[3] 宫伟祥, 赵婳. 民用机载软件集成过程的技术研究[J]. 计算机系统应用, 2016, 25(7).

[4] 童岳威, 刘建方. 民用飞机A级别机载软件项目源代码到目标码追溯性分析研究[J]. 科技视界, 2016, 20.

[5] GNU工具用户手册[Z].

[6] 任建国. 适航认证中的目标码覆盖率分析工具VerOCode[J].航空制造技术, 2012, 22.

猜你喜欢

源文件编译器源代码
人工智能下复杂软件源代码缺陷精准校正
基于TXL的源代码插桩技术研究
基于相异编译器的安全计算机平台交叉编译环境设计
网络社区划分在软件质量问题分析中的应用
基于源文件可疑度的软件缺陷定位方法研究
软件源代码非公知性司法鉴定方法探析
LKJ基础数据源文件自动编制系统的研究
揭秘龙湖产品“源代码”
通用NC代码编译器的设计与实现
误写C源文件扩展名为CPP的危害