汇编语言:基本指令详解
一、数据操作指令
1、数据搬移指令:mov / mvn
1)mov:数据传送指令
语法:mov{cond}{s} Rd, operand2
eg:mov r1, r2 @r1 = r2
注意:操作数2(operand2)可以是寄存器、立即数、有效数
eg:mov r3, #0xFFF @ error
mov r4, #0xFFFF @ error
mov r3, #0xFFFFFF00 @ 有效数OK
2)mvn:数据取反传送指令
语法:mov{cond}{s} Rd, operand2
eg:mov r1, r2 @r1 = ~r2
2、算数指令:add adc sub sbc mul
通用语法:opcode{cond}{s} Rd, Rn, operand2
1)add:普通的加法指令
2)adc:带进位的加法指令
eg: @两个64位的数相加
@ 第一个64位的数高32位在r1,低32位在r0
@ 第二个64位的数高32位在r3,低32位在r2
@ 结果高32位在r5,低32位在r4
mov r0, #0xFFFFFFFE
mov r1, #3
mov r2, #5
mov r3, #6
@ 先算低32位,需要有状态位,因为要使其产生进位标志
adds r4, r0, r2 @ r4 = r0 + r2 = 0x00000003
@ 再算高32位,带进位的加法
adc r5, r1, r3 @ r5 = r1 + r3 + C = 0xA
注意:产生进位,C为1,否则为0
3)sub :普通的减法指令
4)sbc :带借位的减法指令
eg:@ 两个64位的数减法
@ 第一个64位的数高32位在r1,低32位在r0
@ 第二个64位的数高32位在r3,低32位在r2
@ 结果高32位在r5,低32位在r4
mov r0, #4
mov r1, #9
mov r2, #5
mov r3, #6
@ 先算低32位,需要有状态位,因为要使其产生借位标志
subs r4, r0, r2 @ r4 = r0 - r2 = 0xFFFFFFFF
@ 再算高32位,带借位的减法
sbc r5, r1, r3 @ r5 = r1 - r3 - (1 - C) = 0x2
注意:sbc,当产生借位时C为0,否则C为1
5)mul :普通的乘法指令
eg:mov r1, #4
mov r2, #5
mul r0, r1, r2 @ r0 = r1 * r2
注意:乘法指令的第二个操作数只能是一个寄存器
4、位运算指令:and orr eor bic
通用语法:opcode{cond}{s} Rd, Rn, operand2
1)and 按位与运算指令 ,与0清0,与1不变
2)orr 按位或运算指令,或1置1,或0不变
3)eor 按位异或运算指令,相异为1,相同为0,记为:异为1,同为0
4)bic 按位清除运算指令,根据第二个操作数哪位是1,就将第一个操作寄存器的哪位清0
eg:mov r0, #0xFF @ 假设不知道r0寄存器中的值
@ 1> 将r0寄存器中的,[4]位清0,保证其他位不变
a-) and r1, r0, #0xEF
b-) and r1, r0, #(~0x10)
c-) and r1, r0, #(~(0x1 << 4))
@ 2> 将r0寄存器中的第[20]位置1,保证其他位不变
orr r3, r0, #(0x1 << 20)
@ 3> 将r0寄存器的第[11:8]位置1,保证其他位不变
orr r4, r0, #(0xF << 8)
@ 4> 将r0寄存器的第[3:0]位清0,保证其他位不变
a-) bic r5, r0, #(0xF << 0)
b-) and r5, r0, #~(0xF)
@ 5> 将r0寄存器的第[29:26]位写成1010,保证其他位不变
@ 第一步,先清零
bic r0, r0, #(0xF << 26)
@ 第二步,相应的位置1
orr r0, r0, #(0xA << 26)
@ 6> 将r0寄存器的第[30:25]位写成101010,保证其他位不变
@ 第一步,先清零
bic r0, r0, #(0x3F << 25)
@ 第二步,相应的位置1
orr r0, r0, #(0x2A << 25)
@ 7> 将r0寄存器中的[3:0]位清0,结果写到r1寄存器
bic r1, r0, #0xf @ 0xF0
5、比较指令:cmp
语法:cmp{cond} Rn, operand2
作用:比较Rn和Operand2两个数的大小,本质做减法运算
注意:比较指令没有目标寄存器,没有状态 {S} 位,指令结果只影响 CPSR.NZCV 位
eg:mov r0, #9
mov r1, #15
cmp r0, r1
@ r0 > r1 r0 = r0 - r1
subhi r0, r0, r1
@ r0 < r1 r1 = r1 - r0
subcc r1, r1, r0
二、跳转指令:b / bl
跳转指令的本质:修改PC值
1)b:不保存返回地址到 lr 寄存器中,跳转到标签的位置
语法:b{cond} Label
2)bl:自动保存返回地址到 lr 寄存器中,跳转到标签的位置
语法: bl{cond} Label
注意:函数的返回需要手动返回:mov pc, lr
eg:求两数的最大公约数:
解析: mov r0, #9
mov r1, #15
loop:
cmp r0, r1
beq stop
subhi r0, r0, r1
subcc r1, r1, r0
b loop
求两数的最大公约数:
三、Load/Store指令
1、单寄存器操作指令:ldr / str ldrh / strh ldrb / strb
1)ldr:将Rm寄存器指向的内存空间的内容读到Rn寄存器中,读4个字节大小的数据,
语法:ldr{cond} Rn, [Rm]
eg:ldr r0, =0x800000FF
ldr r1, [r0]
注意:不需要是立即数,可以赋值的范围是:0x00000000 - 0xFFFFFFFF
2)str:将Rn寄存器中的值写到Rm寄存器指向的内存地址空间中,写4个字节大小的数据
语法:str{cond} Rn, [Rm]
eg:str r1, [r0]
3)eg:
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)ldrh / strh ldrb / strb
用法与上述一致
h(half word):读写半字
b(byte):读写一个字(可以用作判断大小端)
2、多寄存器操作指令:ldm / stm
1)ldm: 一次可以完成多个寄存器的读操作
语法:ldm{cond} Rn, {寄存器列表}
2)stm: 一次可以完成多个寄存器的写操作
语法:stm{cond} Rn, {寄存器列表}
eg:将r1-r3中的值,存储到r0指向的内存地址空间中
ldr r0, =0x40000800
ldr r1, =0x11111111
ldr r2, =0x22222222
ldr r3, =0x33333333
@ stm r0, {r1-r3}
@ stm r0, {r1,r2,r3}
@ stm r0, {r1-r2,r3}
@ stm r0, {r3, r2, r1} 会报警告但是没错,照样是从r1-r3,不是从r3-r1
将r0指向的地址空间中连续的20个字节中的内容读到r4-r7寄存器中
ldm r0, {r4-r7}
注意:寄存器列表中的寄存器不管顺序如何,都是高地址对应大编号的寄存器,低地址对应小编号的寄存器。
3、栈操作指令:ldmfd / stmfd
栈指针寄存器 r13(sp):存放栈顶的地址
减栈:栈指针向低地址方向移动
增栈:栈指针向高地址方向移动
满栈:栈指针指向的栈空间有效的数据,向栈空间压入数据时,应先将栈指针移动到一个空的位置,
再向栈空间中压入数据,此时栈指针依然指向一块有数据的栈空间。
空栈:栈指针指向的栈空间没有有效的数据,向栈空间压入数据时可以直接压入,再将栈指针移动到一个空的位置。
对于栈的操作方式:
@ 满增栈(FA) :Full Ascending ldmfa/stmfa
@ 满减栈(FD) :Full Descending ldmfd/stmfd
@ 空增减(EA) :Empty Ascending ldmea/stmea
@ 空减栈(ED) :Empty Descending ldmed/stmed
@ ARM默认采用的是**满减栈** ldmfd/stmfd
1)stmfd:看图了解向内存压栈图1,2
语法:stmfd{cond} sp!, {寄存器列表}
2)ldmfd:看图了解向内存压栈图3
语法:ldmfd{cond} sp!, {寄存器列表}
注意:!:更新栈指针的地址
eg:看图4
四、特殊功能寄存器传送指令:msr / mrs
1)msr:cpsr = operand2
语法:msr{cond} cpsr, operand2
2)mrs:Rm = cpsr
语法:mrs{cond} Rm, cpsr
应用:从SVC(超级管理员)模式切换到USR(用户)模式
SVC模式:0b10011
USR模式:0b10000
方法:修改模式位保证其他位不变,将低四位清零 @ 1 0011 --> 1 0000
mrs r0, cpsr
bic r0, r0, #0x1F
orr r0, r0, #0x10
msr cpsr, r0
五、软中断指令
六、混合编程