利用SPARK 95和GNORT对安全关键型应用进行再工程及Ada95在嵌入式安全关键应用认证中的解决方案
在当今科技领域,安全关键型应用的开发和认证至关重要。无论是航空航天、汽车工业还是其他对安全性要求极高的领域,软件的正确性和可靠性都直接关系到系统的稳定运行和人员安全。下面我们将探讨利用SPARK 95和GNORT对安全关键型应用进行再工程,以及Ada95在嵌入式安全关键应用认证中的解决方案。
1. 利用SPARK 95和GNORT对安全关键型应用进行再工程
在安全关键型应用的开发中,代码的生成和优化是关键环节。这里以SHOLIS系统为例,探讨GNORT在代码生成和优化方面相对于原Ada83编译器的改进。
1.1 代码生成与优化
由于SHOLIS目标硬件不可用,无法评估GNORT生成系统的性能。但从代码大小来看,不同编译器和优化级别下的代码和数据大小存在差异,具体如下表所示:
| 编译器 | 代码(字节) | 数据(字节) | 总计(字节) |
| ---- | ---- | ---- | ---- |
| Alsys | 174066 | 78878 | 252944 |
| GNORT -O0 | 202412 | 71052 | 273464 |
| GNORT -O1 | 138280 | 71052 | 209332 |
| GNORT -O2 | 135192 | 71052 | 206244 |
从表中可以看出,GNORT优化级别0生成的代码比Alsys多约27k,这是因为关闭优化时,GNAT能实现完全不优化的目标。而在更高的优化级别下,GNORT表现更好。例如,在级别1时,GCC后端会进行公共子表达式消除、尽可能将变量分配到寄存器以及消除许多冗余的加载和存储操作,代码通常更短,对主内存的引用也显著减少。虽然无法在真实的SHOLIS硬件上测量执行时间,但手动分析几个时间关键的内循环表明,GNORT代码的性能会优于原系统。
1.2 GNORT利用SPARK的能力
SPARK强制执行若干静态语义规则,如无函数副作用、无异常、初始化表达式的静态性等。如果编译器能识别这些程序属性,可能会改进代码生成。具体表现如下:
-
异常处理
:SHOLIS被证明没有所有预定义异常。GNORT允许引发异常,但总是跳转到单个用户定义的例程,可用于终止或重启程序。在像SHOLIS这样完全无异常的程序中,GNORT不会产生不必要的处理程序或表,也不会对子程序的进入/退出序列产生开销。而Alsys编译器虽然对未使用的异常不产生运行时开销,但在最终程序映像中仍会生成6095字节的异常处理表,这些表从未被使用。
-
静态性
:在SPARK程序中,约束总是静态的,初始化常量的表达式在编译时总是可确定的。GNORT在这方面表现出色,大多数情况下,即使Ada95对“静态”的定义不要求,它也能在编译时计算初始化表达式。
-
函数副作用
:SPARK消除了所有函数副作用,这为改进代码生成提供了可能。Pragma Pure是一种实现方法,在SHOLIS的一小部分包中成功应用。GNORT还提供了一个实现定义的Pragma Pure Function,但实验表明,在生成的代码中没有明显的改进,可能是相关算法不适合这种改进。
-
优化
:在安全关键领域,“不优化”似乎是常态,原因包括早期Ada83实现中优化器的不可靠性以及调试和审查优化后目标代码的困难。但GNORT基于GCC后端,通常启用优化器。如果关注目标代码的完整性,可以采取以下三种方法:
- 使用经过形式验证的编译器。
- 审查编译器的使用历史和可靠性。
- 手动审查生成的代码。
对于GNORT(以及其他基于GCC的编译器),非正式证据表明 -O1是最可靠的选项,因为大多数用户通常使用此选项。此外,手动审查目标代码对于某些安全关键系统仍然是必要但艰巨的任务。通过比较Alsys编译器和GNORT在优化级别0和1生成的代码,发现GNORT在优化级别0时生成的代码与Alsys编译器生成的代码一样易于理解,甚至更好;在级别1时,虽然代码解释稍微复杂一些,但代码体积的减少平衡了这种难度,并且GCC优化器在 -O1时不会对代码进行全局重组,不会过度增加验证的复杂性。另外,GNAT通过前端的中间语言(IL)提供了一种其他编译系统所没有的验证级别,这为目标代码的验证提供了两步验证的可能性,有助于减轻验证负担。
2. 进一步工作
2.1 GNORT
GNORT提供的功能基本满足SHOLIS的要求,但存在一个技术问题,即地址子句不能写在预可详细说明的单元中。为了解决这个问题,建议添加一个新的实现定义属性:
for X’Address use Address’Value (...);
这个特殊属性将具有与To Address相同的语义,但将是一个静态属性,因此允许在预可详细说明的单元中使用。未来可能会出现类似情况,需要在额外内联或特殊属性方面进行一些小的工作。
2.2 SHOLIS
SHOLIS本身尚未利用SPARK 95允许的子包。引入子包意味着要重新思考程序的结构,这超出了本次研究的范围,因此这是未来的工作方向。此外,SHOLIS仍然是一个完全单任务的程序,采用循环调度器。虽然这种方法在简单性和效率方面有一些优点,但也有严重的缺点,例如程序结构会受到破坏以适应可用的系统周期,并且难以满足一些实时要求。一个明显的改进方向是使用Ravenscar任务配置文件对SHOLIS进行重新设计。
3. Ada95在嵌入式安全关键应用认证中的解决方案
随着软件在安全关键系统中的使用不断增加,对软件正确性和可靠性的要求也越来越高。Ada95编程语言广泛用于嵌入式安全关键的机载系统和设备的实现,而RTCA/DO - 178B是通过测试认证此类系统和设备的成熟标准。DDC - I计划通过其新的SCORE编译器/调试器产品线和相关测试工具产品,为Ada95应用的RTCA/DO - 178B级别A认证提供解决方案。
3.1 DDC - I认证工具
DDC - I的软件开发工具旨在为软件开发人员提供一套支持嵌入式实时安全关键应用开发和认证的实用工具和功能。这些工具和功能相互补充,解决软件认证的不同问题。
-
Ada95 Annex H的实现
:Ada95核心语言具有许多适合开发安全可靠软件的特性,如强类型系统、指针初始化、广泛的运行时检查、健壮的异常机制、抽象数据类型和包等。Annex H在此基础上增加了一些新特性,主要包括理解程序执行、审查目标代码和限制某些语言特性的使用。DDC - I的SCORE Ada95编译器将全面实现Annex H。
-
理解程序执行
:Annex H通过pragma
2SVQEPM^IC7GEPEVW
和记录实现决策来支持对程序执行的理解。使用该pragma会强制所有未初始化的标量初始分配一个可预测的值,如果可能,会分配一个无效值。例如,对于某些变量的声明,不同类型的变量会被分配不同的初始值,这种策略有助于发现与未初始化变量相关的常见错误,因为分配无效值通常会导致范围检查失败并在运行时引发异常。
-
可审查的目标代码
:Annex H提供了两个pragma(
6IZMI[EFPI
和
-RWTIGXMSRC4SMRX
)来辅助审查目标代码。
6IZMI[EFPI
提供两个单独的列表,一个是带有与目标代码相关信息注释的源代码列表,另一个是带有源代码引用的目标代码列表。通过这些列表,可以清晰地看到变量在寄存器中的分配情况以及条件语句的实现方式。
-RWTIGXMSRC4SMRX
可以看作是一种高级断点,它提供了从所有可检查对象到其值位置的映射,通过基于DWARF调试信息生成列表来支持该pragma。
-
限制某些语言特性的使用
:可以使用特殊的Annex H配置pragma
6IWXVMGXMSRW
来限制某些语言特性的使用。编译器会检测明显的违规情况,例如当
2SC)\GITXMSRW
生效时,编译器会检查是否存在raise语句和异常处理程序。这些限制可以用于编译器进行一些优化和简化,例如DDC - I的Ada95编译器可以根据生效的限制选择专门的运行时系统,从而减少代码大小、提高性能并简化代码,便于认证。
综上所述,利用SPARK 95和GNORT对安全关键型应用进行再工程以及DDC - I提供的Ada95应用认证解决方案,为安全关键型应用的开发和认证提供了有效的方法和工具。在未来的工作中,不断完善这些技术和工具,将有助于提高安全关键型应用的质量和可靠性。
利用SPARK 95和GNORT对安全关键型应用进行再工程及Ada95在嵌入式安全关键应用认证中的解决方案
3.2 具体工具示例及效果
为了更直观地展示DDC - I认证工具的效果,下面结合具体的代码示例进行说明。
3.2.1 理解程序执行示例
考虑以下代码片段:
-- 变量声明
variable % : Integer;
variable & : Integer;
variable ' : Integer;
variable ( : Float;
-- 应用 pragma 2SVQEPM^IC7GEPEVW 后的初始化情况
-- 变量 % 会被赋值为
-- 变量 & 会被赋值为
-- 变量 ' 会被赋值为十六进制数 ()%(()%( 代表的位模式
-- 变量 ( 会被赋值为代表非数字值的位模式
当程序执行时,如果使用了未正确初始化的变量,由于赋予的是无效值,很可能会触发范围检查失败并抛出异常。例如,在一个阶乘程序中,如果传入未正确初始化的参数,就会出现这种情况:
-- 阶乘程序
function Factorial (N : Integer) return Integer is
Result : Integer := 1;
begin
for I in 1..N loop
Result := Result * I;
end loop;
return Result;
end Factorial;
-- 调用阶乘程序,传入未正确初始化的参数 2
-- 由于使用了 pragma 2SVQEPM^IC7GEPEVW,可能会触发异常
通过这种方式,能够方便地发现与未初始化变量相关的错误。
3.2.2 可审查的目标代码示例
以下是一个简单的Ada程序:
procedure Example is
A : Integer := 10;
B : Integer := 20;
C : Integer;
begin
C := A + B;
end Example;
使用
pragma 6IZMI[EFPI
后,生成的源代码列表会包含编译器生成的标量初始化、运行时检查、隐式调用的运行时支持例程等信息。例如,会显示变量
A
和
B
的初始化值,以及加法运算的运行时检查情况。目标代码列表则会显示与源代码的对应关系,比如寄存器的分配情况:
A
可能被分配到寄存器
M
,
B
被分配到寄存器
M
,
C
的计算结果也会在相应的寄存器操作中体现。
使用
pragma -RWTIGXMSRC4SMRX
时,会基于DWARF调试信息生成列表,提供从可检查对象到其值位置的映射,方便审查目标代码。
3.2.3 限制语言特性使用示例
假设我们使用
pragma 6IWXVMGXMSRW
并指定
2SC)\GITXMSRW
限制:
-- 应用 pragma 6IWXVMGXMSRW 限制异常使用
pragma 6IWXVMGXMSRW (2SC)\GITXMSRW);
procedure NoExceptionExample is
A : Integer := 10;
B : Integer := 20;
C : Integer;
begin
-- 这里如果有 raise 语句,编译器会检测到违规
C := A + B;
end NoExceptionExample;
编译器会检查代码中是否存在
raise
语句和异常处理程序,如果存在则会报错。同时,编译器可以根据这个限制选择专门的运行时系统,如非任务型变体,从而减少代码大小、提高性能并简化代码。
4. 总结与展望
通过上述对利用SPARK 95和GNORT对安全关键型应用进行再工程以及Ada95在嵌入式安全关键应用认证中的解决方案的探讨,可以得出以下结论:
- GNORT为安全关键型应用的开发提供了一种可用且有效的方式,相较于传统的“小型但经过认证”的运行时,具有成本效益。
- 谨慎使用SPARK 95的特性可以在现有的SPARK 83应用中实现可衡量的改进,且所需工作量相对较少。
- 关闭优化时,GNORT生成的代码比原Ada83编译器略大,但更适合调试和手动审查;启用优化后,在代码大小和性能方面有显著优势,且不会过度影响目标代码的可理解性。
- GNORT对目标代码审查的支持至少与原编译器相当,还提供了基于中间语言的两阶段审查过程,其开源的特性使得这种审查方式成为可能。
- DDC - I的SCORE编译器/调试器产品线和相关测试工具产品为Ada95应用的RTCA/DO - 178B级别A认证提供了有效的解决方案,通过实现Annex H和提供专用测试工具,能够满足嵌入式安全关键应用开发和认证的需求。
未来,在安全关键型应用的开发和认证领域,还有许多工作可以进一步开展:
- 对于GNORT,需要解决地址子句不能写在预可详细说明单元中的问题,并在额外内联或特殊属性方面进行优化,以更好地适应不同的应用场景。
- 对于SHOLIS系统,可以引入子包来重新设计程序结构,使用Ravenscar任务配置文件改进单任务循环调度器的不足,以满足更多实时要求。
- 对于DDC - I的认证工具,可以进一步完善其功能,提高对复杂应用的支持能力,同时加强与其他开发工具和流程的集成,提高开发效率和认证的准确性。
总之,随着技术的不断发展,安全关键型应用的开发和认证将不断完善,为各个领域的安全稳定运行提供更可靠的保障。
下面是一个简单的mermaid流程图,展示了利用GNORT进行代码生成和优化的大致流程:
graph TD;
A[原始代码] --> B[提交到GNORT];
B --> C{选择优化级别};
C -->|O0| D[生成代码(未优化)];
C -->|O1| E[进行公共子表达式消除等优化];
C -->|O2| F[进一步优化];
E --> G[生成优化后代码];
F --> G;
D --> H[代码审查和分析];
G --> H;
H --> I[评估性能和代码大小];
同时,为了更清晰地对比不同编译器和优化级别下的代码情况,再次列出之前的表格:
| 编译器 | 代码(字节) | 数据(字节) | 总计(字节) |
| ---- | ---- | ---- | ---- |
| Alsys | 174066 | 78878 | 252944 |
| GNORT -O0 | 202412 | 71052 | 273464 |
| GNORT -O1 | 138280 | 71052 | 209332 |
| GNORT -O2 | 135192 | 71052 | 206244 |
这些信息有助于开发者在实际应用中根据需求选择合适的编译器和优化级别。