絕大多數(shù)產(chǎn)品開(kāi)發(fā),軟件一般都會(huì)設(shè)計(jì)成 boot + app 的形式,這是方便后續(xù)軟件更新,否則更新會(huì)變成一個(gè)很麻煩的事情。
網(wǎng)上隨處可見(jiàn)的跳轉(zhuǎn)程序大概如下:
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));//設(shè)置棧頂?shù)刂?/span>
app_start();
}
大多數(shù)情況下,該程序跳轉(zhuǎn)正常,但當(dāng)你改變了編譯器優(yōu)化級(jí)別時(shí),可能直接就 hardfault 了。
此時(shí)你會(huì)莫名其妙,為什么???
從魚(yú)鷹18年接觸到 boot 知識(shí)以來(lái),都覺(jué)得這樣的跳轉(zhuǎn)程序理所當(dāng)然,并且也沒(méi)出現(xiàn)過(guò)問(wèn)題,直到最近修改了優(yōu)化級(jí)別,發(fā)現(xiàn)程序直接hardfault 了,根本沒(méi)跳轉(zhuǎn)到 app 中,才發(fā)現(xiàn)了這里隱藏的 bug。
調(diào)試發(fā)現(xiàn),app_start 這個(gè)函數(shù)指針變成了異常值,但魚(yú)鷹查看0x08040000 處的內(nèi)存空間值是正常的。那只能是代碼問(wèn)題了。
因此結(jié)合匯編和在線調(diào)試,終于發(fā)現(xiàn),執(zhí)行__set_MSP 這條語(yǔ)句前app_start 的值是正常的,執(zhí)行后,這個(gè)值就異常了。
再結(jié)合 C 語(yǔ)言關(guān)于棧、局部變量的知識(shí),立刻就知道是因?yàn)橹匦略O(shè)置棧頂?shù)刂罚珔R編代碼不變,但是從新棧位置偏移取函數(shù)地址,因此跳轉(zhuǎn)失敗。
如:
新棧的位置,變量的值是未知的,用它進(jìn)行跳轉(zhuǎn),失敗是必然的。
但是為什么大部分情況下程序沒(méi)有問(wèn)題呢?
這是因?yàn)樘D(zhuǎn)程序很簡(jiǎn)單,局部變量少,那么這個(gè)app_start 局部變量編譯器可能就不會(huì)從棧中分配,而直接用一個(gè)寄存器存儲(chǔ)數(shù)據(jù),而寄存器是不受棧頂位置影響的,自然程序能跳轉(zhuǎn)了。
但我們不能讓程序運(yùn)行正常與否由編譯器隨機(jī)決定,因此我們要避免這個(gè) bug,讓程序不管在何種優(yōu)化級(jí)別、函數(shù)多復(fù)雜的情況下,依然可以正常運(yùn)行,因此還是有必要進(jìn)行優(yōu)化的。
最簡(jiǎn)單的方法,就是把這個(gè)app_start 局部變量變成全局變量。這樣變量就不會(huì)受到棧頂位置影響,自然可以避免了。
如:
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));//設(shè)置棧頂?shù)刂?/span>
app_start();
}
如有更好的優(yōu)化方法,歡迎留言討論。
-
寄存器
+關(guān)注
關(guān)注
31文章
5401瀏覽量
122805 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4365瀏覽量
63870 -
變量
+關(guān)注
關(guān)注
0文章
614瀏覽量
28756
原文標(biāo)題:本跳轉(zhuǎn)程序靠bug運(yùn)行,請(qǐng)不要優(yōu)化
文章出處:【微信號(hào):emOsprey,微信公眾號(hào):魚(yú)鷹談單片機(jī)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
西門(mén)子S7-1200 PLC程序控制指令:跳轉(zhuǎn)與標(biāo)簽指令
與單片機(jī)Bug戰(zhàn)斗的那些經(jīng)歷
與單片機(jī)Bug戰(zhàn)斗的那些經(jīng)歷
IAP程序跳轉(zhuǎn)到APP只能運(yùn)行大約2秒
關(guān)于程序跳轉(zhuǎn)的問(wèn)題如何解決
為了心愛(ài)的本本,請(qǐng)不要吸煙
---GD32F450---bootloader跳轉(zhuǎn)到app無(wú)法運(yùn)行

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

STM32 IAP - Boot跳轉(zhuǎn)到APP

【單片機(jī)程序和RAM】程序在RAM中調(diào)試的運(yùn)行方式&程序固化后運(yùn)行方式

BL(B)和LDR跳轉(zhuǎn)范圍是如何規(guī)定的
PLC跳轉(zhuǎn)/標(biāo)號(hào)指令的工作原理及應(yīng)用舉例
SCL用GOTO語(yǔ)句執(zhí)行程序跳轉(zhuǎn)
PLC的條件跳轉(zhuǎn)、子程序調(diào)用等

評(píng)論