絕大多數產品開發,軟件一般都會設計成 boot + app 的形式,這是方便后續軟件更新,否則更新會變成一個很麻煩的事情。
網上隨處可見的跳轉程序大概如下:
voidjump2app()
{
typedefvoid(*func_app_start)(void);
__disable_irq();
func_app_start app_start=(func_app_start)(*(__IOuint32_t*)(APP_START_ADDR+4));
__set_MSP(*(__IOuint32_t*)(APP_START_ADDR));//設置棧頂地址
app_start();
}
大多數情況下,該程序跳轉正常,但當你改變了編譯器優化級別時,可能直接就 hardfault 了。
此時你會莫名其妙,為什么???
從魚鷹18年接觸到 boot 知識以來,都覺得這樣的跳轉程序理所當然,并且也沒出現過問題,直到最近修改了優化級別,發現程序直接hardfault 了,根本沒跳轉到 app 中,才發現了這里隱藏的 bug。
調試發現,app_start 這個函數指針變成了異常值,但魚鷹查看0x08040000 處的內存空間值是正常的。那只能是代碼問題了。
因此結合匯編和在線調試,終于發現,執行__set_MSP 這條語句前app_start 的值是正常的,執行后,這個值就異常了。
再結合 C 語言關于棧、局部變量的知識,立刻就知道是因為重新設置棧頂地址,但匯編代碼不變,但是從新棧位置偏移取函數地址,因此跳轉失敗。
如:
新棧的位置,變量的值是未知的,用它進行跳轉,失敗是必然的。
但是為什么大部分情況下程序沒有問題呢?
這是因為跳轉程序很簡單,局部變量少,那么這個app_start 局部變量編譯器可能就不會從棧中分配,而直接用一個寄存器存儲數據,而寄存器是不受棧頂位置影響的,自然程序能跳轉了。
但我們不能讓程序運行正常與否由編譯器隨機決定,因此我們要避免這個 bug,讓程序不管在何種優化級別、函數多復雜的情況下,依然可以正常運行,因此還是有必要進行優化的。
最簡單的方法,就是把這個app_start 局部變量變成全局變量。這樣變量就不會受到棧頂位置影響,自然可以避免了。
如:
voidjump2app()
{
typedefvoid(*func_app_start)(void);
__disable_irq();
static func_app_start app_start=(func_app_start)(*(__IOuint32_t*)(APP_START_ADDR+4));
__set_MSP(*(__IOuint32_t*)(APP_START_ADDR));//設置棧頂地址
app_start();
}
如有更好的優化方法,歡迎留言討論。
-
寄存器
+關注
關注
31文章
5421瀏覽量
123292 -
函數
+關注
關注
3文章
4367瀏覽量
64160 -
變量
+關注
關注
0文章
614瀏覽量
28814
原文標題:本跳轉程序靠bug運行,請不要優化
文章出處:【微信號:emOsprey,微信公眾號:魚鷹談單片機】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
西門子S7-1200 PLC程序控制指令:跳轉與標簽指令
與單片機Bug戰斗的那些經歷
與單片機Bug戰斗的那些經歷
IAP程序跳轉到APP只能運行大約2秒
關于程序跳轉的問題如何解決
為了心愛的本本,請不要吸煙
---GD32F450---bootloader跳轉到app無法運行

KEIL上跳轉程序的起始地址(未完成)

STM32 IAP - Boot跳轉到APP

【單片機程序和RAM】程序在RAM中調試的運行方式&程序固化后運行方式

評論