免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
c51軟復(fù)位經(jīng)典分析

c51軟復(fù)位經(jīng)典分析



  在電子BBS討論區(qū)上溜達(dá),看到一個有趣的帖子,整個帖子內(nèi)容如下:
  純C51復(fù)位功能函數(shù):一個大三學(xué)生,讓人又愛又怕

  現(xiàn)單列復(fù)位部分如下:

main()
{
   unsigned char code rst[]={0xe4,0xc0,0xe0,0xc0,0xe0,0x32};  // 復(fù)位代碼
  (*((void (*)())(rst)))();  // 執(zhí)行上一行代碼,將rst數(shù)組當(dāng)函數(shù)調(diào)用
}

本來我告訴他嵌入如下代碼:
clr a
push acc
push acc
reti

  結(jié)果他卻玩了前面哪一段,而數(shù)組rst[]中的內(nèi)容恰恰是上面的匯編機(jī)器碼,他的做法是將rst數(shù)組的數(shù)據(jù)當(dāng)作代碼保存,然后采用絕對地址方式指向該數(shù)組,將該數(shù)組中的代碼當(dāng)作函數(shù)來運(yùn)行。居然通過了!

  我覺得有問題,我說即使如此,那絕對地址調(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é)了幾天啊,翻了幾天書就這么厲害了,服了!

l 首先分析帖子的C語言代碼
  第一句定義一個數(shù)組rst[],數(shù)組內(nèi)數(shù)據(jù)就是完成復(fù)位功能的匯編機(jī)器碼,具體對應(yīng)關(guān)系
為:clr a == 0xe4、push acc == 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)用形式就可以令單片機(jī)復(fù)位再起。
   (*rst ) ( );   
但可惜,rst不是函數(shù)指針,而是數(shù)組名,雖然兩者都是地址,但不可直接調(diào)用數(shù)組名。
如同把char型變量a賦值給int型變量b,(int) 表示強(qiáng)制類型轉(zhuǎn)換:
   b = (int) a
函數(shù)指針的強(qiáng)制類型轉(zhuǎn)換公式如下(C語言的哲學(xué)是定義形式和使用一致):
   (  (void (*)()  ) rst  
這樣經(jīng)過轉(zhuǎn)換后的rst就可以當(dāng)作函數(shù)指針使用了,簡單的調(diào)用形式如下:
#define  K     (  (void (*)( )  ) rst
  (*K) ( )
或:
  (     * (  void (*)( )  )rst      ) ( );
這樣的語句就完成復(fù)位再啟功能了。類型轉(zhuǎn)換符()的優(yōu)先級跟指針運(yùn)算符*的優(yōu)先級相同,
二者的結(jié)合方向是自右至左,所以上述語句就能完成復(fù)位功能了。保險起見有些程序員常
常喜歡再加個括號:
#define  K     (   (  (void (*)( )  ) rst   )
  (*K) ( )

  (     *(   (  void (*)( )  )rst   )    ) ( );

由于沒有輸入?yún)?shù),上述復(fù)位代碼更嚴(yán)謹(jǐn)?shù)膶懛ㄊ牵?nbsp; 
#define  K     (   (  (void (*)(void )  ) rst   )
  (*K) ( )

  (     *(   (  void (*)(void )  )rst   )    ) ( );

關(guān)于帖子作者的解釋
  千萬不要犯“&rst”形式的錯誤,對于一維數(shù)組而言,數(shù)組名rst就代表地址。以下二者等
價,更常用的是等式左邊的形式:
  rst == &rst[0]
  整個函數(shù)指針無所謂參數(shù)傳遞,只是把rst當(dāng)作程序執(zhí)行地址調(diào)用而已,那個學(xué)生的解釋也
有問題。
  還有一點必須提及,不是說能通過編譯,甚至生成正確代碼,就表示某語句一定是對的。
對很復(fù)雜的語句,要考慮到編譯器不嚴(yán)格甚至出錯的可能性。

  哈佛結(jié)構(gòu)和一個蠕蟲病毒
  請注意,定義數(shù)組rst[]時用了關(guān)鍵字code,這是C51特有的關(guān)鍵字,意味著把數(shù)組定義到程序空間。標(biāo)準(zhǔn)C是沒有關(guān)鍵字code的。

  哈佛結(jié)構(gòu)和普林斯頓結(jié)構(gòu):
哈佛結(jié)構(gòu)——程序空間和存儲空間分開的。C51算是不太嚴(yán)格的哈佛結(jié)構(gòu)——雖地址線分開,但數(shù)據(jù)線沒有分開。DSP是增強(qiáng)的哈佛結(jié)構(gòu)。
  PC電腦上奔騰CPU是普林斯頓結(jié)構(gòu)——數(shù)據(jù)空間和程序空間統(tǒng)一編址。
  如果數(shù)組rst[]數(shù)據(jù)的匯編機(jī)器碼是刪除文件的機(jī)器碼,這算不算是病毒?
  曾經(jīng)流行過一種蠕蟲病毒,其發(fā)作機(jī)理采取的就是將惡意代碼保存成文本文件,然后通過指針調(diào)用執(zhí)行這個文本,很多殺毒程序也不會查詢文本文件。
  程序也罷,數(shù)據(jù)也罷都是二進(jìn)制形式,如果數(shù)據(jù)空間和程序空間是統(tǒng)一編碼的, 數(shù)據(jù)當(dāng)然可以當(dāng)作程序運(yùn)行。
  在這一點上,相對而言,哈佛結(jié)構(gòu)的CPU安全性會好一點點。但嵌入式應(yīng)用少有病毒,一般不用關(guān)心。

單片機(jī)復(fù)位的更好方法
帖子中匯編語言解釋如下:
clr a                   //清除ACC=0
push acc                //壓0到堆棧——8位
push acc                //再壓0到堆?!?位
reti                        //返回到0地址,從而執(zhí)行。

帖子作者的這種復(fù)位方法比較麻煩,更加簡單的復(fù)位寫法是(摘自《C缺陷與陷阱》):
  (     * (  void (*)( )  )0      ) ( );
本句的分析方法同上,但更加精煉,沒有多余的匯編語句。

  上述復(fù)位的方法可稱為軟件復(fù)位。
  軟件復(fù)位跟真正上電復(fù)位有很大差別:上電復(fù)位時大部分寄存器都有確定的復(fù)位值;軟件復(fù)位則只相當(dāng)于從0地址開始執(zhí)行而已,寄存器不會變?yōu)榇_定的復(fù)位值。
  如果用戶要編程實現(xiàn)上電復(fù)位這種情況,在程序中不要踢看門狗即可。大部分單片機(jī)都有看門狗吧。
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
51系列單片機(jī)的軟件復(fù)位方法
C語言數(shù)組當(dāng)參數(shù)傳遞
指針與數(shù)組
神一般的C語言指針,你看懂多少?
【轉(zhuǎn)】typedef int (init
C語言系列
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服