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