RISC架構(gòu)可以認(rèn)為是加載/存儲(chǔ)的架構(gòu)宋欺,因?yàn)樗写鎯?chǔ)在外部數(shù)據(jù)都需要通過指令加載到處理器進(jìn)行處理奥帘。
加載/存儲(chǔ)的指令很多斯碌,常用的如下:
加載 | 存儲(chǔ) | 長度和類型 |
---|---|---|
LDR | STR | 32位的字(默認(rèn)) |
LDRB | STRB | 8位的無符號(hào)字節(jié) |
LDRH | STRH | 16位無符號(hào)的半字 |
LDRSB | 8位的有符號(hào)字節(jié) | |
LDRSH | 16位的有符號(hào)半字 | |
LDM | STM | 多個(gè)字的處理 |
- 加載/存儲(chǔ)的單指令處理的格式如下:
LDR|STR{<size>}{<cond>} <Rd>, <addressing_mode>
LDR表示從內(nèi)存中加載數(shù)據(jù)并寫到通用寄存器即硼,STR表示從通用寄存器讀取數(shù)據(jù)并把它存儲(chǔ)到內(nèi)存中竭宰。其中size是可選的如上表中的B/SB/H/SH等汗唱,addressing_mode表示尋址模式就是前面的文章《ARM匯編之內(nèi)存尋址模式》介紹的宫莱,總共3種。
下面這種格式不加哩罪!是偏移尋址模式授霸,加!是前變址尋址模式
LDR|STR{<size>}{<cond>} <Rd>, [<Rn>, <offset>]{!}
下面這種格式是后變址尋址模式
LDR|STR{<size>}{<cond>} <Rd>, [<Rn>], <offset>
例子:
AREA load_store, CODE, READONLY
ARM
ENTRY
start
MOV R1,#0x40000000
MOV R2,#2
LDR R3,[R1,R2,LSL #2];偏移尋址模式
;LDR R3,[R1,R2,LSL#2]!;前變址尋址模式
;LDR R3,[R1],R2,LSL#2;后變址尋址模式
STR R2,[R1]
STR R2,[R1,#4]!
MOV R2,#0XFF
STR R2,[R1],#8
stop
MOV r0, #0x18 ; angel_SWIreason_ReportException
LDR r1, =0x20026 ; ADP_Stopped_ApplicationExit
SVC #0x123456 ; A32 semihosting (formerly SWI)
END
- 加載/存儲(chǔ)多個(gè)寄存器的指令
LDM的語法格式如下:
LDM{addr_mode}{cond} Rn{!}, reglist{^}
其中<addr_mode>告訴匯編指令尋址的模式有下面四種:
IA,在每次傳輸完之后遞增地址(默認(rèn)模式际插,可省略) 绝葡。
IB,在每次傳輸完之前遞增地址 (僅A32支持)。
DA,在每次傳輸完之后遞減地址 (僅A32支持)腹鹉。
DB,在每次傳輸完之前遞減地址藏畅。
cond是可選的,表示條件碼功咒。
Rn是基址寄存器愉阎。
感嘆號(hào)!是可選的力奋,如果有表示最后的地址要寫回Rn寄存器榜旦。
reglist是用來加載數(shù)據(jù)的寄存器列表(包含一個(gè)或多個(gè)寄存器,多個(gè)的話可用逗號(hào)進(jìn)行分隔景殷,如果是多個(gè)連續(xù)的寄存器也可用一個(gè)范圍表示溅呢,比如R0-R4)澡屡,reglist需要用花括號(hào)括起來,對A32來說寄存器從R0到R15都可用咐旧,但T32只有部分寄存器可用驶鹉。
reglist之后的^是可選的,僅A32支持铣墨,他不能用在用戶模式或者系統(tǒng)模式( User mode/System mode)室埋,他是為如下場景設(shè)計(jì)的:
- 當(dāng)reglist中包含PC寄存器時(shí),不僅將數(shù)據(jù)加載到寄存器列表中指定的寄存器伊约,同時(shí)也順便把SPSR復(fù)制到CPSR姚淆,這發(fā)生在異常模式下中斷處理程序還回時(shí)。
- 否則數(shù)據(jù)將被傳輸進(jìn)/出用戶模式的寄存器屡律,而不是當(dāng)前模式的寄存器
備注:因?yàn)橛卸鄠€(gè)寄存器腌逢,那么怎么考慮寄存器列表里面的寄存器和內(nèi)存之間的映射,拿存儲(chǔ)來說超埋,是最低序號(hào)的寄存器存儲(chǔ)到最低內(nèi)存地址中上忍,最高序號(hào)的寄存器存儲(chǔ)到最高的內(nèi)存地址中,加載也是按這種方式進(jìn)行映射的纳本,這個(gè)是跟寄存器列表中寄存器的存放順序沒有關(guān)系的。
STM的語法格式如下:
STM{addr_mode}{cond} Rn{!}, reglist{^}
STM和LDM所帶選項(xiàng)基本一樣腋颠,釋義也基本一樣繁成,對LDM來說Rn存儲(chǔ)的是內(nèi)存中的基地址,只是STM要從該地址往內(nèi)存中寫數(shù)據(jù)淑玫,而LDM是從該地址從內(nèi)存中讀數(shù)據(jù)巾腕。reglist之后的^對STM來說,同樣也不能在用戶模式或者系統(tǒng)模式絮蒿,只是出現(xiàn)該符號(hào)時(shí)數(shù)據(jù)將被傳輸進(jìn)/出用戶模式的寄存器尊搬,而不是當(dāng)前模式的寄存器。
例子1:
AREA load_store, CODE, READONLY
ARM
ENTRY
start
MOV R9,#0x40000000
ADD R10,R9,#32
LDMIA R9, {R5, R0, R3};低地址的數(shù)據(jù)先加載到r0土涝,在加載到r3佛寿,最后加載到r5,
;加載順序跟放置在列表中的位置無關(guān)但壮,只跟寄存器的編號(hào)有關(guān)
LDMDB R10!,{R0-R1};最終地址會(huì)被寫回R10
stop
MOV r0, #0x18 ; angel_SWIreason_ReportException
LDR r1, =0x20026 ; ADP_Stopped_ApplicationExit
SVC #0x123456 ; A32 semihosting (formerly SWI)
END
例子2:
AREA load_store, CODE, READONLY
ARM
ENTRY
start
MOV R9,#0x40000000
ADD R10,R9,#32
MOV R2,#2
MOV R1,#1
STMIA R9,{R2,R1};注意最低地址存儲(chǔ)R1,在接著存儲(chǔ)R2冀泻,存儲(chǔ)順序跟放置在列表中的位置無關(guān)
STMIB R9,{R1,R2}
STMDA R10,{R2,R1}
STMDB R10!,{R1,R2}
stop
MOV r0, #0x18 ; angel_SWIreason_ReportException
LDR r1, =0x20026 ; ADP_Stopped_ApplicationExit
SVC #0x123456 ; A32 semihosting (formerly SWI)
END
- PUSH和POP
主要是針對棧的操作蜡饵,PUSH其實(shí)就是 STMDB sp!弹渔,POP其實(shí)就是 LDMIA sp!
語法格式如下:
PUSH{<cond>} <reglist>
POP{<cond>} <reglist>
其中reglist可以參照前面的LDM/STMD的說明
例子:
AREA push_pop, CODE, READONLY
ARM
ENTRY
start
mov sp,#0x40000010
push {r1,r0}
pop {r3,r4}
stop
MOV r0, #0x18 ; angel_SWIreason_ReportException
LDR r1, =0x20026 ; ADP_Stopped_ApplicationExit
SVC #0x123456 ; A32 semihosting (formerly SWI)
END
- 使用 LDM和STM來實(shí)現(xiàn)棧
使用棧時(shí)需要注意兩點(diǎn):
- 棧的增長方向,向上增長(ascending)或者向下增長(Descending)
- 棧指針的位置溯祸,指向空的位置(empty肢专,棧中下一個(gè)空的位置)舞肆,或者滿的位置(Full,最后一個(gè)棧成員的位置)
因此就可以組合出四種棧:
FD(Full Descending stack)
FA(Full Ascending stack)
ED(Empty Descending stack)
EA(Empty Ascending stack)
當(dāng)然這四種操作和LDM/STM中的addr_mode是等價(jià)的可以互相替換的博杖,編程時(shí)如果你覺得基于這種棧方式的操作更容易理解椿胯,可以用這種助記符來進(jìn)行編寫程序,匯編器會(huì)自動(dòng)幫你把這些轉(zhuǎn)換為基于addr_mode的合適指令欧募。
下面是一張等價(jià)圖
如果你是基于FD的棧來進(jìn)行開發(fā)压状,如果沒用FD助記符,那么入棧是你需要使用STMDB,而出棧是需要使用LDMIA跟继,如果使用FD的話入棧STMFD种冬,出棧LDMFD就行了剩下的交個(gè)匯編器去解釋,這種就很容易記憶了舔糖。下面是四種棧入棧/出棧的指令及等效的addr_mode模式下的原始指令
例子:
AREA push_pop, CODE, READONLY
ARM
ENTRY
start
mov sp,#0x40000010
stmfd sp!,{r0,r1};入棧
ldmfd sp!,{r2,r3};出棧
stop
MOV r0, #0x18 ; angel_SWIreason_ReportException
LDR r1, =0x20026 ; ADP_Stopped_ApplicationExit
SVC #0x123456 ; A32 semihosting (formerly SWI)
END
參考文獻(xiàn)
【1】DUI0801I_armasm_user_guide