1、数据操作指令
数据搬移指令
mov:移动指令
mvn:取反移动指令
语法格式:{cond}{s} {Rd}, {oprand2}
mov r0, #0xFF // 立即数0xFF放入寄存器r0 立即数前需要加“#”
mov r1, r0 // 将寄存器r0的数据放入寄存器r1中
mvn r2, #0xFF // r2 = ~0xFF(0xFFFFFF00)
mov r3, #0xFFFFFF // 0xFFFFFF是有效数,写入机器码会转换成立即数#~0xFF000000
mov r0, #0xFF000000
ldr r0, =0x12345678 //ldr伪指令 将0x12345678 放入寄存器r0
算数运算指令
{cond}{s} {Rd}, {Rn}, {oprand2}
add :普通的加法指令
adc :带进位的加法指令
sub :普通的减法指令
sbc :带借位的减法指令
练习题1
两个64位的数相加
第一个64位的数高32位在R1,低32位在R0
第二个64位的数高32位在R3,低32位在R2
结果高32位在R5,低32位在R4
mov r0, #0xFFFFFFFE
mov r1, #0x3
mov r2, #0x4
mov r3, #0x5
adds r4, r0, r2 @ r4 = r0 + r2 // s:产生进位C位置1,否则为0
adc r5, r1, r3 @ r5 = r1 + r3 + C // adc指令自动判断C位的值
将R0寄存器中的第[4]位清0的三种方法,保证其他位不变
and r0, r0, #0xFFFFFFEF
and r0, r0, #(~0X10)
and r0, r0, #(~(0x1 << 4))
/*and r0, #0x10000 如果目标寄存器和第一个操作寄存器编号相同,可以合并写一个。*/
练习题2
两个64位的数减法
第一个64位的数高32位在R1,低32位在R0
第二个64位的数高32位在R3,低32位在R2
结果高32位在R5,低32位在R4
mov r0, #0xFFFFFFFE
mov r1, #0x3
mov r2, #0x4
mov r3, #0x5
subs r4, r2, r0 @r4 = r2 - r0
sbc r5, r3, r1 @r5 = r3 - r1 - N
乘法指令测试
mov r0, #3
mov R1, #4
mul r2, r0, r1 //r2 = r0 * r1
// 第二个操作数只能是寄存器,不能是立即数
// mul r2, r0, #4 @ error
mul r0, r1 //r0 = r0 * r1
逻辑运算指令
and:与
orr :或
eor :异或
练习:
使用位运算符 : & | ^ ~ << >>
1、将R0寄存器中的第[4]位清0,保证其他位不变
and r0, r0, #0xFFFFFFEF
and r0, r0, #(~0X10)
and r0, r0, #(~(0x1 << 4))
/*and r0, #0x10000 如果目标寄存器和第一个操作寄存器编号相同,可以合并写一个。*/
2、将R0寄存器中的第[20]位置1,保证其他位不变
orr r0, r0, #(~(0x1 << 20))
3、将R0寄存器中的第[11:8]位置1,保证其他位不变
orr r0, r0, #(0xF << 8)
4、将R0寄存器中的第[3:0]位清0,保证其他位不变
and r0, r0, #0xFFFFFFF0
5、将R0寄存器中的第[29:26]位写成1010,保证其他位不变
and r0, r0, #(~(0xF << 26)) @先清零
orr r0, r0, #(0xA << 26) @再置1
6、将R0寄存器中的第[30:25]位写成101010,保证其他位不变
and r0, r0, #(~(0x3F << 25)) @先清零
orr r0, r0, #(0x2A << 25) @再置1
2、跳转指令 b bl
b :跳转、不保存返回地址到lr寄存器中
bl:跳转、自动保存返回地址到lr中
语法格式: b/bl{cond} Label
Label:
汇编代码
跳转指令的本质:修改PC值
// b 不保存返回地址到lr寄存器中
.if 0
mov r0, #3
mov r1, #4
b func_add //跳转到func_add 不保存rl 没办法返回
add r2, r0, r1
b stop
func_add:
mov r4, #5
mov r5, #6
add r6, r4, r5
//bl 自动保存返回地址到lr中
mov r0, #3
mov r1, #4
bl func_add
add r2, r0, r1
b stop
func_add:
mov r4, #5
mov r5, #6
add r6, r4, r5
mov pc, lr
3、load/store指令(单/多寄存器操作)
1、单寄存器操作指令
将Rn指向的内存空间中的数据读到Rm寄存器中,读4字节
Rn寄存器中的值,看成内存的地址。
ldr{code} Rm, [Rn]
将Rm寄存器中的数据写到Rn指向的内存空间中,写4字节
Rn寄存器中的值,看成内存的地址。
str{code} Rm, [Rn]
ldr r0, =0x40000800
ldr r1, =0x12345678
str r1, [r0] //在0x40000000地址写入数据0x12345678
ldr r2, [r0] //将0x40000000地址的数据0x12345678写入寄存器r2
ldr r0, =0x40000800
ldr r1, =0x11111111
ldr r2, =0x22222222
ldr r3, =0x33333333
//将R1中的值存到R0+4指向的地址空间中,R0中的值不变
str r1, [r0, #4] //前索引
//将R2中的值存到R0指向的地址空间中,R0=R0+4
str r2, [r0], #4 //后索引
//将R3中的值存到R0+4指向的地址空间中,R0=R0+4
str r3, [r0, #4]! //自索引
@ 注:立即数要求是4的整数倍
@ 以上索引方式同样适用于ldr指令
@ ldrb/strb/ldrh/strh b : byte h : half
@ 语法格式跟ldr和str完全一致。
多寄存器操作指令
从Rm指向的地址空间中读连续的数据到寄存器列表中,
ldm Rm, {寄存器列表}
将寄存器列表中的数据写到Rm指向的连续的内存空间中。
stm Rm, {寄存器列表}
要求:
@ 寄存器列表
1》 寄存器的编号要求从小到大
2》 寄存器连续使用“-”隔开
3》 寄存器不连续使用“,”隔开
ldr r0, =0x40000800
ldr r1, =0x11111111
ldr r2, =0x22222222
ldr r3, =0x33333333
ldr r4, =0x44444444
ldr r5, =0x55555555
//stm r0, {r1-r5}
stm r0, {r5,r4,r3,r2,r1}
//stm r0, {r1-r3,r4,r5}
//ldm r0, {r6-r10}
ldm r0, {r10,r9,r8,r7,r6}
@ 总结:寄存器列表中的寄存器顺序不管怎样,
@ 永远都是低地址对应小编号寄存器
@ 高地址对应大编号的寄存器
4、特殊功能寄存器传送指令 msr mrs
将普通寄存器(立即数)中的数据写到cpsr中
msr{cond} cpsr, rn
msr{cond} cpsr, #shift
将cpsr寄存器中的值读到普通寄存器中
mrs rn, cpsr
例子:从SVC模式切换到user模式
第一种方式
msr cpsr,#0xD0
mov r0, #0xD0
msr cpsr, r0
第二种方式
mrs r0, cpsr
bic r0, r0, #0x1F
//and r0, r0, #(~0x1F)
orr r0, r0, #0x10
msr cpsr, r0
5、软中断指令 swi
/******************************/
//构建异常向量表
b reset
b undef_handler
b swi_handler
b pref_handler
b data_handler
b .
b irq_handler
b fiq_handler
reset:
//初始化svc模式下的栈
ldr sp, =0x40000800 //此处的sp是svc模式下的栈指针
//从SVC模式切换到用户模式
mrs r0, cpsr
bic r0, r0, #0x1F
orr r0, r0, #0x10
msr cpsr, r0
//初始化用户模式下的栈
ldr sp, =0x40000900 //此处的user是svc模式下的栈指针
//开始执行代码
mov r0, #3
mov r1, #4
swi 2 //软中断指令
swi 3 //软中断指令
add r2, r0, r1 //r2 = r0 + r1 = 0x7
b stop
//死循环
stop:
bstop
//软中断的异常处理程序
swi_handler:
//保存现场
stmfd sp!, {r0-r1,lr}
//获取软中断号
sub r3, lr, #4
ldr r4, [r3]
bic r4, r4, #0xFF000000
//对软中断号进行判断,执行分支程序
cmp r4, #2
moveq r0, #5
cmp r4, #3
moveq r1, #6
//恢复现场
//^:恢复spsr_<mode>到cpsr中
ldmfd sp!, {r0-r1,pc}^