昨天有位同學(xué)看了我之前的這個(gè)帖子:【STM32F303開發(fā)】+如何找到導(dǎo)致程序出現(xiàn)HardFault的代碼 后在社區(qū)群里說他也遇到了這個(gè)問題,但是他不太清楚那個(gè)帖子最后的那個(gè)圖片的中的有2個(gè)LR的值哪個(gè)才是有用的,該使用哪個(gè)LR的值去找跑飛的代碼。我告訴他是debug viewer中輸出的那個(gè),他好像還是不太明白,下面我們就簡(jiǎn)單的看下LR的變化過程。他說的那個(gè)圖片如下,其中包含了2個(gè)LR,左邊一個(gè)寄存器R14的值,右邊debug viewer輸出一個(gè)。 我們通常說的LR寄存器就是寄存器R14,它常用于在調(diào)用子程序分支時(shí)存儲(chǔ)返回地址,調(diào)用完成后用于返回到調(diào)用之前的地方繼續(xù)執(zhí)行下面的代碼, 《Cortex-M3 權(quán)威指南》對(duì)LR的描述如下,其中提到了LR的地址等于當(dāng)前子程序分支的下一條指令的地址。 我們知道當(dāng)程序發(fā)生異常或者中斷時(shí)會(huì)自動(dòng)保存現(xiàn)場(chǎng)將xPSR,PC,LR,以及R0-R3由硬件自動(dòng)壓入堆棧以及一些其他的處理,然后程序進(jìn)入異常或者中斷函數(shù),此時(shí)LR的值將會(huì)被自動(dòng)被更新為特殊的EXC_RETURN.《Cortex-M3 權(quán)威指南》里的詳細(xì)的介紹如下: 下面我們根據(jù)上面的敘述結(jié)合實(shí)際的代碼看下LR的值的變化過程: 1)我們?cè)诋惓:瘮?shù)void HardFault_Handler(void)里面設(shè)置一個(gè)斷點(diǎn)后debug下全速運(yùn)行,這個(gè)函數(shù)是重載的系統(tǒng)的函數(shù),當(dāng)出現(xiàn)HardFault時(shí)會(huì)自動(dòng)進(jìn)入這個(gè)函數(shù),可以看到此時(shí)的LR=0XFFFFFFF9,且此時(shí)處于Handler模式,和上面的描述相符。在這個(gè)函數(shù)里面首先判斷是使用的MSP還是SPS,然后將這個(gè)SP的值保存到r0寄存器,然后調(diào)用函數(shù)void Hard_Fault_Handler(uint32_t stack[]),此時(shí)的r0,作為函數(shù)Hard_Fault_Handler的參數(shù)。 下面我們進(jìn)入到void Hard_Fault_Handler(uint32_t stack[]),具體如下,主要是打印一些信息出來,我們?cè)谙旅娴暮瘮?shù)里設(shè)置一個(gè)斷點(diǎn),然后進(jìn)入到下面的函數(shù)中去
程序在進(jìn)入函數(shù)時(shí)把r0的值傳給了r4,用于保存參數(shù)的值,因?yàn)橄旅嬉玫絩0. 繼續(xù)看下面的匯編。將要輸出的字符的地址傳到r0保存,我們可以在內(nèi)存中看到地址0x08000818中保存的就是要輸出的字符串'In Hard Fault Handler\n',同時(shí)也可以在我們上次得到的反匯編文件中看到這個(gè)FLASH地址保存的輸出字符。 反匯編中得到保存的輸出字符的位置,具體參考:【STM32F303開發(fā)】+使用fromelf反匯編keil生成的AXF文件 保存好參數(shù)r0后程序會(huì)跳轉(zhuǎn)到輸出函數(shù)的地址0x08002080繼續(xù)執(zhí)行,注意輸出字符串函數(shù)下面的一條語句的地址為0x080006c6,這個(gè)地址將會(huì)在程序跳轉(zhuǎn)到輸出函數(shù)時(shí)被保存在LR中,此時(shí)的LR的值將會(huì)發(fā)生變化。在0x08002080設(shè)置個(gè)斷點(diǎn),然后全速運(yùn)行程序,程序會(huì)暫停在輸出函數(shù)。 從下圖中可以看到LR的值從進(jìn)入中斷函數(shù)時(shí)的0xFFFFFFF9變成了0x080006c7(指令最低bit0必須為1),這個(gè)值正好是我們跳轉(zhuǎn)前的下一句代碼的地址0x080006c6. 綜上,進(jìn)入中斷函數(shù)時(shí)的LR為特殊的EXC_RETURN,但是如果在中斷函數(shù)中有發(fā)生子程序分支調(diào)用時(shí),LR的值就會(huì)被壓棧,然后發(fā)生變化用于存儲(chǔ)子程序的返回地址。而我們用于保存跑飛代碼的LR的值一直在保存著并沒有發(fā)生變化,最后在debug viewer輸出的正是我們要找的LR的值。 |
|