power平台访问全局变量出现signal11

来源:互联网 发布:淘宝情趣用品保密吗 编辑:程序博客网 时间:2024/06/16 01:35

最近,遇到一个进程crash的CR(跑十来个小时才会crash,且每次都在同一个点crash)。crash本是很正常的事情,但是这次crash却让我莫名其妙,crash的点代码如下:

ALA_BpdDstore[0] = ((BT_UPM<<8)|(BT_CEI_PUSCH_Decode<<16)|1);  //ALA_BpdDstore[]是一个全局数组,右操作数全是宏。

你告诉我访问一个全局符号如何会产生signal11?

扫了眼出事函数的汇编(r24用来保存这个全局符号的地址):

3f 00 10 fc         lis     r24,4348            //给r24寄存器赋值0x10fcxxxx
3b 18 07 a4      addi    r24,r24,1956          //给r24寄存器赋值0x10fc07a4


90 f8 00 00     stw     r7,0(r24)           //访问r24寄存器,程序在此crash

看到了吧?先把0x10fc07a4赋值给r24寄存器,然后通过r24访问内存。0x10fc07a4是一个合法的.data段地址,访问一个合法的地址怎么会出现signal11呢?

但是,平台log直接表明crash时寄存器被踩!crash时r24的值为0x00170017,而且后面连着几个寄存器的值都为0x00170017:

......

GPR24 = 00170017   GPR25 = 00170017   GPR26 = 00170017   GPR27 = 00170017

......

于是,重新研究这个函数和汇编,最后终于得出root cause。先奉上函数框架:

void CEI_PUSCH_Decode(void *Msg, u32 length, u32 airNum)

{//crash函数

    ......

    for(msg3Idx = 0; msg3Idx < MAX_NB_MSG3; ++msg3Idx)

    {

        ......

        TL_GetULCrnti(){//这里面有一串子函数调用,大约四层}

        ......

        ALA_BpdDstore[0] = ((BT_UPM<<8)|(BT_CEI_PUSCH_Decode<<16)|1);  //crash语句

        ......

     }

     ......

}

再结合该函数的汇编来看,给r24赋值以及访问[r24]之间隔了很多条汇编指令,于是猜想gcc做了优化,循环之前对r24进行一次性赋值,后面每次访问[r24]的时候直接取其内容!

上面一串子函数调用如下:

TL_GetULCrnti() ==> MAC_RLC_UL_GetCrnti() ==> FSO_SBL2_MAC_RLC_UL_GetCrnti==>FSO_SBL2_MACUL_GetCrntiFromDeMuxProcess()

挨个观察他们的汇编,其中发现MAC_RLC_UL_GetCrnti()函数中有如下保存、恢复寄存器的汇编指令:

93 01 00 40 stw     r24,64(r1)             //保存r24到栈帧
93 21 00 44 stw     r25,68(r1)
93 41 00 48 stw     r26,72(r1)
....
83 01 00 a0      lwz     r24,160(r1)           //从栈帧上恢复r24
83 21 00 a4      lwz     r25,164(r1)
83 41 00 a8      lwz     r26,168(r1)
....

于是,发现问题所在:很可能这一串调用过程中栈帧被踩,导致恢复寄存器r24~r26时出错!

但是问题来了,谁会踩这个函数的栈帧?由于栈生长方向向上,所以应该是被子函数踩了(最后一子函数,有一个局部数组,我们的代码的确存在越界风险)。

那么接着问题又来了,子函数栈帧往上一路踩啊踩,怎么没把链接寄存器(lr)给踩了呢?从汇编中找到了答案:最后一个函数不涉及子函数调用,不用保存链接寄存器,而倒数第二个函数非常短小,汇编代码被优化为区区两行,基本就一条跳转指令。

最后,把最后一个子函数FSO_SBL2_MACUL_GetCrntiFromDeMuxProcess()中数组越界加上保护,signal11果然不再出现。

0 0
原创粉丝点击