ARM匯編編程基礎(chǔ)之六-其它尋址模式與其它指令
我們在“基本尋址模式與基本指令”一文中學(xué)習(xí)了最常用的3種尋址方式。下面介紹其它尋址方式。
本文引用地址:http://www.ex-cimer.com/article/201611/322179.htm1、基址尋址
基址尋址就是將基址寄存器的內(nèi)容與指令中給出的偏移量相加,形成操作數(shù)的有效地址。基址尋址用于訪問基址附近的存儲單元,常用于查表、數(shù)組操作、功能部件寄存器訪問等?;穼ぶ分噶钆e例如下:
LDR R1,[R2,#0x0C]
R2的值+0x0C形成內(nèi)存地址,讀取內(nèi)存中該地址上的內(nèi)容,放入R1
其它額外需要了解的內(nèi)容:
§零偏移。 如:LDR R0,[R1]
§前索引偏移。 如:LDR R0,[R1,#0x04]!,表示將R1的值加上4后作為內(nèi)存地址,并且指令執(zhí)行結(jié)束時,R1本身的值也要加4。這里!表示要回寫
§程序相對偏移。 如:LDR R0,labe1,表示將標(biāo)號label所代表的地址處存放的內(nèi)容放入R0,相當(dāng)于LDR R0, [PC, #某個常數(shù)]
§后索引偏移。 如:LDR R0,[R1],#0x04,表示將R1的值作為內(nèi)存地址,并且指令執(zhí)行結(jié)束時,R1本身的值要加4
2、多寄存器尋址
多寄存器尋址一次可傳送幾個寄存器值,允許一條指令傳送16個寄存器的任何子集或所有寄存器。多寄存器尋址指令舉例如下:
LDMIA R1!,{R2-R4,R6} ,它是ldr的多寄存版本,將內(nèi)存中的4個字放入寄存器R2,R3,R4,R6中
兩點說明:
1)、R1!中的!號表示在指令執(zhí)行完成后,要改變(回寫)基址寄存器(R1)的值
2)、寄存器列表{R2-R4, R6}中的順序并不要緊。最終寄存器與內(nèi)存地址的對應(yīng)關(guān)系是:編號小的寄存器與內(nèi)存的低地址相對應(yīng)
兩點問題:
1)、為什么內(nèi)存起地址是0x40000000,而不是0x40000004
2)、為什么內(nèi)存地址是從0x40000000 ---- 0x4000000C,而不是從0x3FFFFFF4 ----
要解釋上面2個問題,其實也很簡單。其實多寄存加載指令ldm總共有4個:ldmia、 ldmib、 ldmda、 ldmdb。ia的意思是increase after,ib的意思是increase before,da的意思是decrease after,db的意思是decrease before。以LDMIA R1!, {R2-R4, R6}為例子,這里的ia是指辦事(將內(nèi)存中的數(shù)加載到寄存器)之后增加基址寄存器(R1)的值。這條指令的執(zhí)行過程從邏輯上看,如下:
1)、先辦事:將R1的值(0x40000000)作為內(nèi)存地址,到該地址處取得數(shù)(0x01),加載到寄存器R2中
2)、后增加:將R1的值從0x40000000增加為0x40000004
再重復(fù)上面的操作3次,分別將內(nèi)存中的數(shù)0x02、0x03、0x04放到寄存器中R3、R4、R6中,最后R1的值變?yōu)?x40000010。
這個例子中,如果將ldmia改為ldmib,則R2、R3、R4、R6中存放的是0x02、0x03、0x04、內(nèi)存0x40000010處的內(nèi)容,最后R1的值為0x40000010。
除了4條多寄存器加載指令外,還有4條類似的多寄存器存儲指令,分別是stria、 strib、 strda、 strdb
3、堆棧尋址
由于ARM指令集沒有專門的出棧和入棧指令,所以ARM匯編程序是采用SP作為棧指針,以stm指令完成入棧操作,以ldm指令完成出棧操作。
以入棧后SP的值是增加還是減少為依據(jù),可將堆棧類型劃分為遞增堆棧(向上生長)和遞減堆棧(向下生長);
以SP所指向的內(nèi)存處存放的是棧頂元素還是下一次要入棧的元素,可將堆棧類型劃分為滿堆棧和空堆棧
那么當(dāng)堆棧類型為空遞減堆棧時候,入棧操作應(yīng)該使用什么指令?出棧操作應(yīng)該使用什么指令?進一步,如果堆棧類型為空遞增、滿遞增、滿遞減堆棧,又將如何呢?如果你不看下面的答案,我相信你一定會讓這幾個問題折磨得做很多的腦力體操,然后感嘆ARM指令集的設(shè)計者太不為你這樣的程序員考慮了,給了你本不應(yīng)該由你承擔(dān)的負(fù)荷。但事實上正相反,ARM指令集的設(shè)計者充分理解了你作為程序員的苦惱,請看下面的答案。
數(shù)據(jù)塊傳送 | 堆棧操作 | 說明 |
存儲 | 壓棧 | |
STMDA | STMED | 空遞減 |
STMIA | STMEA | 空遞增 |
STMDB | STMFD | 滿遞減 |
STMIB | STMFA | 滿遞增 |
數(shù)據(jù)塊傳送 | 堆棧操作 | 說明 |
加載 | 出棧 | |
LDMDA | LDMFA | 滿遞增 |
LDMIA | LDMFD | 滿遞減 |
LDMDB | LDMEA | 空遞增 |
LDMIB | LDMED | 空遞減 |
這2張表的第一、三列回答了前面你絞盡腦汁回答的問題。而第二列則體現(xiàn)了ARM指令集的設(shè)計者對作為程序員的你的充分體貼。第二列中的ED、EA、FD、FA分別表示empty descend(空遞減)、 empty ascend(空遞增)、 full descend(滿遞減)、 full ascend(滿遞增),其含義是說,如果你采用的是空遞減(空遞增、滿遞減、滿遞增)堆棧的話,入棧操作則使用指令STMED(STMEA、STMFD、STMFA),出棧操作則使用指令LDMED(LDMEA、LDMFD、LDMFA)。從此你再也不會為你應(yīng)該使用ia、ib、da還是db來實現(xiàn)出、入棧操作而苦惱了。
評論