arm堆棧操作

發(fā)布時(shí)間:2012-9-17 18:48    發(fā)布者:a861388037
關(guān)鍵詞: arm
arm堆棧操作
arm堆棧的組織結構是 滿(mǎn)棧降 的形式,滿(mǎn)棧即sp是要停留在最后一個(gè)進(jìn)棧元素,降:就是堆棧的增長(cháng)方向是從高地址向低地址發(fā)展。
arm對于堆棧的操作一般采用 LDMFD(pop)和STMFD (push) 兩個(gè)命令。
以前困惑的就是STMFD 命令 對于操作數 是按照什么順序壓棧的
比如:STMFD sp!{R0-R5,LR} 進(jìn)棧順序是:
高地址(1方式)
LR
R5
R4
```````
R0   <-sp
低地址
還是:
高地址(2方式)
R0
R1
```
R5
LR <-sp
低地址
現在通過(guò)下表,可以輕松的解決這個(gè)問(wèn)題:

尋址方式


說(shuō)明


pop


=LDM


push


=STM


FA


遞增滿(mǎn)


LDMFA


LDMDA


STMFA


STMIB


FD


遞減滿(mǎn)


LDMFD


LDMIA


STMFD


STMDB


EA


遞增空


LDMEA


LDMDB


STMEA


STMIA


ED


遞減空


LDMED


LDMIB


STMED


STMDA

按照圖表,可知 STMFD對應的是STMDB,根據arm指令手冊,可知STMDB入棧順序是(1方式)
而LDMFD對應的是LDMIA,這樣這兩個(gè)操作就可以成功配對:
以下是我在學(xué)習ARM指令中記錄的關(guān)于堆棧方面的知識

1、寄存器 R13 在 ARM 指令中常用作堆棧指針
  2、對于 R13 寄存器來(lái)說(shuō),它對應6個(gè)不同的物理寄存器,其中的一個(gè)是用戶(hù)模式與系統模式共用,另外5個(gè)物理寄存器對應于其他5種不同的運行模式。采用以下的記號來(lái)區分不同的物理寄存器: R13_ 其中,mode為以下幾種模式之一:usr、fiq、irq、svc、abt、und。

  3、寄存器R13在A(yíng)RM指令中常用作堆棧指針,但這只是一種習慣用法,用戶(hù)也可使用其他的寄存器作為堆棧指針。而在Thumb指令集中,某些指令強制性的要求使用R13作為堆棧指針。由于處理器的每種運行模式均有自己獨立的物理寄存器R13,在用戶(hù)應用程序的初始化部分,一般都要初始化每種模式下的R13,使其指向該運行模式的?臻g,這樣,當程序的運行進(jìn)入異常模式時(shí),可以將需要保護的寄存器放入R13所指向的堆棧,而當程序從異常模式返回時(shí),則從對應的堆棧中恢復,采用這種方式可以保證異常發(fā)生后程序的正常執行。

  4、有四種類(lèi)型的堆棧:

  堆棧是一種數據結構,按先進(jìn)后出(First In Last Out,FILO)的方式工作,使用一個(gè)稱(chēng)作堆棧指針的專(zhuān)用寄存器指示當前的操作位置,堆棧指針總是指向棧頂。

  當堆棧指針指向最后壓入堆棧的數據時(shí),稱(chēng)為滿(mǎn)堆棧(Full Stack),而當堆棧指針指向下一個(gè)將要放入數據的空位置時(shí),稱(chēng)為空堆棧(Empty Stack)。

  同時(shí),根據堆棧的生成方式,又可以分為遞增堆棧(Ascending Stack)和遞減堆棧(DecendingStack),當堆棧由低地址向高地址生成時(shí),稱(chēng)為遞增堆棧,當堆棧由高地址向低地址生成時(shí),稱(chēng)為遞減堆棧。這樣就有四種類(lèi)型的堆棧工作方式,ARM 微處理器支持這四種類(lèi)型的堆棧工作方式,即:
       ◎ Full descending 滿(mǎn)遞減堆棧堆棧首部是高地址,堆棧向低地址增長(cháng)。棧指針總是指向堆棧最后一個(gè)元素(最后一個(gè)元素是最后壓入的數據)。 ARM-Thumb過(guò)程調用標準和ARM、Thumb C/C++ 編譯器總是使用Full descending 類(lèi)型堆棧。<這是什么原因呢?>

  ◎ Full ascending 滿(mǎn)遞增堆棧堆棧首部是低地址,堆棧向高地址增長(cháng)。棧指針總是指向堆棧最后一個(gè)元素(最后一個(gè)元素是最后壓入的數據)。

  ◎ Empty descending 空遞減堆棧堆棧首部是低(這里是不是錯了,應該是高地址吧)地址,堆棧向高地址增長(cháng)。棧指針總是指向下一個(gè)將要放入數據的空位置。

  ◎ Empty ascending 空遞增堆棧堆棧首部是高地址,堆棧向低地址增長(cháng)。棧指針總是指向下一個(gè)將要放入數據的空位置。

  5、操作堆棧的匯編指令堆棧類(lèi)型 入棧指令 出棧指令 Full descending STMFD (STMDB) LDMFD (LDMIA) Full ascending STMFA (STMIB) LDMFA (LDMDA) Empty descending STMED (STMDA) LDMED (LDMIB) Empty ascending STMEA (STMIA) LDMEA (LDMDB)

  例子: STMFD r13!, {r0-r5} ; Push onto a Full Descending Stack LDMFD r13!, {r0-r5} ; Pop from a Full Descending Stack.
