嵌入式Linux+ARMARM體系結(jié)構(gòu)與編程(ARM匯編指令)
1.匯編系統(tǒng)預(yù)定義的段名
本文引用地址:http://butianyuan.cn/article/201611/317792.htm.text @代碼段
.data @初始化數(shù)據(jù)段
.bss @未初始化數(shù)據(jù)段
需要注意的是,源程序中.bss段應(yīng)該在.text之前。
2.定義入口點
匯編程序的缺省入口是 start標號,用戶也可以在連接腳本文件中用ENTRY標志指明其它入口點。
.text
.global _start
_start:
3 .word用法
word expression就是在當(dāng)前位置放一個word型的值,這個值就是expression
舉例來說,
_rWTCON:
.word 0x15300000
就是在當(dāng)前地址,即_rWTCON處放一個值0x15300000
4.equ賦值操作,相當(dāng)于c語言的宏定義
.equ MEM_CTRL_BASE, 0x48000000 //注意要加,號
5. 邏輯指令
AND―――――邏輯"與"操作指令
ANDS R1,R1,R2 ;R1=R1&R2,并根據(jù)運算的結(jié)果更新標志位
AND R0,R0,#0x0F ;R0=R0&0x0F,取出R0最低4位數(shù)據(jù)。
指令格式:ORR{cond}{S} Rd,Rn,operand2 ORR指令將操作數(shù)operand2 與Rn 的值按位邏輯"或",結(jié)果存放到目的寄存器Rd 中。指令示例:
ORRS R1,R1,R2 ;R1=R1|R2,并根據(jù)運算的結(jié)果更新標志位
指令格式:
BIC{cond}{S} Rd,Rn,operand2
cmp R0,R1 ;比較R0,R1
beq stop ;R0=R1跳到stop
blt less ;R0
Stop:...
參考:
http://blog.csdn.net/denlee/article/details/2501182
在嵌入式開發(fā)中,匯編程序常常用于非常關(guān)鍵的地方,比如系統(tǒng)啟動時的初始化,進出中斷時的環(huán)境保存、恢復(fù),對性能要求非??量痰暮瘮?shù)等。
1、相對跳轉(zhuǎn)指令:b、bl
不同之處在于:bl指令除了跳轉(zhuǎn)之外,還將返回地址(bl的下一條指令的地址)保存在lr寄存器中。
跳轉(zhuǎn)范圍:當(dāng)前指令的前后32M。
它們是與位置無關(guān)的指令。
示例:
b fun1
......
fun1:
bl fun2
......
fun2:
......
2、數(shù)據(jù)傳送指令:mov,地址讀取偽指令:ldr
mov指令可以把一個寄存器的值賦給另一個寄存器,或者把一個常數(shù)賦給寄存器。
例:
mov r1, r2
mov r1, #4096
mov指令傳送的常數(shù)必須能用立即數(shù)來表示。
當(dāng)不知道一個數(shù)能否用立即數(shù)來表示時,可以使用ldr命令來賦值。ldr是偽指令,它不是真實存在的指令,編譯器會把它擴展成真正的指令:如果該常數(shù)能用立即數(shù)來表示,則使用mov指令;否則編譯時將該常數(shù)保存在某個位置,使用內(nèi)存讀取指令把它讀出來。
例:
ldr r1, =4097
ldr本意為“大范圍的地址讀取偽指令”,以下是獲得代碼的絕對地址:
例:
ldr r1, =label
label:
......
3、內(nèi)存訪問指令:ldr、str、ldm、stm
ldr指令既可能是大范圍的地址讀取偽指令,也可能是內(nèi)存訪問指令。當(dāng)它的第二個參數(shù)前面有“ = ”時,表示偽指令,否則表示內(nèi)存訪問指令。
ldr指令是從內(nèi)存中讀取數(shù)據(jù)到寄存器,str指令把寄存器的值存儲到內(nèi)存中,它們操作的數(shù)據(jù)都是32位的。
例:
ldr r1, [r2, #4] // 將地址為r2+4的內(nèi)存單元數(shù)據(jù)讀取到r1中
ldr r1, [r2] // 將地址為r2的內(nèi)存單元數(shù)據(jù)讀取到r1中
ldr r1, [r2], #4 // 將地址為r2的內(nèi)存單元數(shù)據(jù)讀取到r1中,然后r2=r2+4
str r1, [r2, #4] // 將r1的數(shù)據(jù)保存到地址為r2+4的內(nèi)存單元中
str r1, [r2] // 將r1的數(shù)據(jù)保存到地址為r2的內(nèi)存單元中
str r1, [r2], #4 // 將r1的數(shù)據(jù)保存到地址為r2的內(nèi)存單元中,然后r2=r2+4
ldm和stm屬于批量內(nèi)存訪問指令,只用一條指令就可以讀寫多個數(shù)據(jù)。格式為:
ldm {cond}
stm {cond}
其中,{cond}表示指令的執(zhí)行條件有:
條件碼(cond) | 助記符 | 含義 | cpsr中條件標志位 |
0000 | eq | 相等 | Z = 1 |
0001 | ne | 不相等 | Z = 0 |
0010 | cs/hs | 無符號數(shù)大于/等于 | C = 1 |
0011 | cc/lo | 無符號數(shù)小于 | C = 0 |
0100 | mi | 負數(shù) | N = 1 |
0101 | pl | 非負數(shù) | N = 0 |
0110 | vs | 上溢出 | V = 1 |
0111 | vc | 沒有上溢出 | V = 0 |
1000 | hi | 無符號數(shù)大于 | C = 1或Z = 0 |
1001 | ls | 無符號數(shù)小于等于 | C = 0或Z = 1 |
1010 | ge | 帶符號數(shù)大于等于 | N = 1, V = 1或N = 0, V = 0 |
1011 | lt | 帶符號數(shù)小于 | N = 1, V = 0或N = 0, V = 1 |
1100 | gt | 帶符號數(shù)大于 | Z = 0且N = V |
1101 | le | 帶符號數(shù)小于/等于 | Z = 1或N! = V |
1110 | al | 無條件執(zhí)行 | - |
1111 | nv | 從不執(zhí)行 | - |
大多數(shù)ARM指令都可以條件執(zhí)行,即根據(jù)cpsr寄存器中的條件標志位決定是否執(zhí)行該指令:如果條件不滿足,該指令相當(dāng)于一條nop指令。
每條ARM指令包含4位的條件碼域,這表明可以定義16個執(zhí)行條件。
cpsr條件標志位N、Z、C、V分別表示Negative、Zero、Carry、oVerflow。
表示地址變化模式,有4種方式:
ia (Increment After) :事后遞增方式。
ib (Increment Before) :事先遞增方式。
da (Decrement After) :事后遞減方式。
db (Decrement Before):事先遞減方式。
{^}有兩種含義:
如果
如果
例:
HandleIRQ: @中斷入口函數(shù)
sub lr, lr, #4 @計算返回地址
stmdb sp!, { r0 - r12, lr } @保存使用的寄存器
@r0 - r12, lr被保存在sp表示的內(nèi)存中
@“!”使得指令執(zhí)行后sp = sp - 14 * 4
ldr lr, =int_return @設(shè)置調(diào)用IRQ_Handle函數(shù)后的返回地址
ldr pc, =IRQ_Handle @調(diào)用中斷分發(fā)函數(shù)
int_return:
ldmia sp!, { r0 - r12, pc }^ @中斷返回,“^”表示將spsr的值到cpsr
@于是從irq模式返回被中斷的工作模式
@“!”使得指令執(zhí)行后sp = sp + 14 * 4
4、加減指令:add、sub
例:
add r1, r2, #1 // r1 = r2 + 1
sub r1, r2, #1 // r1 = r2 - 1
5、程序狀態(tài)寄存器的訪問指令:msr、mrs
ARM處理器有一個程序狀態(tài)寄存器(cpsr),它用來控制處理器的工作模式、設(shè)置中斷的總開關(guān)。
例:
msr cpsr, r0 // r0到cpsr中
mrs r0, cpsr // cpsr到r0中
6、其他偽指令
.extern : 定義一個外部符號(可以是變量也可以是函數(shù))
.text : 表示現(xiàn)在的語句都屬于代碼段
.global : 將本文件中的某個程序標號定義為全局的
ARM-THUMB子程序調(diào)用規(guī)則:ATPCS
為了使C語言程序和匯編程序之間能夠互相調(diào)用,必須為子程序間的調(diào)用制定規(guī)則,在ARM處理器中,這個規(guī)則被稱為ATPCS:ARM程序和THUMB程序中子程序調(diào)用的規(guī)則?;镜腁TPCS規(guī)則包括寄存器使用規(guī)則、數(shù)據(jù)棧使用規(guī)則、參數(shù)傳遞規(guī)則。
1、寄存器使用規(guī)則
子程序間通過寄存器r0 ~ r3來傳遞參數(shù),這時可以使用它們的別名a1 ~ a4。被調(diào)用的子程序返回前無需恢復(fù)r0 ~ r3的內(nèi)容。
在子程序中,使用r4 ~ r11來保存局部變量,這時可以使用它們的別名v1 ~ v8。如果在子程序中使用了它們的某些寄存器,子程序進入時要保存這些寄存器的值,在返回前恢復(fù)它們;對于子程序中沒有使用到的寄存器,則不必進行這些操作。在THUMB程序中,通常只能使用寄存器r4 ~ r7來保存局部變量。
寄存器r12用作子程序間scratch寄存器,別名為ip。
寄存器r13用作數(shù)據(jù)棧指針,別名為sp。在子程序中寄存器r13不能用作其他用途。它的值在進入、退出子程序時必須相等。
寄存器r14稱為連接寄存器,別名為lr。它用于保存子程序的返回地址。如果在子程序中保存了返回地址(比如將lr值保存到數(shù)據(jù)棧中),r14可以用作其他用途。
寄存器r15是程序計數(shù)器,別名為pc。它不能用作其他用途。
寄存器 | 別名 | 使用規(guī)則 |
r15 | pc | 程序計數(shù)器 |
r14 | lr | 連接寄存器 |
r13 | sp | 數(shù)據(jù)棧指針 |
r12 | ip | 子 程序內(nèi)部調(diào)用的scratch寄存器 |
r11 | v8 | ARM狀態(tài)局部變量寄存器8 |
r10 | v7、s1 | ARM狀態(tài)局部變量寄存器7、在支持數(shù)據(jù)棧檢查的ATPCS中為數(shù)據(jù)棧限制指針 |
r9 | v6、sb | ARM狀態(tài)局部變量寄存器6、在支持RWPI的ATPCS中為靜態(tài)基址寄存器 |
r8 | v5 | ARM狀態(tài)局部變量寄存器5 |
r7 | v4、wr | ARM狀態(tài)局部變量寄存器4、THUMB狀態(tài)工作寄存器 |
r6 | v3 | ARM狀態(tài)局部變量寄存器3 |
r5 | v2 | ARM狀態(tài)局部變量寄存器2 |
r4 | v1 | ARM狀態(tài)局部變量寄存器1 |
r3 | a4 | 參數(shù)/結(jié)果/scratch寄存器4 |
r2 | a3 | 參數(shù)/結(jié)果/scratch寄存器3 |
r1 | a2 | 參數(shù)/結(jié)果/scratch寄存器2 |
r0 | a1 | 參數(shù)/結(jié)果/scratch寄存器1 |
2、數(shù)據(jù)棧使用規(guī)則
數(shù)據(jù)棧有兩個增長方向:向內(nèi)存地址減小的方向增長時,稱為DESCENDING棧;向內(nèi)存地址增加的方向增長時,稱為ASCENDING棧。
所謂數(shù)據(jù)棧的增長就是移動棧指針。當(dāng)棧指針指向棧頂元素(最后一個入棧的數(shù)據(jù))時,稱為FULL棧;當(dāng)棧指針指向棧頂元素(最后一個入棧的數(shù)據(jù))相鄰的一個空的數(shù)據(jù)單元時,稱為EMPTY棧。
則數(shù)據(jù)??梢苑譃?種:
FD:Full Descending 滿遞減
ED:Empty Descending 空遞減
FA :Full Ascending 滿遞增
EA:Empty Ascending 空遞增
ATPCS規(guī)定數(shù)據(jù)棧為FD類型,并且對數(shù)據(jù)棧的操作是8字節(jié)對齊的。使用stmdb / ldmia批量內(nèi)存訪問指令來操作FD數(shù)據(jù)棧。
使用stmdb命令往數(shù)據(jù)棧中保存內(nèi)容時,先遞減sp指針,再保存數(shù)據(jù),使用ldmia命令從數(shù)據(jù)棧中恢復(fù)數(shù)據(jù)時,先獲得數(shù)據(jù),再遞增sp指針,sp指針總是指向棧頂元素,這剛好是FD棧的定義。
3、參數(shù)傳遞規(guī)則
一般地,當(dāng)參數(shù)個數(shù)不超過4個時,使用r0 ~ r3這4個寄存器來傳遞參數(shù);如果參數(shù)個數(shù)超過4個,剩余的參數(shù)通過數(shù)據(jù)棧來傳遞。
對于一般的返回結(jié)果,通常使用r0 ~ r3來傳遞。
例:
假設(shè)CopyCode2SDRAM函數(shù)是用C語言實現(xiàn)的,它的數(shù)據(jù)原型如下:
int CopyCode2SDRAM( unsigned char *buf, unsigned long start_addr, int size )
在匯編代碼中,使用下面的代碼調(diào)用它,并判斷返回值:
ldr r0, =0x30000000 @1. 目標地址 = 0x30000000,這是SDRAM的起始地址
mov r1, #0 @2. 源地址 = 0
mov r2, #16*1024 @3. 長度 = 16K
bl CopyCode2SDRAM @調(diào)用C函數(shù)CopyCode2SDRAM
cmp a0, #0 @判斷函數(shù)返回值
評論