一、ARM的工作模式
1、非特权模式
user模式:非特权模式,大部分任务执行在这种模式
2、特权模式
异常模式:
FIQ : 当一个快速(fast) 中断产生时将会进入这种模式
IRQ : 当一个通用(normal) 中断产生时将会进入这种模式
Supervisor(svc) :当复位或软中断指令执行时将会进入这种模式
Abort : 当存取异常时将会进入这种模式
Undef : 当执行未定义指令时会进入这种模式
非异常模式:
System : 使用和User模式相同寄存器集的特权模式
二、汇编语言的相关语法
1、汇编语言的组成部分
- 1.伪操作:不参与程序的执行,但是用于告诉编译器程序该怎么编译
- .text
- .global .end .if .else .endif .data
-
- 2.汇编指令
- 编译器将一条汇编指令编译成一条机器码,在内存里一条指令占4字节内存,一条指令可以实现一个特定的功能
-
- 3.伪指令
- 不是指令,看起来像是一条指令,可以实现和指令类似的功能。一条伪指令实际上可能是由多条指令共同实现
-
- 4.注释
- 单行注释: @
- 多行注释 /* */
- 条件编译
- .if 0
- 指令段
- .else
- 指令段
- .endif
2.汇编指令的介绍
- 1.基本数据操作指令
- 数据搬移指令 =
- 数据移位指令 << >>
- 数据算数运算指令 + - * /
- 位运算指令 & | ~ ^
- 数据比较指令
- 2.跳转指令
- 3.内存读写指令
- 4.状态寄存器读写指令
- 5.软中断指令
3.汇编指令的基本语法格式
- 指令的基本格式:
- <opcode>{<cond>}{s} <Rd>, <Rn>, <shifter_operand>
- 解释:
-
- <opcode>:指令码
- {<cond>}:条件码
- {s}:状态位,如果在指令后面加上s,则运算的结果会影响CPSR的条件位
- <Rd>:目标寄存器
- <Rn>:第一操作寄存器 只能是寄存器
- <shifter_operand>:第二操作数,可以是寄存器,也可以是立即数
- 按照指令码将第一操作寄存器和第二操作数进行运算,将运算后的结果保存在目标寄存器
-
- 注意:
- 1.一条汇编指令一般占一行
- 2.汇编不区分大写小写
三、汇编指令
1.数据搬移指令
- <opcode>{<cond>}{s} <Rd>, <shifter_operand>
- 解释:
-
- <opcode>:指令码
- {<cond>}:条件码
- {s}:状态位,如果在指令后面加上s,则运算的结果会影响CPSR的条件位
- <Rd>:目标寄存器
- <shifter_operand>:第一操作数,可以是寄存器,也可以是立即数
- 按照指令码将第一操作数运算后的结果保存在目标寄存器
-
- 指令码功能:
- mov:将第一操作数的值保存在目标寄存器
- mvn:将第一操作数的值按位取反,将结果保存在目标寄存器
2、移位指令
2.1 格式以及指令码
- 格式:<opcode>{<cond>}{s} <Rd>, <Rn>, <shifter_operand>
- 解释:将第一操作寄存器的数值移位第二操作数指定的位数,将结果保存在目标寄存器中
-
- 指令码:
- LSL:左移运算 低位补0
- LSR:右移运算 高位补0
- ROR:循环右移:低位移出的值补到高位
2.2 示例
- 1.左移
- mov r0,#0XFF
- lsl r1,r0,#0X4 @将R0的值左移4位保存在r1寄存器 R1结果:0XFF0
- 2.右移
- mov r0,#0XFF
- lsr r1,r0,#0X4 @将R0的值右移4位保存在r1寄存器 R1结果:0XF
- 3.循环右移
- mov r0,#0XFF
- ror r1,r0,#0X4 @将R0的值循环右移4位保存在r1寄存器 R1结果:0XF000000F
- 4.c风格写法
- mov r0,#0XFF
- ror r1,r0,#(0X1<<2) @将R0的值循环右移4位保存在r1寄存器 R1结果:0XF000000F
3.位运算指令
3.1 格式以及功能码
- 格式:<opcode>{<cond>}{s} <Rd>, <Rn>, <shifter_operand>
- 解释:将第一操作寄存器和第二操作数进行位运算,将结果保存在目标寄存器中
-
- 指令码:
- and:与 与0清0 与1不变
- orr:或 或1置1 或0不变
- eor:异或 相同为0 不同为1
- bic:按位清零指令,想将哪一位设置为0,只需要用bic指令给这一位运算一个1即可
3.2 示例
- 1.and:
- mov r0,#0XFF
- and r1,r0,#0XF0 @R1结果为0XF0
- 2.ORR:
- mov r0,#0XFF
- orr r1,r0,#0XF000 @R1结果为0XF0FF
- 3.EOR:
- ldr r0,=0xf0f0
- EOr r1,r0,#0XFF @R1结果为0XF00F
- 0000 0000 0000 0000 0000 0000 1111 1111
- 0000 0000 0000 0000 1111 0000 1111 0000
- 结果:0000 0000 0000 0000 1111 0000 0000 1111 -》0XF00F
-
- 4.BIC
- ldr r0,=0xFF
- BIC r0,r0,#(0x1<<5) @将R0的值第5位清0 @R0结果为0XDF
3.3 练习
- LDR r1,=0X12345678 @将0X12345678存放在r1寄存器
- 0001 0010 0011 0100 0101 0110 0111 1000
- 1.将R1寄存器的第4位清0,其他位不变
- and r1,r1,#(~(0X1<<4))
- 或者BIC R1,R1,#(0x1<<4)
- 2.将r1寄存器第7位置1,其他位不变
- orr r1,r1,#(0X1<<7)
- 3.将r1寄存器[31:28]清0,其他位不变
- and r1,r1,#(~(0Xf<<28))
- 或者BIC R1,R1,#(0xF<<28)
- 4.将r1寄存器[7:4]置1,其他位不变
- orr r1,r1,#(0XF<<4)
- 5.将r1寄存器[15:11]设置为10101,其他位不变
- @先清0
- BIC R1,R1,#(0X1F<<11)
- @再置位
- orr r1,r1,#(0X15<<11)
4.算数运算指令
4.1 格式以及指令码
- 格式:<opcode>{<cond>}{s} <Rd>, <Rn>, <shifter_operand>
- 解释:将第一操作寄存器的值和第二操作数进行算数运算,结果保存在目标寄存器中
-
- add:加法运算
- adc:进行加法运算时需要考虑CPSR的条件位
- sub:减法运算
- sbc:进行减法运算时需要考虑CPSR的条件位
- mul:乘法运算
4.2 示例
- 1.ADD:加法
- ex1: mov r1,#1
- mov r2,#2
- add r3,r1,r2@r3=r1+r2
- ex:
- mov r1,#0XFFFFFFFE
- mov r2,#2
- addS r3,r1,r2@r3=r1+r2 @运算的结果影响到条件位
- 2.SUB
- mov r1,#0XFFFFFFFE
- mov r2,#2
- sub r3,r1,r2@r3=r1-r2
- ex2:
- mov r1,#0XFFFFFFFE
- mov r2,#2
- subs r3,r2,r1@r3=r2-r1
- 3.ADC
- mov r1,#0XFFFFFFFE
- mov r2,#2
- ADDS r3,r2,r1 @r3=r1+r2
- ADC R4,R2,#3 @R4=R2+3+cpsr(C位) 6
-
- 4.sbc:减法运算考虑条件位
- mov r1,#0XFFFFFFFE
- mov r2,#2
- SUBS r3,r2,r1 @r3=R2-R1 4
- sbC R4,R1,#3 @R4=R1-3-CPSR(C位取反)
4.3 64位数据进行算数运算
- 原则:
- 一个 64位数保存在两个寄存器
- 高32位运算,低32位运算
- mov r1,#0XFFFFFFFE @保存第一个数据的低32位
- mov r2,#2@保存第一个数据的高32位
- mov r3,#3 @保存第二个数据的低32位
- mov r4,#4 @保存第2数据的高32位
- @低32位运算要求影响条件位
- ADDS R5,R1,R3@R5保存运算后结果的低32位
- ADC R6,R2,R4@R6寄存器保存运算结果的高32位,需要考虑条件位
5.比较指令
- 格式:
- cmp 第一操作数,第二操作寄存器
- 比较两个数据
- cmp命令本质:实际上就是比较的两个数进行减法运算,并且减法运算的结果会影响到CPSR寄存器的条件位
- 通常比较指令完毕之后会使用条件码进行判断,根据判断的结果做不同的逻辑
- mov r1,#3
- mov r2,#4
- cmp r1,r2 @比较两个数
- SUBHI r3,r1,r2 @如果r1>r2 进行减法运算
- MULEQ r3,r1,r2@如果两数相等,进行乘法运算
- ADDCC R3,R1,R2@如果r1<r2 ,进行加法运算
6. 跳转指令
- 格式:
- <opcode>{<cond>} 标签
- 功能:跳转到指定的标签下
-
- 指令码:
- b:跳转时不影响LR寄存器的值
-
- ex:.text
- .global _start
-
- _start:
- mov r1,#3
- mov r2,#4
- b fun1 @程序跳转
- mul r5,r1,r2
-
- stop:
- b stop
-
- fun1:
- add r4,r1,r2
-
-
-
- .end
-
-
- bl:跳转时影响LR寄存器的值
-
- .text
- .global _start
-
- _start:
- mov r1,#3
- mov r2,#4
- bl fun1 @程序跳转
- mul r5,r1,r2
-
- stop:
- b stop
-
- fun1:
- add r4,r1,r2
- mov pc,lr @程序返回
-
-
-
- .end
7.单寄存器内存读写指令
- 向内存中写:
- str:向内存中写一个字(4字节)的数据
- strh:向内存写半个字(2字节)的数据
- strb:向内存写一个字节的数据
- 从内存读:
- ldr:从内存读取一个字的数据
- ldrh:从内存读取半个字的数据
- ldrb:从内存读取一个字节的数据
- mov r1,#0XFFFFFFFF
- ldr r2,=0X40000000
- @向内存写入
- str r1,[r2]
- @从内存读
- ldr r3,[r2]
8.批量寄存器的内存读写方式
- mov r1,#1
- mov r2,#2
- mov r3,#3
- mov r4,#4
- mov r5,#5
- ldr r6,=0X40000000
- stm r6,{r1,r2,r3,r4,r5} @将r1-r6寄存器的值写道r6指向的连续内存中
- ldm r6,{r7,r8,r9,r10,r11}@从r6指向的连续内存中读取数据保存到r7-r11寄存器中
四、栈内存读写
1、栈的类型
- 增栈:压栈结束后,栈顶往地址大的方向增长
- 减栈:压栈结束后,栈顶往地址小的方向增长
- 空栈:压栈结束后,栈顶区域没有有效数据
- 满栈:压栈结束后,栈顶区域存放有效数据
-
- 空增栈(EA)/空减栈(ED)/满增栈(FA)/满减栈(FD)
- ARM使用的栈是满减栈
2、满减栈压栈的出栈操作
- ex1:
- ldr sp,=0X40000020 @指定顶地址
- mov r1,#1
- mov r2,#2
- mov r3,#3
- mov r4,#4
- mov r5,#5
- push {r1-r5} @压栈
- pop {r6-r10} @将栈顶元素数值出栈
- ex2:
- ldr sp,=0X40000020 @指定顶地址
- mov r1,#1
- mov r2,#2
- mov r3,#3
- mov r4,#4
- mov r5,#5
- STMDB sp!,{r1-r5} @压栈
- LDMIA sp!,{r6-r10} @将栈顶元素数值出栈
- EX3:
- ldr sp,=0X40000020 @指定顶地址
- mov r1,#1
- mov r2,#2
- mov r3,#3
- mov r4,#4
- mov r5,#5
- STMfd sp!,{r1-r5} @压栈
- LDMfd sp!,{r6-r10} @出栈
- 4.栈实例---叶子函数的调
3、栈实践,叶子函数的调用过程
- .text
- .global _start
-
-
- _start:
- ldr sp,=0X40000020 @初始化栈
- b main
- main:
- mov r1,#1
- mov r2,#2
- bl func
- add r3,r1,r2
- b main
-
- func:
- @压栈保护现场
- stmfd sp!,{r1,r2}
- mov r1,#3
- mov r2,#4
- sub r4,r2,r1
- @出栈恢复现场
- ldmfd sp!,{r1,r2}
- mov pc,lr @返回main函数
-
-
- wh:
- b wh
-
- .end
4、非叶子函数的调用过程
- .text
- .global _start
-
-
- _start:
- ldr sp,=0X40000020 @初始化栈
- b main
- main:
- mov r1,#1
- mov r2,#2
- bl func
- add r3,r1,r2
- b main
-
- func:
- @压栈保护现场
- stmfd sp!,{r1,r2,lr}
- mov r1,#3
- mov r2,#4
- bl fun1
- sub r4,r2,r1
- @出栈恢复现场
- ldmfd sp!,{r1,r2,lr}
- mov pc,lr @返回main函数
- fun1:
- @压栈保护现场
- stmfd sp!,{r1,r2}
- mov r1,#4
- mov r2,#5
- mul r5,r1,r2
- @出栈恢复现场
- ldmfd sp!,{r1,r2}
- mov pc,lr
-
-
- wh:
- b wh
-
- .end