C51軟復(fù)位分析
現(xiàn)單列復(fù)位部分如下:
main()
{
unsignedcharcoderst[]={0xe4,0xc0,0xe0,0xc0,0xe0,0x32};//復(fù)位代碼
(*((void(*)())(rst)))();//執(zhí)行上一行代碼,將rst數(shù)組當(dāng)函數(shù)調(diào)用
}
本來我告訴他嵌入如下代碼:
clra
pushacc
pushacc
reti
結(jié)果他卻玩了前面哪一段,而數(shù)組rst[]中的內(nèi)容恰恰是上面的匯編機器碼,他的做法是將
rst數(shù)組的數(shù)據(jù)當(dāng)作代碼保存,然后采用絕對地址方式指向該數(shù)組,將該數(shù)組中的代碼當(dāng)作
函數(shù)來運行。居然通過了!
我覺得有問題,我說即使如此,那絕對地址調(diào)用也應(yīng)該寫成(*((void(*)())(rst)))()
才對呀,結(jié)果他反駁說,那樣的話,rst的地址就會當(dāng)成參數(shù)傳遞給這個絕對地址函數(shù),而
實際LJMP調(diào)用的地址并非rst的地址,而是一個不確定的地址。于是我按照自己的說法嘗試
了一下,看看匯編結(jié)果,還真的是將rst的地址傳遞給了R1R2,而絕對函數(shù)最終LJMP到了
一個莫名其妙的地址上去了,死翹!
看來C真是一匹不容易駕馭的野馬,這個大三學(xué)生理解力在我之上,我30多歲的人了,干了
這么多年還沒他的境界呢,唉,人家才學(xué)了幾天啊,翻了幾天書就這么厲害了,服了!
首先分析帖子的C語言代碼
第一句定義一個數(shù)組rst[],數(shù)組內(nèi)數(shù)據(jù)就是完成復(fù)位功能的匯編機器碼,具體對應(yīng)關(guān)系
為:clra==0xe4、pushacc==0xc0,0xe0、reti==0x32
第二句是一個函數(shù)指針的用法,函數(shù)指針用法稍微有點復(fù)雜,可參看本人著的書,:),以
下為快速入門講解。
定義一個返回值是空函數(shù)指針的定義形式如下:
void(*p)()
當(dāng)把函數(shù)指針賦值后,就能通過函數(shù)指針調(diào)用函數(shù),調(diào)用形式如下,
(*p)();
或等價的簡化形式:
p();
假設(shè)rst就是函數(shù)指針,則如下調(diào)用形式就可以令單片機復(fù)位再起。
(*rst)();
但可惜,rst不是函數(shù)指針,而是數(shù)組名,雖然兩者都是地址,但不可直接調(diào)用數(shù)組名。
如同把char型變量a賦值給int型變量b,(int)表示強制類型轉(zhuǎn)換:
b=(int)a
函數(shù)指針的強制類型轉(zhuǎn)換公式如下(C語言的哲學(xué)是定義形式和使用一致):
((void(*)())rst
這樣經(jīng)過轉(zhuǎn)換后的rst就可以當(dāng)作函數(shù)指針使用了,簡單的調(diào)用形式如下:
#defineK((void(*)())rst
(*K)()
或:
(*(void(*)())rst)();
評論