1. 程式人生 > >ARM中斷異常處理的返回

ARM中斷異常處理的返回

舉個小例子,下面是一段ARM彙編程式碼:

地址

指令

0x3000

BL add

0x3004

MOV r0,#0

0x3008

MOV r1,#1

0x300C

MOV r2,#2

AREA test,CODE,READONLY
    ENTRY
    Start
         MOV r0,#1
         MOV r1,#1
         BL add
         MOV r0,#0
         MOV r1,#1
    Add
         ADD r0,r0,r1
         MOV r0,r0,r1
         END
 

當0x3000處的BL指令執行時,會把PC(=0x3008)儲存到LR暫存器裡面,也就是LR=0x3008。接下來處理器會立即對LR進行一個自動的更新動作:LR=LR-0x4,這樣,LR裡面的地址為0x3008 – 0x4 = 03004,它是指令”MOV r0,#0”的地址,所以當從子程式add返回時,LR裡面正好是正確的返回地址。既是下一條要執行的指令的地址。
 

(2)中斷異常處理函式呼叫
異常就是正在執行的指令,由於各種軟體或硬體故障被打斷,比如,在讀資料或指令時,訪問儲存器失敗、產生了一個外部硬體中斷等。當這些情況發生時,在ARM系統裡,由異常和中斷處理程式做出相應的處理,當處理完成後,要返回到被中止的指令,使被中止的指令能夠繼續正常執行下去。因此,確定異常和中斷處理程式的返回地址是一個非常重要的問題。

1、中斷處理

當外部中斷IRQ和FIQ(Fast Interrpt Request,快速中斷請求)發生時,ARM核完成一部分工作。當然,這些工作是任何異常發生時都必須要做的,所以ARM處理器就會自動帶我們完成。 其它重要的工作,必須由程式設計師來完成。ARM處理器處理的事包括從使用者模式切換到IRQ模式、狀態暫存器值的變化及跳轉。比如說,處理器自動跳轉到從0x0地址開始的異常中斷向量表的0x18處,在向量表的0x18處,最簡單的指令為”B HandlerIRQ”。

那程式設計師所要關心的就是實現具體的異常處理程式(HandlerIRQ)。當用ARM組合語言實現HandlerIRQ函式的時候,如何確定HandlerIRQ函式正確地返回地址,使被中止的指令能夠繼續正常執行下去。
 

比較常用的中斷處理程式結構如下:
 

HandlerIRQ ;中斷響應,從向量表直接跳來
 

SUB r14,r14,#4 ;計算返回地址
 

STMFD r13,{r0-r3,r14} ;保護現場,一般只需要保護{r0-r3,lr}
 

BL irqHandler ;跳到具體的異常處理函式
 

LDMFD r13,{r0-r3,pc}^ ;恢復現場
 

有程式可以看出,通過”SUB R14,R14,#4”計算中斷函式的返回地址。那有人一定會問,為什麼計算返回地址的時候要減去4呢?

地址

指令

0x3000

BL add

0x3004

MOV r0,#0

0x3008

MOV r1,#1

0x300C

MOV r2,#2

我們看上個表,比如在執行地址為0x3004的move指令時,突然來了一個IRQ中斷,這個中斷打斷了move指令的執行,這個時候就要去跳轉到異常處理函式,之後還要返回0x3004地址重新執行move指令。當中斷髮生時,LR裡面儲存了使用者模式下PC的值,那麼當執行地址為0x3004的move指令時,PC的值應該是0x300C,前面介紹過,當發生跳轉時,處理器會對LR進行一個自動的更新動作:LR=LR-0x4,這樣LR裡面的地址是0x300C-0x04=0x3008。但是0x3008並不是我們要的地址,因為中斷髮生在地址為0x3004的move指令執行的時候,所以中斷處理完後應該返回這個地址。 這就是在計算返回地址的時候LR減去4的原因。對於FIQ中斷和預取指中止異常,計算返回地址方法和IRQ相同。