AAPCS關(guān)于ARM寄存器的定義
對(duì)于32位及其以下的ARM處理器來說,函數(shù)調(diào)用規(guī)則如下:
- 父函數(shù)與子函數(shù)的入口參數(shù)以此通過 R0~R3 這4個(gè)寄存器傳遞。 父函數(shù)在調(diào)用子函數(shù)前先將子函數(shù)入口參數(shù)存入 R0~R3 寄存器中,若只有一個(gè)入口參數(shù)則使用 R0 寄存器傳遞,若有2個(gè)入口參數(shù)則使用 R0 和 R1 寄存器傳遞,以此類推。。當(dāng)超過4個(gè)參數(shù)時(shí),其余的入口參數(shù)則以此壓入當(dāng)前棧通過棧傳遞。子函數(shù)運(yùn)行時(shí),其將根據(jù)自身參數(shù)個(gè)數(shù)從 R0~R3 或者棧中讀取入口參數(shù)
- 子函數(shù)通過 R0 寄存器將函數(shù)返回值傳遞給父函數(shù)。子函數(shù)返回時(shí),將返回值存入 R0寄存器,當(dāng)返回到父函數(shù)時(shí),父函數(shù)讀取 R0 寄存器就可以獲得子函數(shù)的返回值。
- AAPCS規(guī)定,發(fā)生函數(shù)調(diào)用前由父函數(shù)備份 R0~R3 寄存器中有用的數(shù)據(jù),若沒有有用的數(shù)據(jù)則可以不處理,然后才能調(diào)用子函數(shù),以防止父函數(shù)保存在 R0~R3 寄存器中有用的數(shù)據(jù)在子函數(shù)使用這些寄存器時(shí)被破壞。因此,無論父函數(shù)是否通過 R0~R3 寄存器向子函數(shù)傳遞入口參數(shù),子函數(shù)都可以直接使用 R0~R3 寄存器,無需考慮改寫 R0~R3 寄存器會(huì)破壞父函數(shù)存儲(chǔ)在它們中的數(shù)值,子函數(shù)返回時(shí)也無需恢復(fù) R0~R3 寄存器中的數(shù)值。
- R4~R11 寄存器為普通的通用寄存器。AAPCS規(guī)定,發(fā)生函數(shù)調(diào)用時(shí),父函數(shù)無需對(duì)這些寄存器進(jìn)行備份處理,若子函數(shù)需要使用這些寄存器,則由子函數(shù)負(fù)責(zé)備份(需要使用哪個(gè)就備份哪個(gè)),以防止破壞父函數(shù)保存在 R4~R11 寄存器中的數(shù)據(jù)。子函數(shù)返回父函數(shù)前需先恢復(fù) R4~R11 寄存器中的數(shù)值(使用了哪個(gè)就恢復(fù)哪個(gè)),恢復(fù)到父函數(shù)調(diào)用子函數(shù)這一時(shí)刻的數(shù)值,然后再返回到父函數(shù)。
- R12 寄存器在某些版本的編譯下另有他用,在函數(shù)調(diào)用時(shí)需要備份,它的用法等同于 R0~R3 寄存器。
- R13 寄存器時(shí)棧寄存器(SP),用來保護(hù)棧的當(dāng)前指針,函數(shù)存儲(chǔ)在棧中的數(shù)據(jù)就是通過這個(gè)寄存器來尋址的。函數(shù)返回時(shí)需要保證 SP 指向 調(diào)用 該函數(shù)時(shí)的棧地址。
- R14 寄存器時(shí)鏈接寄存器(LR),用來保存函數(shù)的返回地址。父函數(shù)調(diào)用子函數(shù)時(shí),父函數(shù)會(huì)將調(diào)用子函數(shù)指令的下一條指令地址存入到 LR 寄存器中,當(dāng)子函數(shù)返回時(shí)只需要跳轉(zhuǎn)到 LR 寄存器里的地址就會(huì)返回父函數(shù)繼續(xù)執(zhí)行。父函數(shù)調(diào)用子函數(shù)將子函數(shù)返回地址存入 LR 寄存器前, LR 寄存器中保存的可能是父函數(shù)返回其上一級(jí)函數(shù)的地址或其他有用的數(shù)據(jù),因此需要先備份 LR 寄存器然后才能調(diào)用子函數(shù)。
- R15 寄存器時(shí)程序寄存器(PC),正在執(zhí)行的指令地址就存儲(chǔ)在 PC 寄存器中,更改 PC 寄存器的數(shù)值就會(huì)執(zhí)行這個(gè)數(shù)值所對(duì)應(yīng)的地址中的指令。
寄存器
ARM內(nèi)核有 18 個(gè)寄存器,包括 R0~R12,2個(gè)R13,R14,R15和 XPSR 寄存器。
其中 R13 寄存器又叫 SP 寄存器, R14 寄存器又叫 LR 寄存器, R15 寄存器也叫 PC 寄存器。
R0~R12 通用寄存器
這些通用寄存器用來臨時(shí)存放數(shù)據(jù),供處理器運(yùn)行程序時(shí)使用。
其中某些寄存器在程序調(diào)用時(shí)還會(huì)有其他專用功能,
比如說 R0~R3 寄存器在程序調(diào)用時(shí)可以用來傳遞函數(shù)參數(shù)和返回值,R12 寄存器在某些情況下可以保存子程序調(diào)用的中間值。
R13-SP(Stack Pointer) 棧寄存器
在ARM內(nèi)核中有 2個(gè) SP,分別是 MSP 和 PSP,根據(jù)模式不同使用的 SP 寄存器不同,不能同時(shí)存在。
R14-LR(Link Register) 鏈接寄存器
用來保存跳轉(zhuǎn)后返回的地址。
當(dāng)發(fā)生函數(shù)調(diào)用時(shí),LR 寄存器中保存著函數(shù)返回后需要執(zhí)行的指令地址。
R15-PC(Program Counter) 程序計(jì)數(shù)器
存放的是當(dāng)前所執(zhí)行指令所在的地址。
當(dāng)在C語言中調(diào)用函數(shù)或者產(chǎn)生跳轉(zhuǎn)時(shí),實(shí)際上就是通過改變PC寄存器的值實(shí)現(xiàn)的。
指令
數(shù)據(jù)計(jì)算指令: ADD ADR SUB
數(shù)據(jù)搬移指令: MOV LDR LDM STM PUSH POP
狀態(tài)寄存器操作指令: MRS MSR
邏輯計(jì)算指令: AND
跳轉(zhuǎn)指令: BX CBZ
軟中斷指令: SVC
ADD 加法指令
SUB 減法指令
MOV 數(shù)據(jù)搬移指令(復(fù)制)
LDR 將內(nèi)存數(shù)據(jù)加載到寄存器
指令格式有兩種:LDR 目的寄存器,=常量
LDR 目的寄存器,[源寄存器]
第一種格式,是將常量值存入目的寄存器
第二種格式,是將源寄存器中的數(shù)據(jù)指向的內(nèi)存地址中的數(shù)據(jù)存入目的寄存器
例:
LDR R0,=globalVariate ;globalVariate表示全局變量,變量名對(duì)應(yīng)它的地址
LDR R3,[R0]
對(duì)應(yīng) C語言:
R0 = &globalVariate
R3 = *R0
LDM (LDR增強(qiáng)版,將多個(gè)連續(xù)數(shù)據(jù)存入到一組寄存器中)
根據(jù)對(duì)棧指針不同的操作方式可以有4中劃分:
滿棧(Full):棧指針指向棧頂最后一個(gè)入棧的位置,此時(shí)棧指針指向的??臻g是滿的。
空棧(Empty):棧指針指向棧頂將要入棧的位置,此時(shí)棧指針指向的??臻g是沒用過的,是空的。
遞減棧(Descending):向棧內(nèi)存儲(chǔ)數(shù)據(jù)時(shí)棧指針向著內(nèi)存地址減少的方向移動(dòng)。
遞增棧(Ascending):向棧內(nèi)存儲(chǔ)數(shù)據(jù)時(shí)棧指針向著內(nèi)存地址增加的方向移動(dòng)。
綜合棧的空滿和增減特性,棧可分為FD ED FA EA 這4種類型。
匯編指令提供了4種對(duì)棧的操作方式,分別是DB(Decrement Before)、DA(Decrement After)、IB(Increment Before)和IA(Increment After)。
- DB意為棧指針先減少再操作
- DA意為棧指針先操作再減少
- IB意為棧指針先增加再操作
- IA意為棧指針先操作再增加
這4種操作方式都可以與 LDM 指令組合,形成 LDMDB、LDMDA、LDMIB和LDMIA 指令
LDM經(jīng)常在棧操作中使用,有2中指令格式,以LDMIA為例:LDMIA 源寄存器,{一組目的寄存器} ;目的寄存器之間可以用 ','分開,也可以用'-'表示一個(gè)范圍的寄存器
LDMIA 源寄存器!,{一組目的寄存器}
第一種指令格式,從源寄存器指定的站地址開始,將棧中的一組數(shù)據(jù)存入到目的寄存器組中;
第二種指令格式,除了完成第一種指令格式功能外,還將源寄存器操作后指向的棧地址保存到源寄存器中。
例:LDMIA R14,{R0-R3,R12}
LDMIA R1!,{R4-R7}
對(duì)應(yīng) C語言:
/* No.1 */
R0 = *R14
R1 = *(R14 + 4) //32位,4字節(jié)
R2 = *(R14 + 8) //32位,4字節(jié)
R3 = *(R14 + 12) //32位,4字節(jié)
R12 = *(R14 + 16) //32位,4字節(jié)
//操作完成,R14寄存器的數(shù)值仍不變
/* No.2 */
R4 = *R1
R5 = *(R1 + 4) //32位,4字節(jié)
R6 = *(R1 + 8) //32位,4字節(jié)
R7 = *(R1 + 12) //32位,4字節(jié)
R1 = R1 + 16 //32位,4字節(jié)
//操作完成,將R1寄存器的數(shù)值更新為當(dāng)前指向的棧地址
STM (將一組寄存器中的數(shù)據(jù)存入到棧中)
STM功能正好和LDM功能相反,同樣,STM也有4種操作方式:STMDB、STMDA、STMIB和STMIA,分別與LDM對(duì)應(yīng)
指令格式:STMIA 目的寄存器,{一組源寄存器}
STMIA 目的寄存器!,{一組源寄存器}
例:STMIA R13,{R0}
PUSH 壓棧指令
指令格式:PUSH {一組寄存器}
PUSH指令其實(shí)就是如下指令的簡(jiǎn)寫:STMDB SP!,{一組寄存器} ;先減少后操作
POP 出棧指令
POP指令可以將數(shù)據(jù)從棧中彈出到寄存器中
指令格式:POP {一組寄存器}
PUSH指令其實(shí)就是如下指令的簡(jiǎn)寫:LDMIA SP!,{一組寄存器} ;先操作后增加
MRS
將 XPSR寄存器中的數(shù)據(jù)保存到通用寄存器中,格式為:MRS 寄存器,XPSR
MSR
將通用寄存器中的數(shù)據(jù)保存到 XPSR寄存器,格式為:MSR XPSR,寄存器
AND 與
將源寄存器中的數(shù)據(jù)和目的寄存器中的數(shù)據(jù)進(jìn)行與操作,并將結(jié)果存入到目的寄存器中
指令格式:AND 目的寄存器,源寄存器
BX 跳轉(zhuǎn)
BX指令除了可以跳轉(zhuǎn)到目的寄存器指向的地址外,還可以改變處理器運(yùn)行的指令集
指令格式:BX 寄存器
CBZ
CBZ指令判斷 R0 寄存器中的數(shù)值是否為0,如果是0,則跳轉(zhuǎn)到 __BACKUP_REG地址,其中__BACKUP_REG是一個(gè)地址常數(shù)
指令格式:CBZ R0,__BACKUP_REG
即:
if(0 == R0) {
goto __BACKUP_REG
}
SVC 軟中斷指令
指令格式:SVC 立即數(shù)
例:SVC #0
這條指令將產(chǎn)生一次軟中斷,并將立即數(shù)0存入指令中,這個(gè)立即數(shù)可以作為軟中斷號(hào)使用,軟中斷服務(wù)程序可以通過這個(gè)立即數(shù)區(qū)分不同的軟中斷服務(wù)。
匯編代碼示例
父函數(shù)向子函數(shù)傳6個(gè)參數(shù),子函數(shù)將其參數(shù)之和返回,父函數(shù)將返回值 +7后的值,當(dāng)做自己的返回值返回。
TestFunc1
TestFunc1
;需使用R4,R5寄存器,為避免破壞R4,R5寄存器中的數(shù)據(jù),將其壓棧
PUSH {R4 - R5}
LDR R0, =1 ;相當(dāng)于 R0 = 1
LDR R1, =2
LDR R2, =3 ;R0~R3寄存器作為接口寄存器,可直接使用
LDR R3, =4
LDR R4, =5
LDR R5, =6
;R4,R5寄存器壓棧,是因?yàn)樗鼈兪亲鳛榈?,6個(gè)入口參數(shù),需要棧傳遞
;R14(LR)寄存器壓棧,是因?yàn)門estFunc2的返回地址將被存入LR寄存器,防止 LR 寄存器中現(xiàn)有數(shù)據(jù)破壞
PUSH {R4 - R5, R14}
BL TestFunct2 ;跳轉(zhuǎn)到 TestFunc2函數(shù)
ADD R0, #7 ;TestFunc2函數(shù)的返回值保存在R0寄存器,將其 +7
;恢復(fù)進(jìn)入TestFunt1函數(shù)現(xiàn)場(chǎng)
;將 SP指針向棧頂方向移動(dòng) 8個(gè)字節(jié),跳過原來存入棧中的2個(gè)入口參數(shù)
;此時(shí) SP指針指向的棧中存放的是調(diào)用TestFunc2函數(shù)前存入的 LR寄存器
ADD SP, #8
POP {R14} ;彈出 LR寄存器,將其恢復(fù)到進(jìn)入 TestFunc1函數(shù)前的數(shù)值
POP {R4 - R5} ;彈出 R4,R5寄存器,將其恢復(fù)到進(jìn)入 TestFunc1函數(shù)前的數(shù)值
BX R14 ;函數(shù)執(zhí)行完畢,此時(shí) R14保存的是TestFunc1函數(shù)的返回地址
TestFunc2
TestFunc2
ADD R0, R1
ADD R0, R2
ADD R0, R3
POP {R1, R2} ;從棧中取出第5,6參數(shù),將其值賦給R1,R2寄存器
ADD R0, R1
ADD R0, R2
SUB SP, #8 ;POP時(shí)移動(dòng)棧指針,現(xiàn)在恢復(fù)到進(jìn)入此函數(shù)之前棧指針指向
BX R14
C語言原型文章來源:http://www.zghlxwxcb.cn/news/detail-779020.html
char TestFunc1() {
return TestFunc2(1, 2, 3, 4, 5, 6) + 7;
}
char TestFunc2(char p1, char p2, char p3, char p4, char p5, char p6) {
return p1 + p2 + p3 + p4 + p5 + p6;
}
本文內(nèi)容為閱讀《嵌入式操作系統(tǒng)內(nèi)核調(diào)度-底層開發(fā)者手冊(cè)》筆記,如有侵權(quán),請(qǐng)聯(lián)系刪除。文章來源地址http://www.zghlxwxcb.cn/news/detail-779020.html
到了這里,關(guān)于ARM匯編寄存器和常用指令詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!