软件调试器奇怪现象——编译优化

一、问题:

一版软件编译完后,程序员都会用调试工具(UDE,Lauterbach等)把执行文件Hex,S19刷入控制器CPU,然后单步调试一下执行逻辑,这是最基本的测试方法。但有的时候会发现一些奇怪的现象:输入的条件与输出的结果逻辑上不相符。例如,图-1,变量ISO14229_len的值明明等于6,即红框中的条件成立,但是程序却执行到else里面的逻辑了。为什么呢?

二,分析:

第一问:会不会是高优先级任务干涉共有变量ISO14229_len造成的?如图-2所示,假设逻辑运行到断点之前条件判断的确小于2,在进入断点前的一刻,由于其它高优先级任务中断,把变量改成了6,从而造成这样的假象?对此,在红框条件判断的前面加一条语句,强制把ISO14229_len赋值等于6,并关中断。发现执行结果还是在会进入else里。可见不存在高优先级任务干涉共有变量ISO14229_len。

第二问:会不会是因为写完程序后为了快速测试,选择的是增量编译,导致生成可执行文件不正确?如图-3所示,M1,M2都引用了头文件A.h,但是只有A.h, M1.c发生了变更,增量编译仅更新M1.obj, M2.obj还是旧值。对此,首先删除了所有旧的.obj,然后Rebuild All,但是发现S19文件跟增量编译的结果一样。说明不是这个原因引起的。

第三问:会不会是编译器优化导致的?如图-4,设有两个函数Func_A(), Func_B()它们都会调用同一条语句Proc_X(1,2,3),对于该条语句,两个函数里编译器声称的汇编代码完全不一样。这样当全局变量Value_A == 1, Value_B != 2时,运行结果是执行JMP Proc_X断点就会返回到Func_A()的else里,给人的感觉是Func_A里的else成立了。实际上,这是一种假象!

三,验证:

实测结果,的确是编译器优化后导致的。打断点测试本例图-1中省去的逻辑被执行了,而且它里面的逻辑结构与图-4是相似的。

四,思考:

C语言虽然作为底层语言,但它实际是面向对象的,这个对象是编程者,测试者,及软件架构师。为了程序的可读性和较好的维护性,MISRA-C规则里禁止使用goto语句,这是很好的习惯,行业内大家都遵守。但是它带来的结果是C程序的规模迅速增大。如果C语言的每一句都生成汇编代码,那么最终生成的可执行文件也会迅速增大,对于只有几兆字节左右的程序存储空间来说随着软件规模的增大可能很快不够用了,另外时间上的执行效率也会降低,这显然是不现实的。所以好的编译器会尽可能的优化源C代码,一些优化规则,如:

1.只做了初始化的变量,常量全部被删除,最后在map文件里找不到地址。

2.只有赋值操作,没有读操作的变量全部被删除,最后在map文件里找不到地址。

3.逻辑和参数上完全一样的多处语句,只对一处生成一段汇编代码,其它几处全部用Jump跳转过去。

五,结论:

软件测试过程中如果发现逻辑执行顺序不对,并不是真正的不对,而是编译器优化后的假象。相信编译器不会出错,真有错误也只能是编程错误。熟悉一些编译优化规则有助于尽快查明问题原因。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180728G029V900?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券