常用-匯編指令


為什么要學匯編程序:在bootloard和linux內核的初始化中都要用到匯編程序。還有一個就是匯編程序的效率更高。
-----------------------------------------
arm匯編的分類:arm標准匯編(windows下ADS),GNU匯編(linux平台)。
---------------------------------------------------
匯編程序的框架: \簡化之后的框架:
.section.data \.text
<初始化數據> \.globle _start
.section.bss \_start:
<未初始化的數據>\ <匯編代碼>
.section.text \
.global _start \
_start: \
<匯編代碼> \
--------------------------------------------------------
建立匯編程序編程環境:
cd/home/smb/program/
mkdir start cd start
vim start.S
.text#表明是代碼段
.globle _start#全局的標號
_start #表明程序的入口
move r1,#1
move r2,#2
move r3,#3
vim
因為我們僅僅只是在內存中調試這個程序,所以我們只要elf格式的文件。不使用鏈接器腳本的方法
all:start.o
arm-linux-ld -Ttext 0x50008000 -o start.elf
#指定代碼段的起始地址
%.o : %.S
arm-linux-gcc -g -o $@ -c $^
clean:
rm *.o *.elf
--------------------------------------------------------
arm指令分類學習:
1.算術和邏輯指令.標准的為大寫
mov :將一個立即數或通用寄存器另外一個寄存器中。
mov <dest>,<op_1> //op_為立即數或通用寄存器,dest只為一個通用寄存器
.text
.global _start
_start
@mov example注釋
mov r1,#8
mov r2,r1
mov r3,#10
--------------------------------------------------
mvn:將一個立即數或通用寄存器中的值取反后傳到另一個目的寄存器中。十進制先加1,然后取反。
mvn r0,#4
@mvn指令范例
mvn r1,#0b10 @0b表二進制
mvn r2,#5
mvn r3,r1
----------------------------------------------------------
sub:將第一個源寄存器中的值減去另一個寄存器中的值或一個立即數,放到目的寄存器中。
sub r0,r1,r2
@sub指令范例
sub r1,#4,#2//編譯器報錯,原因是被減數(#4)不能為立即數應該為mov r2,#4
sub r1,r2,#2
mov r0,#1
sub r3,r1,r0
--------------------------------------------------------
add:將把兩個操作數加起來,把結果放置到目的寄存器中。操作數 1 是一個寄存器,操作數 2 可以是一個寄存器,被移位的寄存器,或一個立即值.
@add范例
add r1, r2, #3
----------------------------------------------------------
and:邏輯與
@add范例:
mov r1,#5
add r2,r1,#0
mov r1,#5
add r2,r1,#1
------------------------------------------------------
bic:位清除;將掩碼1對應的位置清除為0.
@bic范例
bic r0,r0,#%1011
如:r0:0b101111101
掩碼為: 1011
位清除后: 0100
mov r1,#0b101011
bic r2,r1,#0b101
-----------------------------------------------------------
比較指令:
cmp:比較CMP 允許把一個寄存器的內容如另一個寄存器的內容或立即值進行比較。會將比較的結果放到狀態寄存器中cpsr(r15):
N Z C V I F 若結果為負N(negative)就會被置1,結果為零Z會被置1
@cmp指令范例
mov r1,#2
cmp r1,#1 //0x2
mov r1,#2
cmp r1,#3 //0x8
mov r1,#2
cmp r1,#2 //0x6
---------------------------------------------------------
tst:測試位:按位與,如果與的結果為0,CPSR中的Z位會被置1
@tst范例
mov r1,#0b101
tst r1,#0b001 //0x2

