尋址方式就是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自動更新,指向操作後的地址