例子
1) 保護現場(chǎng)參數,不影響PC,嵌匯編的時(shí)候對之前的存參數的寄存器R0~R12保存
STMFD r13!, {r0-r7,LR}
LDMFD r13!, {r0-r7,PC}
2)  ARM匯編中lr(r14)寄存器的作用
lr(r14)的作用問(wèn)題,這個(gè)lr一般來(lái)說(shuō)有兩個(gè)作用:
1.當使用bl或者blx跳轉到子過(guò)程的時(shí)候,r14保存了返回地址,可以在調用過(guò)程結尾恢復。
2.異常中斷發(fā)生時(shí),這個(gè)異常模式特定的物理R14被設置成該異常模式將要返回的地址。

另外注意pc,在調試的時(shí)候顯示的是當前指令地址,而用mov lr,pc的時(shí)候lr保存的是此指令向后數兩條指令的地址,大家可以試一下用mov pc,pc,結果得到的是跳轉兩條指令,這個(gè)原因是由于arm的流水線(xiàn)造成的,預取兩條指令的結果.
3.我們看到的LR值是上一個(gè)子程序調用保存的子程序返回地址,這個(gè)LR是要賦給PC的。
  嵌入式匯編要手動(dòng)保存返回地址,進(jìn)行現場(chǎng)保護。
  PC記錄當前運行的地址。下一條回自己+4
  進(jìn)入子程序,LR才自動(dòng)更新為返回地址值,PC為程序運行地址