mov r1,#0b101
tst r1,#0b10 //0x6
-----------------------------------------------------
為什么要有跳轉的操作:gt(great than 大於)
if(a>b) \mov r1,#6
a-b; \mov r2,#5
else \cmp r1,r2
a+b; \bgt branch1 //若條件滿足跳轉到branch1分支
跳轉指令: \add r3,r1,r2
\ b end //結束跳轉操作
b \branch1:
\sub r3,r1,r2
\end:
\nop //空操作
--------------------------------------------------
bl:帶鏈接返回的跳轉
mov r1,#2 //lr=0x0
cmp r1,#1
b func1 //b指令無法讓lr寄存器記錄下條指令的地址,bl可以 。bl func1 //lr=0x000800c
mov r1,#2
cmp r1,#3
func1:
mov r1,#2
mov r2,#3
mov pc,lr //賦值給pc指針,使用bl指令可返回到mov r1,#2,b卻不行。
-----------------------------------------------------------
移位指令:
lsl:邏輯左移
@lsl指令范例
mov r1,#0b1
mov r1,r1,lsl#2 //0b100
---------------------------------------------------
ror:循環右移
@ror范例
mov r1,#0b11
mov r1,r1,ror#1 //0b100000000000000000000000001
--------------------------------------------------
程序狀態字訪問指令
msr:搬回 mrs:搬出;s為狀態寄存器,源在后,所以它是搬出
如何訪問程序狀態寄存器:首先把程序狀態寄存器通過專業指令把狀態寄存器中的值搬移到通用寄存器當中,然后再通用寄存器中修改值,修改完了之后再用專用指令將該值搬回程序狀態寄存器當中。
@程序狀態字寄存器
mrs r0,cpsr
orr r0,#0b100 //邏輯或
msr cpsr,r0
-----------------------------------------------------
存儲器訪問指令
ldr:將內存中的內容導出到寄存器中
str:將寄存器中的值保存到內存中
mov r0,#0xff
str r0,[r1] 將寄存器r0中的值保存到r1內存中
ldr r2,[r1] //將r1中的值保存到r2中。//0xff
arm-linux-objdump -D -S start.elf
30008008 e58100000(arm機器碼) str r0,[r1]
-------------------------------------------------
打開文檔ARM Architecture Reference Manual
先提取兩條匯編指令的機器碼
mov r0,r1
機器碼:e1a00001將其轉成二進制位:1110 00 0 1101 0 0000 0000 000000000001,用的r1寄存器。
moveq r0,#0xff`
機器碼:03a000ff將其轉成二進制位:0000 00 1 1101 0 0000 0000 000011111111
將機器碼和文檔中116頁機器碼格式對比112
cond uncondition:1110 EQ:0000
保留位
i:如果0-11位存的是一個立即數i=1,寄存器i=0:相對於標志位。
opcode:區別不同的指令(mov,ldr等)
S:表明是否影響狀態寄存器(cpsr)
Rn:mov並沒有使用Rn
Rd:目的寄存器,寄存器的編號(如r1:0001)
shifter_operand:源操作數
易知我們源操作數的大小是有限制的,因此立即數的大小超過了這個限制以后,這個指令就會報錯,如何解決呢?我們引入了偽指令。
-----------------------------------------------------
定義類偽指令:它是一個指令,在編譯的時候起作用(或轉化為其它實際指令運行),但不會產生對應的機器碼。
-----------------------------------------------------
.global:表明一個全局的符號;
.data:定義數據段,表明接下來的數據將存入數據段
oscii:
實例:
.data
hello: //標號
.ascii "hello world"
bh:
byte 0x1
ADD:
.word 0xff
--------------------------------------
equ:
_start:
.equ DA.0x89 //定義了一個宏DA,它的值為0x89
mov r0,#DA
----------------------------------------------
align:接下來的地址按4字節對齊
.align 4
------------------------------------------------------
操作類偽指令

.text
.global _start
_start
mov r0,#0x1ff(mov能使用的立即數不能超過8位)此處會報錯。
shift_operand中的12位,其中有4位要留下了用於左右移位用的,因此立即數不能超過4位。解決辦法:
ldr r0,=0x1ff //在ldr中用=表示立即數
arm-linux-objdump -D -S start.elf
找到:ldr偽指令,經過轉換之后變成了ldr r0,[pc,#-4(當前的pc指針減去4)]
----------------------------------------------------
nop:空操作,反匯編可在實際執行的是mov r0,r0
------------------------------------------------
協處理器訪問指令
什么是協處理器(CP15:co-processor):用於執行特定的處理任務,以減輕處理器的負擔。如:數學協處理器可以控制數字處理。ARM可支持多大16組協處理器,CP15最重要。
CP15作用:起到系統控制的作業,通過cpu提供的16組寄存器來對他進行訪問
----------------------------------------------------------
協處理器訪問:
mcr:將通用寄存器中的值復制到協處理器中
mrc:把協處理器中的搬到通用寄存器中。
r:表示通用寄存器,c:co-processor,
訪問格式:
mcr{cond} P15,<Opcode_1>,<Rd>,<CRm>,<Opcode_2>
mrc{}............................................
Rd:目的寄存器
其他幾個參數的確定:見手冊:Arm1176 p146頁
如訪問Main ID寄存器:mcr p15,0,r0,c0,c0,0

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM