ARM的九種尋址方式

尋址方式就是CPU根據指令中的地址信息,找出物理地址也就是內存地址的方式,通俗理解就是ARM指出內存地址的方式。

尋址的目的就是找出操作數,比如ARM要做一個除法運算,就需要除數和被除數,除數和被除數都是除法指令的操作數,要找到這些操作數,可以有多種方法,尋找操作數的過程就叫做尋址。(我個人理解)

ARM支持九種尋址方式:

  • 立即數尋址
  • 寄存器尋址
  • 寄存器偏移尋址
  • 寄存器間接尋址
  • 寄存器基址變址尋址
  • 多寄存器尋址
  • 相對尋址
  • 堆棧尋址
  • 塊拷貝尋址

1.立即數尋址

立即數尋址就是直接將內存中的數據發給CPU作爲操作數。注意,由於ARM是32位指令集,所以立即數的範圍不可以超出0255,也就是說立即數的範圍只能是0255。

格式:就是在立即數前面加上 # 來作爲操作數

典型的例子就是直接對寄存器進行寫值:

ldr r0, #254   ;將254寫入r0寄存器
add r1, r2, #3 ;將r2寄存器中的值與3相加後,在寫入r1寄存器

2.寄存器尋址

寄存器尋址就是直接將寄存器中的數值作爲操作數:

ldr r1, r0      ;將r0寄存器中的值寫到r0
add r3, r2, r1  ;將r1、r2寄存器的值相加,結果寫入r3寄存器

3.寄存器間接尋址

還是利用了寄存器,只不過操作數不是寄存器中的值了,操作數在內存中,那怎麼辦?沒事,操作數的地址就在寄存器中。所以寄存器間接尋址相當於以寄存器中的值作爲內存地址,去內存中尋找操作數。

格式:在提供操作數地址的寄存器上加上[],比如[r0]

mov r0, #0X54000032
ldr r1, [r0]           ;將地址爲0X54000032的數據寫入r1寄存器中

4.寄存器偏移尋址

以寄存器尋址爲本,將寄存器中的數移位後作爲操作數。

一共有6中移位操作:

LSL:邏輯左移(Logical Shift Left),寄存器中字的低端空出的位補0。

LSR:邏輯右移(Logical Shift Right),寄存器中字的高端空出的位補0。

ASL:算術左移(Arithmetic Shift Left),和邏輯左移LSL相同。

ASR:算術右移(Arithmetic Shift Right),移位過程中符號位不變,即如果源操作數是正數,則字的高端空出的位補0,否則補1。

ROR:循環右移(Rotate Right),由字的低端移出的位填入字的高端空出的位。

RRX:帶擴展的循環右移(Rotate Right eXtended),操作數右移一位,高端空出的位用進位標誌C的值來填充,低端移出的位填入進位標誌位。

格式:rx, 移位命令 移位操作數

ldr r0, r1, lsl #3   ;將r1的值邏輯左移3位後寫入r0
ldr r0, r1, ror r2   ;將r1的值循環右移r2中的值對應位後,寫入r0

5.寄存器基址變址尋址

基址變址尋址是基於寄存器間接尋址的,只不過地址不再是寄存器中的值了,而是偏移後的值,這裏的偏移值可以理解爲地址相加值。

加上感嘆號應該有優先執行的意思吧(個人理解)

格式:[rx, n],表示在rx寄存器所指向的地址上,再偏移(相加)n字節

ldr r0, [r1, #3]     ;地址爲:r1值+3字節,指令執行完r1不變
ldr r0, [r1, #3]!    ;地址爲:r1值+3字節,指令執行完r1+3
ldr r0, [r1, #-1]    ;地址爲:r1值-1字節,指令執行完r1不變
ldr r0, [r1, r2]     ;地址爲:r1值+r2值
ldr r0, [r1], #4     ;地址爲:r1值,但指令執行完後,r1值+4字節

6.批量寄存器尋址

批量寄存器尋址就是使用一個大括號{}包含多個寄存器

ldmia r0, {r1, r2, r3, r4}     ;將r1,r2,r3,r4中的數據依次放入R0指向的內存地址,r0+4指向的內存地址...
ldmia r0, {r1-r4}             ;同上。

7.相對尋址

通過標號進行尋址,經常與跳轉指令相配合使用

	bl heihei 

heihei:        ;跳轉到heihei執行

8.堆棧尋址

堆棧即Stack,因爲CPU的寄存器總是及其有限的,很多時候我們不得不使用內存來存儲數據,比如進行多級跳轉的時候,這時候堆棧就是一個很好的工具,每次跳轉就將當前函數的返回地址存儲到內存,最底層被調用的子函數會最先返回,就先將壓入棧的現場返回,以此類推…,ARM使用SP(R13)作爲棧指針,ARM設計的內存棧模型有2×2=4種

按照棧在內存增長的方向分爲遞增棧遞減棧

遞增(Increase) 堆棧:向堆棧寫入數據時,堆棧由低地址向高地址生長。

遞減(Descend) 堆棧:向堆棧寫入數據時,堆棧由高地址向低地址生長。

根據堆棧指針SP指向的位置,又可以把堆棧分爲滿堆棧空堆棧兩種。

滿堆棧(Full Stack):SP始終指向棧頂元素,壓棧的時候先移動SP,再將數據放入SP指向的地址。

空堆棧(Empty Stack):SP始終指向下一個將要放入元素的位置,壓棧時先將數據放入SP指向的地址,再移動SP

最後,可以得到4種基本的堆棧類型:

滿增棧(FA):堆棧指針指向最後壓入的數據,且由低地址向高地址生長。

滿減棧(FD):堆棧指針指向最後壓入的數據,且由高地址向低地址生長。常用這種

空增棧(EA):堆棧指針指向下一個將要壓入數據的地址,且由低地址向高地址生長。

空減棧(ED):堆棧指針指向下一個將要壓入數據的地址,且由高地址向低地址生長。

stmfd sp!, {r1-r7, lr}  ;將r1到r7和lr的數據壓入fd棧

9.塊拷貝尋址

塊拷貝尋址提供了一塊內存和一組寄存器之間的拷貝,按照內存使用方式的不同,可以分爲2×2=4種。地址增方向/地址減方向×先偏移/後偏移。堆棧尋址就可以看作是塊拷貝尋址的的一個實例。

即:

IB:Increment Before Operating

IA:Increment After Operating

DB:Decrement Before Operating

DA:Decrement After Operating

STMIA  R0!,{R1—R7}  ;將R1-R7的寄存器中的值放入R0指向的地址,R0自動更新,指向操作後的地址

參考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章