ARM匯編編程基礎之一 —— 寄存器


ARM的匯編編程,本質上就是針對CPU寄存器的編程,所以我們首先要弄清楚ARM有哪些寄存器?這些寄存器都是如何使用的?

ARM寄存器分為2類,普通寄存器和狀態寄存器

寄存器類別

寄存器在匯編中的名稱

各模式下實際訪問的寄存器

用戶

系統

管理

中止

未定義

中斷

快中斷

通用寄存器和程序計數器

R0(a1)

R0

R1(a2)

R1

R2(a3)

R2

R3(a4)

R3

R4(v1)

R4

R5(v2)

R5

R6(v3)

R6

R7(v4)

R7

R8(v5)

R8

R8_fiq

R9(SB,v6)

R9

R9_fiq

R10(SL,v7)

R10

R10_fiq

R11(FP,v8)

R11

R11_fiq

R12(IP)

R12

R12_fiq

R13(SP)

R13

R13_svc

R13_abt

R13_und

R13_irq

R13_fiq

R14(LR)

R14

R14_svc

R14_abt

R14_und

R14_irq

R14_fiq

R15(PC)

R15

狀態寄存器

CPSR

CPSR

SPSR

SPSR_abt

SPSR_abt

SPSR_und

SPSR_irq

SPSR_fiq

 

請看上表的第2列,普通寄存器總共16個,分別為R0-R15;狀態寄存器共2個,分別為CPSR和SPSR

普通寄存器中特別要提出來的是R13、R14、R15。

R15別名PC(program counter),中文稱為程序計數器,它的值是當前正在執行的指令在內存中的位置(不考慮流水線的影響,參見流水線對PC值的影響一文),而當指令執行結束后,CPU硬件會自動將PC的值加上一個單位,從而使得PC的值為下一條即將執行的指令在內存中的位置,這樣CPU硬件就可以根據PC的值自動完成取指的操作。正是由於有PC的存在,以及CPU硬件會自動增加PC的值,並根據PC的值完成取指操作,才使得CPU一旦上電就永不停歇地運轉,由此可見PC寄存器對於計算機的重要性。對於我們進行匯編程序編寫而言,PC寄存器亦是十分重要,因為當程序員通過匯編指令完成了對PC寄存器的賦值操作的時候,其實就是完成了一次無條件跳轉,這一點非常重要,請務必要牢記。

R14別名LR(linked register),中文稱為鏈接寄存器,它與子程序調用密切相關,用於存放子程序的返回地址,它是ARM程序實現子程序調用的關鍵所在。下面我們用C語言中對子程序調用的實現細節來說明LR是如何被使用的。

1 int main(void)
2 {
3    int k, i = 1, j = 2;
4    addsub(i, j);
5    k = 3;
6 }

7 int addsub(int a, int b)
8 {
9    int c;
10    c = a + b;
11    return c;
12 }

對於上面的程序,編譯器會將第4行編譯為指令:BL addsub,將第11行編譯為指令:MOV pc, lr。(關於BL和MOV指令詳見“基本尋址模式與基本指令”)

在這里,關鍵指令BL addsub會完成2件事情:1、將子程序的返回地址(也就是第5行代碼在內存中的位置)保存到寄存器LR中;2、跳轉到子程序addsub的第1條指令處。這樣就完成了子程序的調用。而指令MOV pc, lr則將保存在lr中的返回地址賦給pc,這樣就完成了從子程序的返回。由此可見,lr是用於存放子程序的返回地址的。

另外一個要引起注意的問題是,如果子程序又調用了孫子程序,那么根據前面的分析,在調用孫子程序時,lr寄存器中的值將從子程序的返回地址變為孫子程序的返回地址,這將導致從孫子程序返回子程序沒有問題,但從子程序返回父程序則會出錯。那么這個問題如何解決呢?其實,如果我們編寫的是C程序,那么我們一點也不用擔心,因為編譯器會為我們考慮一切,針對這個問題,編譯器會在孫子程序的入口處增加入棧操作將lr的值入棧,然后在孫子程序的返回處增加出棧操作,將lr的值恢復,從而解決這個難題。不過我們一定要保持頭腦的清醒,因為你要知道,我們現在是在編寫匯編子程序,此時編譯器已經不能在這方面給我們提供保障,所以當你在編寫匯編子程序的時候,發現該子程序還要再調用孫子程序,那么請你務必記住,一定要在子程序的入口處保存lr寄存器的值。

好了,現在輪到寄存器R13了,R13又名SP(stack pointer),中文名稱棧指針寄存器。顧名思義,它是用於存放堆棧的棧頂地址的。也就是說,每次當我們進行出棧和入棧的時候,都將根據該寄存器的值來決定訪問內存的位置(即:出入棧的內存位置),同時在出棧和入棧操作完成后,SP寄存器的值也應該相應增加或減少。這里要特別說明的是,其實在32位的ARM指令集中沒有專門的入棧指令和出棧指令,所以並不是一定要用SP來作為棧指針寄存器,除了PC外,任何普通寄存器均可作為棧指針寄存器,只不過,約定俗成都使用SP罷了。我們將在“其它尋址模式與其它指令”一文中見到ARM中使用SP作為棧指針寄存器的出入棧指令。

寄存器R0-R12是普通的數據寄存器,可用於任何地方。在不涉及ATPCS規則(在“ATPCS與混合編程”一文中詳細介紹)的情況下,他們並沒有什么特別的用法。

狀態寄存器CPSR(current program status register),中文名稱:當前程序狀態寄存器,顧名思義它是用於保存程序的當前狀態的。那么,程序的哪些狀態是需要保存的呢?

image

上圖是CPSR寄存器的內容,主要由以下部分組成:

1、條件代碼標志位。它們是ARM指令條件執行的依據。

N:運算結果的最高位反映在該標志位。對於有符號二進制補碼,結果為負數時N=1,結果為正數或零時N=0;

Z:指令結果為0時Z=1(通常表示比較結果“相等”),否則Z=0;

C:當進行加法運算(包括CMN指令),並且最高位產生進位時C=1,否則C=0。當進行減法運算(包括CMP 指令),並且最高位產生借位時C=0,否則C=1。對於結合移位操作的非加法/減法指令,C為從最高位最后移出的值,其它指令C通常不變

V:當進行加法/減法運算,並且發生有符號溢出時V=1,否則V=0,其它指令V通常不變

2、控制位。它們將控制CPU是否響應中斷。

I:中斷禁止位,當I位置位時,IRQ中斷被禁止

F:快中斷禁止位,當F位置位時,FIQ中斷被禁止

T:反映了CPU當前的狀態。當T位置位時,處理器正在Thumb狀態下運行;當T位清零時,處理器正在ARM狀態下運行

3、模式位

包括M4、M3、M2、M1和M0,這些位決定了處理器的模式(關於處理器模式詳見“ARM處理器模式與異常初步”一文)。

總共有7種模式:用戶、快中斷、中斷、管理、中止、未定義、系統,分別會用於不同的情況和異常。由此可見,不是所有模式位的組合都定義了有效的處理器模式,如果使用了錯誤的設置,將引起一個無法恢復的錯誤。

SPSR(saved program status register),中文名稱:保存的程序狀態寄存器

該寄存器的結構與CPSR完全一樣,在異常發生時(關於異常,請參見“ARM處理器模式與異常初步”一文),由硬件自動將異常發生前的CPSR的值存放到SPSR中,以便將來在異常處理結束后,程序能恢復原來CPSR的值。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM