一、编程模型
1.1数据和指令类型
在之后的演示当中,我们大多数将采用ARM指令集
1.2处理器工作模式
1.3ARM寄存器
1.3.1分类
(1) 31 个通用寄存器,包括 PC(程序计数器)在内,都是 32 位的寄存器。
(2) 6 个状态寄存器,都是 32 位的寄存器。
LR(链接寄存器):保存函数的返回地址
SP(栈指针寄存器):指向栈顶(满减栈)
1.3.2程序状态寄存器
1.3.3程序指针PC
CPU总是按照PC的指向对指令序列进行取指、译码和执行,也就是说,最终是PC 决定了程序运行流向。
在程序开始执行前,将程序指令序列的起始地址,即程序的第一条指令所在的内存单元地址送入PC,CPU 按照 PC的指示从内存读取第一条指令(取指)。当执行指令时,CPU自动地修改PC 的内容,即每执行一条指令PC增加一个量,这个量等于指令所含的字节数(指令字节数),使 PC总是指向下一条将要取指的指令地址。由于大多数指令都是按顺序来执行的,所以修改PC 的过程通常只是简单的对PC 加“指令字节数”。
因此,我们可以判断,PC总是指向正在执行的下下一个操作
二、ARM指令集
2.1数据处理指令集
2.1.1BIC指令
2.1.2条件执行及标志位
三、汇编语言程序设计
3.1立即数
循环右移偶数位
像0X104就是立即数,0X101就不是立即数,0X104换算成二进制是0000 0000 0000 0000 0000 0001 0000 0100,可以看做是0000 0000 0000 0000 0000 0000 0100 0001循环右移30位变换成的,所以是立即数,但0X101换算成二进制是0000 0000 0000 0000 0000 0001 0000 0001,无法通过变换完成,所以不是立即数
一个简单的区分立即数的方法,立即数是8位常数变换来的,右移偶数位其实根本没有限制,因为8位的常数是可变的,那么只要保证数值换算成二进制后带有1的数位在8位以内就可以判定为立即数。
3.2函数调用
3.2.1内部
start
ldr sp, =0x40001000
mov r0, #1
mov r1, #2
mov r2, #3
mov r3, #4
bl fun
fun
mov r0,#1
mov r1,#2
add r2,r0,r1
mov pc ,lr ;调用后返回
end
3.2.2外部
(1)export
(2)import
3.2.3传参
4个以上传参需要将参数入栈
start
ldr sp, =0x40001000
mov r0, #1
mov r1, #2
mov r2, #3
mov r3, #4
mov r4, #5
mov r5, #6
stmfd sp!, {r4,r5}
bl fun
import c_add
bl c_add
3.2.4嵌套中断
使用入栈出栈的方式,保留lr,每次函数结束出栈时赋值给pc,返回函数调用后该执行的指令
preserve8
area reset , code , readonly
code32
entry
start
ldr sp, =0x40001000
mov r0, #1
mov r1, #2
mov r2, #3
mov r3, #4
import c_add
bl c_add ;将当前指令的下一条指令地址保存在LR寄存器,然后跳转。通常用于调用子程序,可通过在子程序的尾部添加mov pc, lr 返回。
nop
b start
export asm_add
asm_add
stmfd sp!,{r4-r12,lr} ;保护现场
add r0,r0,r1
ldmfd sp!,{r4-r12,pc} ;恢复现场
end
int asm_add(int x,int y);
int c_add(int a,int b,int c,int d)
{
int sum = asm_add(a,b);
sum += asm_add(c,d);
return sum;
}