關於#define EnterPWDN(clkcon)

來源:互聯網
上載者:User

經常見到嵌入式設計中,將某一程式段的入口地址轉換為一個函數,我們來分析一下它的成分:
      如在bootloader的0x00000020地址上的雙字單元中有這樣一條語句:
@Address is 0x00000020
      b powerdown          @Jump to the flag "powerdown"
...
...
powerdown:
...
...
      然後在某一C標頭檔中可以見到這樣的宏聲明:
#define EnterPWDN(clkcon) ((void (*)(int))0x20)(clkcon)
      初一看,亂七八糟的,現在,我們來整理一下。
      不難看出,當我們編程調用EnterPWDN(clkcon)函數的時候,編譯器在編譯前首先把EnterPWDN(clkcon)轉換為
((void (*)(int))0x20)(clkcon)語句。
對於這個語句,我們將之分解成3部分來看。
      1:(void (*)(int)
      2:0x20
      3:(clkcon)
      (clkcon)是函數的參數,就不用說了。0x20呢?當然就是要轉換的函數的入口地址了。那對於(void (*)(int)呢??呵呵……,這一部分作為一個整體,描述了轉換後的函數的類型,即無傳回值,帶一個整形參數。而中間那個”(*)“,就表示要轉換成一個函數(或者說把0x20轉換為一個地址,因為在ARM彙編中,就把C語言的函數名當作一個地址標號看待了)。就像我們平常用的強制類型轉換一樣,(int)temp,只不過這裡是將一個數轉換為另一類型,而那是將一個地址轉換為一個函數罷了。

關於arm中: #define EnterPWDN(clkcon) ((void (*)(int))0x00000020)(clkcon)

1。首先要知道帶參數的宏定義。定義方法如下:

      #define 宏名(參數) 字串

      如下:#define add(a,b) (a)+(b)

      那麼:程式中的 b=add((2*3),(4*5)) 等價於 b=(2*3)+(4*5) 。

      具體請參考c語言書籍。

2。下面看:EnterPWDN(0x7fff4);

      會被替換成:((void (*)(int))0x00000020)(0x7fff4);

      這個涉及到函數指標,函數指標的用法如下:

      void fun(int x); /* 聲明一個函數 */

      void (*pfun) (int x); /* 聲明一個函數指標 */

      pfun=fun; /* 將func函數的首地址賦給指標f */

      那麼調用函數fun可以這樣寫:a. fun(5);  b. (*pfun)(5); 

      則:((void (*)(int))0x00000020)(0x7fff4); 中藍色0x7fff4是傳遞的參數,紅色(void (*)(int))0x00000020是函數名。其實函數名本身就是一個地址。像上式中,如果你知道函數fun存在地址0x012345,那麼理論上你可以這麼寫:0x012345(5),當然實際上不能這麼寫,因為你雖然fun在0x012345地址,但是你編譯器不知到這個函數的參數、傳回值等資訊。所以要強制轉換一下。

      接下來看一下怎麼把一個地址轉換成函數名:

      如果把 char a ; 中的a轉換成 int  形變數,要這樣:b=(int)a;

      同樣要把0x00000020地址轉換為函數名,也要強制轉換,只要在0x00000020的前面加上要轉換的類型。(void (*)(int))就是函數類型,和void (*pfun) (int x); / / 聲明一個函數指標 是相對應的。

3。再看一下EnterPWDN(0x7fff4); 調用之後具體的參數傳遞,這個涉及到c和彙編的相互調用。

      看

__ENTRY
ResetEntry
 
       b ResetHandler
    
       b HandlerUndef ;handler for Undefined mode
       b HandlerSWI ;handler for SWI interrupt
       b HandlerPabort ;handler for PAbort
       b HandlerDabort ;handler for DAbort
       b .  ;reserved
       b HandlerIRQ ;handler for IRQ interrupt
       b HandlerFIQ ;handler for FIQ interrupt

;@0x20
       b EnterPWDN ; Must be @0x20.

      跳到0x00000020地址後會接著跳轉到標號EnterPWDN 處。

 EnterPWDN
       mov r2,r0  ;r2=rCLKCON
       tst r0,#0x8  ;SLEEP mode?
       bne ENTER_SLEEP

      看這裡第一句:mov r2,r0  。其實 r0 中存的就是參數0x7fff4 ,這個涉及到c調用彙編,自己找一下參考書吧,我就不獻醜了。 

ARM中#define EnterPWDN(clkcon) ((void (*)(int))0x20)(clkcon))代表什麼意思

1.首先,這是一個帶參數宏定義,所以,如果有語句EnterPWDN(0x7fff4)則展開以後就是如下語句 ((void (*)(int))0x20)(0xffff4))

2.(void(*)(int))0x20的意思

(void(*)(int))作為一個強制類型轉換,將0x20轉換為一個函數指標類型,這個函數的原型為 void fun(int); 而後面的0xffff4就是代表的函數的參數,所以 ((void (*)(int))0x20)(0xffff4))整句話的意思就是調用地址在0x20處的函數,參數為0xffff4.其實看後面實際上就是跳轉到地址0x20處執行代碼,並且把參數傳到r0,ATPCS中規定1-4個參數對應的儲存寄存器為r0-r3。

3.再看在2440init.s中對該部分的定義

b ResetHandler
b HandlerUndef ;handler for Undefined mode
b HandlerSWI ;handler for SWI interrupt
b HandlerPabort ;handler for PAbort
b HandlerDabort ;handler for DAbort
b .   ;reserved
b HandlerIRQ ;handler for IRQ interrupt
b HandlerFIQ ;handler for FIQ interrupt

;@0x20
b EnterPWDN ; Must be @0x20.

    EnterPWDN
         mov r2,r0   ;r2=rCLKCON
         tst r0,#0x8   ;SLEEP mode?
         bne ENTER_SLEEP

b EnterPWDN ; Must be @0x20.這條語句,對應的指令地址為0x20,這就是前面((void (*)(int))0x20)中0x20的意義,然後語句跳到EnterPWDN執行,單然,參數值就傳給了r0,後面的東西查看硬體說明。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.