• 正文
  • 相關(guān)推薦
申請入駐 產(chǎn)業(yè)圖譜

本跳轉(zhuǎn)程序靠bug運行,請不要優(yōu)化

01/27 10:45 來源:公眾號【魚鷹談單片機】
648
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

絕大多數(shù)產(chǎn)品開發(fā),軟件一般都會設計成 boot + app 的形式,這是方便后續(xù)軟件更新,否則更新會變成一個很麻煩的事情。

網(wǎng)上隨處可見的跳轉(zhuǎn)程序大概如下:

#define APP_START_ADDR          0x08040000 
void?jump2app(){??typedef?void?(*func_app_start)(void);   ??__disable_irq();????func_app_start app_start?=?(func_app_start)?(*(__IO??uint32_t*)?(APP_START_ADDR?+?4));  ??__set_MSP(*(__IO??uint32_t*)?(APP_START_ADDR));//?設置棧頂?shù)刂?/code>
??app_start();}

大多數(shù)情況下,該程序跳轉(zhuǎn)正常,但當你改變了編譯器優(yōu)化級別時,可能直接就 hardfault 了。

此時你會莫名其妙,為什么???

從魚鷹18年接觸到 boot 知識以來,都覺得這樣的跳轉(zhuǎn)程序理所當然,并且也沒出現(xiàn)過問題,直到最近修改了優(yōu)化級別,發(fā)現(xiàn)程序直接hardfault 了,根本沒跳轉(zhuǎn)到 app 中,才發(fā)現(xiàn)了這里隱藏的 bug。

調(diào)試發(fā)現(xiàn),app_start 這個函數(shù)指針變成了異常值,但魚鷹查看?0x08040000 ?處的內(nèi)存空間值是正常的。那只能是代碼問題了。

因此結(jié)合匯編和在線調(diào)試,終于發(fā)現(xiàn),執(zhí)行?__set_MSP 這條語句前?app_start 的值是正常的,執(zhí)行后,這個值就異常了。

再結(jié)合 C 語言關(guān)于棧、局部變量的知識,立刻就知道是因為重新設置棧頂?shù)刂?,但匯編代碼不變,但是從新棧位置偏移取函數(shù)地址,因此跳轉(zhuǎn)失敗。

如:

新棧的位置,變量的值是未知的,用它進行跳轉(zhuǎn),失敗是必然的。

但是為什么大部分情況下程序沒有問題呢?

這是因為跳轉(zhuǎn)程序很簡單,局部變量少,那么這個?app_start 局部變量編譯器可能就不會從棧中分配,而直接用一個寄存器存儲數(shù)據(jù),而寄存器是不受棧頂位置影響的,自然程序能跳轉(zhuǎn)了。

但我們不能讓程序運行正常與否由編譯器隨機決定,因此我們要避免這個 bug,讓程序不管在何種優(yōu)化級別、函數(shù)多復雜的情況下,依然可以正常運行,因此還是有必要進行優(yōu)化的。

最簡單的方法,就是把這個?app_start 局部變量變成全局變量。這樣變量就不會受到棧頂位置影響,自然可以避免了。

如:

#define APP_START_ADDR          0x08040000 
void?jump2app(){??typedef?void?(*func_app_start)(void);   ??__disable_irq();????static func_app_start app_start?=?(func_app_start)?(*(__IO??uint32_t*)?(APP_START_ADDR?+?4));  ??__set_MSP(*(__IO??uint32_t*)?(APP_START_ADDR));//?設置棧頂?shù)刂?/code>
??app_start();}

如有更好的優(yōu)化方法,歡迎留言討論。

相關(guān)推薦

登錄即可解鎖
  • 海量技術(shù)文章
  • 設計資源下載
  • 產(chǎn)業(yè)鏈客戶資源
  • 寫文章/發(fā)需求
立即登錄