c51軟復位,經典,分析透徹
........注:轉貼...........
從單片機指針說到黑客程序
2004年7月的一天,在電子BBS討論區上溜達,看到一個有趣的帖子,整個帖子內容如下:
純C51復位功能函數:一個大三學生,讓人又愛又怕
現單列復位部分如下:
main()
{
?? unsigned char code rst[]={0xe4,0xc0,0xe0,0xc0,0xe0,0x32};??// 復位代碼
?? (*((void (*)())(rst)))();??// 執行上一行代碼,將rst數組當函數調用
}
本來我告訴他嵌入如下代碼:
clr a
push acc
push acc
reti
結果他卻玩了前面哪一段,而數組rst[]中的內容恰恰是上面的匯編機器碼,他的做法是將
rst數組的數據當作代碼保存,然后采用絕對地址方式指向該數組,將該數組中的代碼當作
函數來運行。居然通過了!
我覺得有問題,我說即使如此,那絕對地址調用也應該寫成(*((void (*)())(&rst)))()
才對呀,結果他反駁說,那樣的話,rst的地址就會當成參數傳遞給這個絕對地址函數,而
實際LJMP調用的地址并非rst的地址,而是一個不確定的地址。于是我按照自己的說法嘗試
了一下,看看匯編結果,還真的是將rst的地址傳遞給了R1 R2,而絕對函數最終LJMP到了
一個莫名其妙的地址上去了,死翹!
看來C真是一匹不容易駕馭的野馬,這個大三學生理解力在我之上,我30多歲的人了,干了
這么多年還沒他的境界呢,唉,人家才學了幾天啊,翻了幾天書就這么厲害了,服了
定義一個返回值是空函數指針的定義形式如下:
void (*p) ( )
當把函數指針賦值后,就能通過函數指針調用函數,調用形式如下,
??????(*p) ( );
或等價的簡化形式:
p ( );
假設rst就是函數指針,則如下調用形式就可以令單片機復位再起。
(*rst ) ( );??
但可惜,rst不是函數指針,而是數組名,雖然兩者都是地址,但不可直接調用數組名。
如同把char型變量a賦值給int型變量b,(int) 表示強制類型轉換:
b = (int) a
函數指針的強制類型轉換公式如下(C語言的哲學是定義形式和使用一致):
(??(void (*)()??) rst
這樣經過轉換后的rst就可以當作函數指針使用了,簡單的調用形式如下:
#define??K???? (??(void (*)( )??) rst
(*K) ( )
或:
(???? * (??void (*)( )??)rst??????) ( );
這樣的語句就完成復位再啟功能了。類型轉換符()的優先級跟指針運算符*的優先級相同,
二者的結合方向是自右至左,所以上述語句就能完成復位功能了。保險起見有些程序員常
常喜歡再加個括號:
#define??K???? (?? (??(void (*)( )??) rst?? )
(*K) ( )
或
(???? *(?? (??void (*)( )??)rst?? )????) ( );
posted on 2006-10-26 20:33
天性如此 閱讀(129)
評論(0) 編輯 收藏 引用