自己的一些简略的总结,也是最常用的ARM汇编指令,之后也会不断的弥补完善。
1.汇编体系预界说的段名
.text @代码段
.data @初始化数据段
.bss @未初始化数据段
需求留意的是,源程序中.bss段应该在.text之前。
2.界说进口点
汇编程序的缺省进口是 start标号,用户也能够在衔接脚本文件顶用ENTRY标志指明其它进口点。
.text
.global _start
_start:
3 .word用法
word expression便是在当时方位放一个word型的值,这个值便是expression
举例来说,
_rWTCON:
.word 0x15300000
便是在当时地址,即_rWTCON处放一个值0x15300000
4.equ赋值操作,相当于c言语的宏界说
.equ MEM_CTRL_BASE, 0x48000000 //留意要加,号
5. 逻辑指令
AND―――――逻辑"与"操作指令
ANDS R1,R1,R2 ;R1=R1&R2,并依据运算的成果更新标志位
AND R0,R0,#0x0F ;R0=R0&0x0F,取出R0最低4位数据。
指令格局:ORR{cond}{S} Rd,Rn,operand2 ORR指令将操作数operand2 与Rn 的值按位逻辑"或",成果存放到意图寄存器Rd 中。指令示例:
ORRS R1,R1,R2 ;R1=R1|R2,并依据运算的成果更新标志位
指令格局:
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
在嵌入式开发中,汇编程序常常用于十分要害的当地,比方体系启动时的初始化,进出中止时的环境保存、康复,对功能要求十分严苛的函数等。
1、相对跳转指令:b、bl
不同之处在于:bl指令除了跳转之外,还将回来地址(bl的下一条指令的地址)保存在lr寄存器中。
跳转规模:当时指令的前后32M。
它们是与方位无关的指令。
示例:
b fun1
……
fun1:
bl fun2
……
fun2:
……
2、数据传送指令:mov,地址读取伪指令:ldr
mov指令能够把一个寄存器的值赋给另一个寄存器,或许把一个常数赋给寄存器。
例:
mov r1, r2
mov r1, #4096
mov指令传送的常数有必要能用当即数来表明。
当不知道一个数能否用当即数来表明时,能够运用ldr指令来赋值。ldr是伪指令,它不是实在存在的指令,编译器会把它扩展成真实的指令:假如该常数能用当即数来表明,则运用mov指令;不然编译时将该常数保存在某个方位,运用内存读取指令把它读出来。
例:
ldr r1, =4097
ldr本意为“大规模的地址读取伪指令”,以下是取得代码的肯定地址:
例:
ldr r1, =label
label:
……
3、内存拜访指令:ldr、str、ldm、stm
ldr指令既可能是大规模的地址读取伪指令,也可能是内存拜访指令。当它的第二个参数前面有“ = ”时,表明伪指令,不然表明内存拜访指令。
ldr指令是从内存中读取数据到寄存器,str指令把寄存器的值存储到内存中,它们操作的数据都是32位的。
例:
ldr r1, [r2, #4] // 将地址为r2+4的内存单元数据读取到r1中
ldr r1, [r2] // 将地址为r2的内存单元数据读取到r1中
ldr r1, [r2], #4 // 将地址为r2的内存单元数据读取到r1中,然后r2=r2+4
str r1, [r2, #4] // 将r1的数据保存到地址为r2+4的内存单元中
str r1, [r2] // 将r1的数据保存到地址为r2的内存单元中
str r1, [r2], #4 // 将r1的数据保存到地址为r2的内存单元中,然后r2=r2+4
ldm和stm归于批量内存拜访指令,只用一条指令就能够读写多个数据。格局为:
ldm {cond}
stm {cond}
其间,{cond}表明指令的履行条件有:
条件码(cond) |
助记符 |
意义 |
cpsr中条件标志位 |
0000 |
eq |
持平 |
Z = 1 |
0001 |
ne |
不持平 |
Z = 0 |
0010 |
cs/hs |
无符号数大于/等于 |
C = 1 |
0011 |
cc/lo |
无符号数小于 |
C = 0 |
0100 |
mi |
负数 |
N = 1 |
0101 |
pl |
非负数 |
N = 0 |
0110 |
vs |
上溢出 |
V = 1 |
0111 |
vc |
没有上溢出 |
V = 0 |
1000 |
hi |
无符号数大于 |
C = 1或Z = 0 |
1001 |
ls |
无符号数小于等于 |
C = 0或Z = 1 |
1010 |
ge |
带符号数大于等于 |
N = 1, V = 1或N = 0, V = 0 |
1011 |
lt |
带符号数小于 |
N = 1, V = 0或N = 0, V = 1 |
1100 |
gt |
带符号数大于 |
Z = 0且N = V |
1101 |
le |
带符号数小于/等于 |
Z = 1或N! = V |
1110 |
al |
无条件履行 |
– |
1111 |
nv |
从不履行 |
– |
大多数ARM指令都能够条件履行,即依据cpsr寄存器中的条件标志位决议是否履行该指令:假如条件不满足,该指令相当于一条nop指令。
每条ARM指令包含4位的条件码域,这表明能够界说16个履行条件。
cpsr条件标志位N、Z、C、V别离表明Negative、Zero、Carry、oVerflow。
表明地址改变形式,有4种方法:
ia (Increment After) :过后递加方法。
ib (Increment Before) :事前递加方法。
da (Decrement After) :过后递减方法。
db (Decrement Before):事前递减方法。
{^}有两种意义:
假如
假如
例:
HandleIRQ: @中止进口函数
sub lr, lr, #4 @核算回来地址
stmdb sp!, { r0 – r12, lr } @保存运用的寄存器
@r0 – r12, lr被保存在sp表明的内存中
@“!”使得指令履行后sp = sp – 14 * 4
ldr lr, =int_return @设置调用IRQ_Handle函数后的回来地址
ldr pc, =IRQ_Handle @调用中止分发函数
int_return:
ldmia sp!, { r0 – r12, pc }^ @中止回来,“^”表明将spsr的值到cpsr
@所以从irq形式回来被中止的作业形式
@“!”使得指令履行后sp = sp + 14 * 4
4、加减指令:add、sub
例:
add r1, r2, #1 // r1 = r2 + 1
sub r1, r2, #1 // r1 = r2 – 1
5、程序状况寄存器的拜访指令:msr、mrs
ARM处理器有一个程序状况寄存器(cpsr),它用来操控处理器的作业形式、设置中止的总开关。
例:
msr cpsr, r0 // r0到cpsr中
mrs r0, cpsr // cpsr到r0中
6、其他伪指令
.extern : 界说一个外部符号(能够是变量也能够是函数)
.text : 表明现在的句子都归于代码段
.global : 将本文件中的某个程序标号界说为大局的
ARM-THUMB子程序调用规矩:ATPCS
为了使C言语程序和汇编程序之间能够相互调用,有必要为子程序间的调用拟定规矩,在ARM处理器中,这个规矩被称为ATPCS:ARM程序和THUMB程序中子程序调用的规矩。根本的ATPCS规矩包含寄存器运用规矩、数据栈运用规矩、参数传递规矩。
1、寄存器运用规矩
子程序间经过寄存器r0 ~ r3来传递参数,这时能够运用它们的别号a1 ~ a4。被调用的子程序回来前无需康复r0 ~ r3的内容。
在子程序中,运用r4 ~ r11来保存局部变量,这时能够运用它们的别号v1 ~ v8。假如在子程序中运用了它们的某些寄存器,子程序进入时要保存这些寄存器的值,在回来前康复它们;关于子程序中没有运用到的寄存器,则不用进行这些操作。在THUMB程序中,一般只能运用寄存器r4 ~ r7来保存局部变量。
寄存器r12用作子程序间scratch寄存器,别号为ip。
寄存器r13用作数据栈指针,别号为sp。在子程序中寄存器r13不能用作其他用处。它的值在进入、退出子程序时有必要持平。
寄存器r14称为衔接寄存器,别号为lr。它用于保存子程序的回来地址。假如在子程序中保存了回来地址(比方将lr值保存到数据栈中),r14能够用作其他用处。
寄存器r15是程序计数器,别号为pc。它不能用作其他用处。
寄存器 |
别号 |
运用规矩 |
r15 |
pc |
程序计数器 |
r14 |
lr |
衔接寄存器 |
r13 |
sp |
数据栈指针 |
r12 |
ip |
子 程序内部调用的scratch寄存器 |
r11 |
v8 |
ARM状况局部变量寄存器8 |
r10 |
v7、s1 |
ARM状况局部变量寄存器7、在支撑数据栈查看的ATPCS中为数据栈约束指针 |
r9 |
v6、sb |
ARM状况局部变量寄存器6、在支撑RWPI的ATPCS中为静态基址寄存器 |
r8 |
v5 |
ARM状况局部变量寄存器5 |
r7 |
v4、wr |
ARM状况局部变量寄存器4、THUMB状况作业寄存器 |
r6 |
v3 |
ARM状况局部变量寄存器3 |
r5 |
v2 |
ARM状况局部变量寄存器2 |
r4 |
v1 |
ARM状况局部变量寄存器1 |
r3 |
a4 |
参数/成果/scratch寄存器4 |
r2 |
a3 |
参数/成果/scratch寄存器3 |
r1 |
a2 |
参数/成果/scratch寄存器2 |
r0 |
a1 |
参数/成果/scratch寄存器1 |
2、数据栈运用规矩
数据栈有两个添加方向:向内存地址减小的方向添加时,称为DESCENDING栈;向内存地址添加的方向添加时,称为ASCENDING栈。
所谓数据栈的添加便是移动栈指针。当栈指针指向栈顶元素(最终一个入栈的数据)时,称为FULL栈;当栈指针指向栈顶元素(最终一个入栈的数据)相邻的一个空的数据单元时,称为EMPTY栈。
则数据栈能够分为4种:
FD:Full Descending 满递减
ED:Empty Descending 空递减
FA :Full Ascending 满递加
EA:Empty Ascending 空递加
ATPCS规矩数据栈为FD类型,而且对数据栈的操作是8字节对齐的。运用stmdb / ldmia批量内存拜访指令来操作FD数据栈。
运用stmdb指令往数据栈中保存内容时,先递减sp指针,再保存数据,运用ldmia指令从数据栈中康复数据时,先取得数据,再递加sp指针,sp指针总是指向栈顶元素,这刚好是FD栈的界说。
3、参数传递规矩
一般地,当参数个数不超越4个时,运用r0 ~ r3这4个寄存器来传递参数;假如参数个数超越4个,剩下的参数经过数据栈来传递。
关于一般的回来成果,一般运用r0 ~ r3来传递。
例:
假定CopyCode2SDRAM函数是用C言语完成的,它的数据原型如下:
int CopyCode2SDRAM( unsigned char *buf, unsigned long start_addr, int size )
在汇编代码中,运用下面的代码调用它,并判别回来值:
ldr r0, =0x30000000 @1. 方针地址 = 0x30000000,这是SDRAM的开始地址
mov r1, #0 @2. 源地址 = 0
mov r2, #16*1024 @3. 长度 = 16K
bl CopyCode2SDRAM @调用C函数CopyCode2SDRAM
cmp a0, #0 @判别函数回来值