b或bl指令引起處理器轉移到「子程式名(也就是位址)」處開始執行,這兩個指令都是相對跳轉指令。兩者的不同之處在於bl指令在轉移到子程式執行之前,將其下一條指令的位址拷貝到r14(lr,鏈結暫存器)。由於bl指令儲存了下條指令的位址,因此使用指令「mov pc ,lr」即可實現子程式的返回。
而b指令則無法實現子程式的返回,只能實現單純的跳轉。如在中斷向量表中就只能用b跳轉指令,因為它不要返回。而常用的分支語句則用bl指令。位是條件碼
;[27:24]
位為「1010」
(0xeaffffff)時
,表示b
跳轉指令
,為「1011」
時,表示
bl跳轉指令;
[23:0]
表示偏移位址。
使用b或bl
跳轉時,下一條指令的位址是這樣計算的:
將指令中24位帶符號的補碼立即數擴充套件為
32(擴充套件其符號位
);將此
32位數左移兩位;將得到的值加到
pc暫存器中,即得到跳轉的目標位址。
該指令完成的操作是pcb跳轉指令是相對跳轉
,依賴當前pc的值,偏移量是通過該指令本身的 bit[23:0]算出來的,這使得使用b指令的程式不依賴於要跳到的**的位置,只看指令本身。即該分支指令的二進位製碼的後24位的實際的值是相對當前 的 r15 的值的乙個偏移量;而不是乙個絕對位址,
即跳轉時pc的值是以pc=pc+/-n的方式來改變的
。它的值由彙編器來計算,它是 24 位有符號數,左移兩位後有符號擴充套件為 32 位,表示的有效偏移為 26 位(+/- 32 m)。
例程:1.text
2.global _start
3_start:
4 b step1
5 step1:
6 ldr pc, =step2
7 step2:
8 b step2
反彙編**:
0: eaffffff b 0x4
4: e59ff000 ldr pc, [pc, #0] ; 0xc
8: eafffffe b 0x8
c: 30000008 tsteq r0, #8 ; 0x8
b跳轉指令:它是個相對跳轉指令,其機器碼格式如下:
[31:28]位是條件碼
;[27:24]
位為「1010」
(0xeaffffff
為一條指令的二進位制
機器碼)
時,表示
b跳轉指令
,為「1011」
時,表示
bl跳轉指令;
[23:0]
表示乙個相對於
pc的偏移位址。
將指令中
24位帶符號的補碼立即數擴充套件為
32(擴充套件其符號位
);將此
32位數左移兩位;將得到的值加到
pc暫存器中,即得到跳轉的目標位址。
我們看看第一條指令「b step1」
的機器碼
0xeaffffff
:
1.24位帶符號的補碼為
0xffffff
,將它擴充套件為
32得到:
0xffffffff
2.將此32
位數左移兩位得到:
0xfffffffc
,其值就是-4(
0xfffffffc
符號位不變,其餘位取反再加1得到
-4);
3.pc的值是當前指令的
下兩條(
下一條的下一條
)指令的位址,加上步驟
2得到的-4(
pc-4
,即pc回退4
個位元組,剛好指向當前指令的下一條指令上)
,這恰好是第二條指令
step1
的位址。
不要被被反彙編**中的「b 0x4」
給迷惑了,它可不是說跳到絕對位址
0x4處執行,絕對位址得像上述
3個步驟那樣計算。
助記符
說 明
操 作
b
跳轉指令
pc←label
bl
帶返回的連線跳轉
pc←label(lr←bl後面的第一條指令)
bx
跳轉並切換狀態,絕對位址
pc←rm&0xfffffffe, t←rm&1
blx
帶返回的跳轉並切換狀態
pc←lable, t←1pc←rm&0xfffffffe, t←rm&1
lr←bl後面的第一條指令
它們是儲存器訪問指令。arm中對rom,ram,io位址採用統一編址,
除ram外,對外圍io、程式資料的訪問都要採用l/s指令進行操作。ldr用於把記憶體中的資料載入到暫存器中,而str則相反。
ldr r0, [r1] ,把r1所指向的儲存單元的內容載入到r0暫存器中
比如 str r0, [r1] ,意思是r0-> [r1],它把源暫存器寫在前面,跟mov、ldr都相反。
ldr應該是非常常見了。ldr就是把資料從儲存器傳輸到暫存器上。
例一:@ disable watch dog timer
mov r1, #0x53000000 //立即數定址方式
mov r2, #0x0
str r2, [r1]
立即數定址方式,立即數要求以「#」作字首,對於十六進製制的數,還要求在#後面加上0x或者&。
有個偽指令也是ldr,與之前的ldr載入命令相同。看這段**:
mov r1, #gpio_ctl_base
add r1, r1, #ogpio_f
ldr r2,=0x55aa // 0x55aa是個立即數啊,前面加個=幹什麼?
對於當中的ldr 那句,如果你把=去掉,是不能通過編譯的。
這個=應該表示ldr不是arm指令,而是偽指令。作為偽指令的時候,ldr的格式如下:ldr 暫存器, =數字常量/label
它的作用是把乙個32位的位址或者常量調入暫存器。嗬嗬,那大家可能會問,
「mov r2,#0x55aa」也可以啊。應該是這樣的。不過,ldr是偽指令啊,
也就是說編譯時編譯器會處理它的。怎麼處理的呢?——規則如下:
如果該數字常量在mov指令範圍內,彙編器會把這個指令作為mov。
如果不在mov範圍中,彙編器把該常量放在程式後面,
用ldr來讀取,pc和該常量的偏移量不能超過4kb。
ldm把一塊連續記憶體單元的資料載入到多個暫存器中 ldmrn,stm把多個暫存器的內容儲存到一塊連續的記憶體單元中。stmrn,
con如ia,fd
rn為基址暫存器,它不能為pc !表示是否要改變rn的值。
ldmia r0,,把【r0】開始的四個字載入到r1-r4中,
但r0的值沒有變。如果為r0!,則最後r0=r0+4*4
arm中對程式狀態暫存器的操作由上述兩條專用指令實現,而不能由其它指令,實現 「1+2+3+.........+n」mrs 讀程式狀態暫存器
msr 寫程式狀態暫存器。
5.bic,把標誌中的1清0,
area test, code, readonly ;定義乙個**段 test
entry ; 標記第一和可以執行的**位置
start
mov r0, #0 ;r0=0
ldr r1, =n ; r1=n
begin
add r0, r0, r1 ;累加,r0=r0 + r1
subs r1, r1, #1 ;將r1減1,影響標誌位
bne begin ;如果r1不為0,則迴圈加,否則退出
stop
b stop ;讓程式停止,此時r0裡面就是結果
end
arm彙編指令
一般arm官方風格彙編指令為大寫,windows ads mdk 實際運用一般用gnu風格,為小寫,linux 1 arm採用risc架構,cpu本身不能直接讀取內 存,而需要先將記憶體中內容加載入cpu中通用寄 存器中才能被 cpu處理 ldr loadregister 指令 將記憶體內容加載入通...
ARM彙編指令
1.彙編概述 2.指令分類學習 3.偽指令 4.協處理訪問指令 為什麼要學習使用匯程式設計序?bootloader kernel的初始化和需要執行效率極高的程式中 1.arm標準彙編 2.gnu彙編 section.data 初始化的資料 section.bss 未初始化的資料 section.te...
arm彙編指令
加法指令 add r1,r2,r3 r1 r2 r3 帶進製加法 adc r1,r2,r3 r1 r2 r3 c 減法指令 sub r1,r2,r3 r1 r2 r3 逆向減法 rsb r1,r2,r3 r1 r3 r2 帶借位減法 sbc r1,r2,r3 r1 r2 r3 c 帶錯位逆減法 rs...