arm b bl 地址无关码_ARM汇编语言入门(六)
Part 6:條件狀態和分支
在探討CPSR時我們已經接觸了條件狀態。我們通過跳轉(分支)或者一些只有滿足特定條件才執行的指令來控制程序在運行時的執行流。通過CPSR寄存器中的特定bit位來表示條件狀態。這些位根據指令每次執行的結果而不斷變化。例如,比較運算時如果兩個數相等,那么就置CPSR中的Zero位(Z=1),實際上是因為:a - b = 0,這種情況下就是相等狀態。如果第一個數大,那么就是大于狀態。如果第二個數大,就是小于狀態。除此之外,還有小于等于、大于等于等等。
下面的表格列出了可用的條件狀態碼,描述和標志位:
在下面代碼片段中看一下執行條件加法時的實際用法L:
.global main ? main:mov r0, #2 /* 初始化變量 */cmp r0, #3 /* 將R0中的值與3比較,負數位置1 */addlt r0, r0, #1 /* 如果上一條比較結果是小于(查看CPSR),則將R0加1 */cmp r0, #3 /* 將R0中的值再與3比較, 零位置1,同時負數位重置為0 */addlt r0, r0, #1 /* 如果上一條比較結果是小于(查看CPSR),則將R0加1 */bx lr第一條cmp指令結果導致CPSR中的負數位置1(2- 3 = -1)意思是R0小于R3。因為滿足小于條件(CPSR中的溢出位不等于負數位V != N)所以接下來的ADDLT指令執行。在執行下一條cmp指令時,R0 = 3。所以清除負數位(3 - 3 = 0,負數位清零),零位置位(Z = 1)。現在溢出位是0,負數位是0,不滿足小于條件。所以最后一條ADDLT指令不執行,R0值保持3不變。
Thumb模式下的條件執行
我們在介紹指令集的章節討論了Thumb狀態下的不同。具體而言是Thumb-2版本支持條件執行。某些 ARM 處理器版本支持"IT"指令,允許在 Thumb 狀態下支持多達4個條件執行指令。參考:http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/BABIJDIC.html。
語法:IT{x{y{z}}} cond
- cond 指定 IT 塊的第一個指令的條件。
- x 指定 IT 塊中第二個指令的條件開關。
- y 指定 IT 塊中第三個指令的條件開關。
- z 指定 IT 塊中第四個指令的條件開關。
其實IT指令的結構就是“IF-Then-(Else)”,語法都是由字母“T”和“E”構成:
- IT:If-Then(下一條指令是條件的);
- ITT:If-Then-Then(后兩條指令是條件的);
- ITE:If-Then-Else(后兩條指令是條件的);
- ITTE:If-Then-Then-Else(后三條指令是條件的);
- ITTEE:If-Then-Then-Else-Else(后四條指令是條件的);
IT塊中的每條指令必須指定相同或邏輯相反的條件后綴。意思是,如果使用ITE,那么前兩個指令必須有相同的后綴,而第三個必須是邏輯相反的后綴。下面是 ARM 參考手冊中的一些示例,說明了這些邏輯:
ITTE NE ; 接下來的3條指令都是有條件的。 ANDNE R0, R0, R1 ; ANDNE不更新條件標志。 ADDSNE R2, R2, #1 ; ADDSNE更新條件標志。 MOVEQ R2, R3 ; 有條件的移動 ? ITE GT ; 接下來的2條指令都是有條件的。 ADDGT R1, R0, #55 ; 條件滿足大于時進行相加。 ADDLE R1, R0, #48 ; 條件不滿足大于時進行相加。 ? ITTEE EQ ; 接下來的4條指令都是有條件的。 MOVEQ R0, R1 ; 有條件的MOV ADDEQ R2, R2, #10 ; 有條件的ADD ANDNE R3, R3, #1 ; 有條件的AND BNE.W dloop ; 分支指令只能在IT塊的最后一個指令中使用。錯誤示例:
IT NE ; 下一條指令是條件的。 ADD R0, R0, R1 ; 語法錯誤,不是有條件的指令。下面是條件代碼和相反代碼:
現在使用以下代碼來測試:
.syntax unified @ 非常重要! .text .global _start ? _start:.code 32add r3, pc, #1 @ PC的值加1并存儲到R3。bx r3 @ 跳轉到R3中的地址處,并切換運行模式 ->切換到Thumb模式,因為R3最低有效位(LSB) = 1。 ?.code 16 @ Thumb模式cmp r0, #10 ite eq @ 如果R0等于10...addeq r1, #2 @ ... 那么 R1 = R1 + 2addne r1, #3 @ ... 否則 R1 = R1 + 3bkpt.code 32
示例中的代碼開始在ARM模式下,第一條指令將PC中的地址值加1并存儲到R3,然后bx指令跳轉到R3中的地址位置,并且模式切換成Thumb模式,因為R3中的值最低有效位為1(0不切換)。為此使用bx(分支+交換)非常重要。
.code 16
在Thumb模式下,首先比較R0和10,結果將負數位N置位(0 - 10 = -10)。之后使用If-Then-Else塊,因為零位Z(Zero)沒有被置位所以ADDEQ指令被跳過,然后因為結果不相等所以執行ADDNE指令。
在 GDB 中單步執行此代碼會干擾結果,因為你要在 ITE 塊中執行這兩個指令。 但是,在 GDB 中運行代碼而不設置斷點并單步執行每個指令將生成正確的結果設置 R1 = 3。
分支
分支(跳轉)允許我們跳轉到另一個代碼段。當你需要跳過(或者重復)某塊代碼或者跳轉到指定的函數的時候,分支很有用。此類情形中最佳的示例是IF和循環。先來看看IF案例。
.global main ? main:mov r1, #2 /* 設置初始變量a */mov r2, #3 /* 設置初始變量b */cmp r1, r2 /* 比較兩個變量值看哪個更大 */blt r1_lower /* 因為R2更大(N==1),跳轉到r1_lower */mov r0, r1 /* 如果沒有跳轉, 例如R1的值更大(或者相等),則將R1的值存儲到R0 */b end /* 結束 */ r1_lower:mov r0, r2 /* R1小于R2時跳轉到此處, 將R2的值存儲到R0 */b end /* 結束 */ end:bx lr /* THE END */上面代碼是比較兩個初始值并返回最大值,C語言偽代碼:
int main() {int max = 0;int a = 2;int b = 3;if(a < b) {max = b;}else {max = a;}return max; }現在再看一下怎么使用條件分支實現循環:
.global main ? main:mov r0, #0 /* 設置初始變量a */ loop:cmp r0, #4 /* 比較a==4 */beq end /* 如果a==4,結束 */add r0, r0, #1 /* 否則將R0中的值遞增1 */b loop /* 跳轉到loop開始位置 */ end:bx lr /* THE END */C語言偽代碼:
int main() {int a = 0;while(a < 4) {a= a+1;}return a; }B、BX、BLX指令
有三種類型的分支指令:
- 普通分支(B)
- 簡單的跳轉到一個函數。
- 帶鏈接的跳轉(BL)
- 將PC+4的值保存到LR寄存器,然后跳轉。
- 帶狀態切換的跳轉(BX)和帶狀態切換及鏈接的跳轉(BLX)
- 與B和BL一致,只是添加了工作狀態的切換(ARM模式-Thumb模式)。
- 需要寄存器作為第一個操作數。
BX、BLX用來切換ARM模式到Thumb模式。
.text .global _start ? _start:.code 32 @ ARM modeadd r2, pc, #1 @ put PC+1 into R2bx r2 @ branch + exchange to R2 ?.code 16 @ Thumb modemov r0, #1這里的技巧是獲得當前PC的值,加1然后保存到一個寄存器,然后跳轉(并且切換狀態模式)到這個寄存器內的地址。可以看到加指令(add r2, pc, #1)獲取到有效的PC地址值(當前PC內的值+8=0x805C)然后加1(0x805C + 1 = 0x805D)。接下來,我們跳轉的地址( 0x805D = 10000000 01011101)最低有效位為1,那么意味著地址不是4字節(32bit)對齊的。跳轉到這樣的地址不會導致非對齊問題。在GDB中運行的樣子(含GEF):
注意上面的gif圖片是在低版本的GEF下創建的,所以你的顯示界面可能不一樣,但是邏輯是一樣的。
條件分支
分支也可以有條件地執行,用于在滿足特定條件時跳轉到函數。我們看一個使用BEQ應用條件分支的例子,這是一段沒太有用的匯編代碼,只不過是在寄存器等于特定值時將一個值移動到寄存器并跳轉到另一個函數的過程。
.text .global _start ? _start:mov r0, #2mov r1, #2add r0, r0, r1cmp r0, #4beq func1add r1, #5b func2 func1:mov r1, r0bx lr func2:mov r0, r1bx lr<end>
總結
以上是生活随笔為你收集整理的arm b bl 地址无关码_ARM汇编语言入门(六)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c语言按照姓名查询员工信息,输入10个职
- 下一篇: github打开前端样式丢失_工具资源系