ARM匯編嵌套子程序
幾個(gè)星期前閱讀了(加)Carl Hamacher、 Zvonko Vranesic、 Safwat Zaky編寫(xiě)的《計算機組成》第五版中的ARM子程序調用的一些知識,啟發(fā)很大,順便將它整理了一下并加入了自己的理解。
子程序
1 通過(guò)寄存器傳遞參數
BL指令通常用于調用一個(gè)子程序。它和B指令的區別在于它將返回地址裝載到R14中。由于子程序可能是嵌套的,因此LR的內容必須保存在子程序所使用的堆棧中。
下面的例子使用寄存器傳遞參數。調用者通過(guò)寄存器R1和R2分別將數組的大小和數組的首地址傳遞給子程序;子程序利用寄存器R0將和傳遞給調用者。該子程序使用了寄存器R3,必須將它和LR推入堆棧。
調用程序
LDR R1, N
LDR R2, POINTER
BL  LISTADD
STR R0, SUM
子程序
LISTADD  STMFD  R13!, {R3, R14}
MOV  R0, #0
LOOP LDR  R3, [R2], #4
ADD  R0, R0, R3
SUBS  R1, R1, #1
BGT  LOOP
LDMFD R13!, {R3, R15}
注:這里并沒(méi)有遵守APCS(ARM過(guò)程調用標準),一般由調用者負責保存R0~R3,被調用者負責保存其他的寄存器以使調用返回后程序的狀態(tài)不被破壞。
2 通過(guò)堆棧傳遞參數
調用程序
LDR R0, POINTER
STR R0, [R13, #-4]! ;將數組首地址推入堆棧
LDR R0, N
STR R0, [R13, #-4]! ;將元素個(gè)數N推入堆棧
BL  LISTADD
LDR R0, [R13, #4] ;將元素和裝載到寄存器R0中
STR R0, SUM
ADD R13, R13, #8 ;恢復堆棧
子程序
LISTADD  STMFD  R13!, {R0-R3, R14}
LDR  R1, [R13, #20]
LDR  R2, [R13, #24]
MOV  R0, #0
LOOP LDR  R3, [R2], #4
ADD  R0, R0, R3
SUBS  R1, R1, #1
BGT  LOOP
STR R0, [R13,#24] ;把和推入堆棧的最深處
LDMFD R13!, {R0-R3, R15}

[R0]


[R1]


[R2]


[R3]


返回地址


N


POINTER/SUM

3 嵌套子程序
當子程序嵌套時(shí),堆棧是用于處理返回地址的最合適的數據結構。當調用子程序時(shí)在堆棧上建立了完整的堆棧結構。應當注意當前子程序的堆棧幀指針所指向的空間中存儲的是調用當前子程序的子程序的堆棧幀指針。調用者將子程序所需要的參數按照順序推入堆棧。子程序首先保存工作寄存器、調用者的堆棧幀指針以及返回地址,然后它計算自己的堆棧幀指針的值(ADD  FP, SP, #16),并利用這個(gè)堆棧幀指針從堆棧幀中獲取調用者傳遞給它的參數。在子程序完成它的任務(wù)之后,它也將返回值保存在堆棧中,此例保存在參數所在的內存單元。調用者和被調用者必須約定好參數的傳遞順序和返回值保存位置。如果返回值比較多的話(huà),調用者要為返回值預先在堆棧中保留合適的空間。
調用程序
2000 LDR   R0, PARAM2
STR   R0, [SP, #-4]! ;將參數推入堆棧
LDR   R0, PARAM1
STR  R0, [SP, #-4]!
BL   SUB1
2020 LDR  R0, [SP] ;保存SUB1的結果
STR  R0, RESULT
ADD  SP, SP, #8 ;恢復堆棧
子程序
2100 SUB1  STMFD  SP!, {R0-R3, FP,LR}
ADD  FP, SP, #16 ;計算幀指針
LDR  R0, [FP, #8] ;載入參數1
LDR  R1, [FP, #12] ;載入參數2
LDR  R2, PARAM3 ;載入參數3
STR  R2, [SP, #-4]! ;將參數3推入堆棧
BL  SUB2
2164 LDR  R2, [SP], #4 ;將SUB2的結果彈出并存儲在R2中,并遞增SP
STR  R3, [FP, #8] ;將結果推入堆棧
LDMFD  SP!, {R0-R3, FP, PC} ;恢復寄存器并返回
3000 SUB2  STMFD  SP!, {R0, R1, FP, LR}
ADD  FP, SP, #8 ;載入結構指針
LDR  R0, [FP, #8] ;載入參數
STR  R1, [FP, #8] ;將結果推入堆棧
LDMFD  SP!, {R0, R1, FP, PC}


[R0] from SUB1


[R1] from SUB1


[FP] from SUB1


2164/返回地址


param3/SUB2的結果最后保存在這里


[R0] from main


[R1] from main


[R2] from main


[R3] from main


[FP] from main


2020/返回地址


param1/SUB1的結果最后保存在這里


param2


原棧頂



3 子程序編譯后都放在哪
嵌匯編子程序:會(huì )在編譯后統一放到一個(gè)地方 系統調用__main()庫函數,
后再進(jìn)入main.c前的初始化C下面的堆棧命令前(這個(gè)堆棧是用來(lái)放置C里參數的)
   嵌匯編子程序:按定義順序放在堆棧前,而C語(yǔ)言子程序,放在初始化堆棧堆棧命令后。

本文地址:http://selenalain.com/thread-97735-1-1.html     【打印本頁(yè)】

本站部分文章為轉載或網(wǎng)友發(fā)布,目的在于傳遞和分享信息,并不代表本網(wǎng)贊同其觀(guān)點(diǎn)和對其真實(shí)性負責;文章版權歸原作者及原出處所有,如涉及作品內容、版權和其它問(wèn)題,我們將根據著(zhù)作權人的要求,第一時(shí)間更正或刪除。
您需要登錄后才可以發(fā)表評論 登錄 | 立即注冊

相關(guān)視頻

關(guān)于我們  -  服務(wù)條款  -  使用指南  -  站點(diǎn)地圖  -  友情鏈接  -  聯(lián)系我們
電子工程網(wǎng) © 版權所有   京ICP備16069177號 | 京公網(wǎng)安備11010502021702
快速回復 返回頂部 返回列表
午夜高清国产拍精品福利|亚洲色精品88色婷婷七月丁香|91久久精品无码一区|99久久国语露脸精品|动漫卡通亚洲综合专区48页