复习:
数据处理指令
一.分类
1. 数据 传送(MOV数据传送指令 MVN数据取反传送指令)
2. 算术运算(
ADD加法 ADC带进位的加法
SUB减法 SBC带借位的减法
RSB反向减法指令 RSC带借位的反向减法指令)
3. 位运算(AND与 ORR或 EOR异或 BIC位清除)
4.比较测试(CMP比较指令,减法CMN负数比较指令,加法TST位测试指令,位相与TEQ测试相等指令,位异或)
二.指令格式
操作码{条件码}S 目标寄存器, 第一源操作数, 第二源操作数
1.数据传送指令无第一源操作数
2.比较测试指令无目标寄存器
3.比较测试指令不加S,结果影响NZCV
4.第一源操作数是寄存器
5.第二源操作数有:8位图立即数,寄存器,寄存器移位
(LSL,LSR,ASR,ROR,RRX)
6.S:1.目标寄存器为PC,CPSR=SPSR
2.目标寄存器不为PC,结果影响NZCV
7.加法,C进位,有进位,C=1,无进位,C=0
8.减法,C借位,有借位,C=0,无借位,C=1
1-10累加和
arm-linux-as-g -o sum.o sum.s
arm-linux-ld-e _start -o sum sum.o
qemu-arm -g1234 sum
arm-linux-gdbsum
最大公约数的求解
20=5X4
12=3X4
= 2X4
R0=20
R1=12
R0==R1? 20!=12
R0=R0-R1=20-12=8
R1=R1-R0=12-8=4
R0=R0-R1=8-4=4
while(R0 !=R1)
{
if(R0>= R1)
{
R0 = R0– R1;
}
else
{
R1 = R1 – R0;
}
}
跳转指令
数据处理指令(传送,加法,减法,位运算,比较测试)
mov r1,#0x56
从存储器中获得,怎么办?
------------------------------------------------------------------------------------------------------------
Day10
(1)加载指令:将数据从存储器中读到寄存器
(2)存储指令:将处理完毕的数据(寄存器)存储回存储器
实现了寄存器与存储器之间的数据交互
单寄存器
多寄存器
单寄存器字和无符号字节的加载,存储指令
单寄存器的字加载指令
LDR{cond} Rd, <地址模式>
功能:将指定地址单元<地址模式>的字数据读入Rd中。
单寄存器的无符号字节加载指令
LDR{cond}B Rd, <地址模式>
功能:将指定<地址模式>地址单元中的字节数据读入Rd中,
字节数据放在Rd的低8位,高24bit用0填充
<地址模式>:数据来源
Rd:目标寄存器
示例
LDR R1, [R2]
R2=0x20008000
R1是0x20008000地址中的数据
LDR PC, [R0, #8]
LDRB R1, [R2], #1
R2=0x20008000 0x56
R1=0x56
R2=R2+1=0x20008001
LDR R1, [PC, R3]
LDR R1,[R2, R3, LSL #2]
LDREQB R1,[R2, R3]
LDR R0, [R0, #8]! @×
基址与目标寄存器不一样
单寄存器字和无符号字节存储指令
语法格式
STR{cond} Rd, <地址模式>
功能:将Rd寄存器的字数据存储到由<地址模式>指定的地址中
STR{<cond>}B Rd, <地址模式>
功能:将寄存器中一个字节数据保存到<地址模式>指定的地址中
Rd:源寄存器
<地址模式>:数据需要存储到的目标地址
示例
STR R1, [R2]
STR R1, [R2], #1
STR R1, [R2, R3]
STRB R0, [R1, R2, ASR #2]
STREQB R0, [R1, R2, LSL #2]
STR PC, [R0, #8] [PC, #8] 单元内容
STR R0, [R0, #8]! @×
1 .零偏移
LDR R0, [R1] //将R1指定的地址中的数据加载到R0
R0=0xe92d4800
2. [<Rn>, #+/-<offset_12>] 偏移量为立即数(12bit)
LDR R0, [R1,#0x8] ;R0<-[R1+0x8]
LDR R0, [R1, #-0x20] ; R0<- [R1 – 0x20]
R0=0xe59f3060
3. [<Rn>, +/-<Rm>] 偏移量为寄存器
LDR R0,[R1, R2] ;R0<-[R1+R2]
LDR R0,[R1,-R2] ;R0<-[R1-R2]
4. [<Rn>, +/-<Rm>, <shift> #<shift_imm>] 偏移量为寄存器移位
LDR R0,[R1 ,R2,LSL #2] ;R0<-[R1+R2*4]
5. [<Rn>, #+/-<offset_12>]!
LDR R0,[R1, #0x8]! ;R0<-[R1+0x8] R1=R1+8
1.先加载数据
2.改变基址
6. [<Rn>, +/-<Rm>]!
LDR R0,[R1,R2] ! ;R0<-[R1+R2] R1=R1+R2
7. [<Rn>, +/-<Rm>, <shift> #<shift_imm>]!
LDR R0,[R1,R2,LSL #2] !
;R0<-[R1+R2*4] R1=R1+R2*4
8. [<Rn>], #+/-<offset_12>
LDR R0, [R1], #0x20 ;R0=<-[R1] R1=R1+0x20
1.现将基址指定的数据加载到R0
2.改变基址
9. [<Rn>], +/-<Rm>
LDR R0, [R1], R2 ;R0=<-[R1] R1=R1+R2
10. [<Rn>], +/-<Rm>,<shift> #<shift_imm>
LDR R0, [R1], R2, LSL #2;R0=<-[R1] R1=R1+R2*4
地址模式:
10:
1.无偏移量,将指定基址的数据加载到寄存器,基址不变
2.将基址+偏移量指定地址的数据加载到寄存器,基址不变
1.立即数
2.寄存器
3.寄存器移位
3.将基址+偏移量指定地址的数据加载到寄存器,基址=基址+偏移量
1.立即数
2.寄存器
3.寄存器移位
4.将基址表示的加载到寄存器,基址=基址+偏移量
1.立即数
2.寄存器
3.寄存器移位
单寄存器字和无符号字节的加载,存储指令
单寄存器半字和有符号字节的加载,存储指令
加载指令
语法格式
LDR{cond}H Rd, <地址模式>
功能:Rd<- <地址模式>,高16bit用0填充
LDR{cond}SH Rd, <地址模式>
功能:Rd<- <地址模式>,高16bit用符号位填充
LDR{cond}SB Rd, <地址模式>
功能:Rd<- <地址模式>,高24bit用符号位填充
使用示例
LDRH R1, [R0]
R0=0x20008000
R1=0x4800
LDRSH R8, [R3, #2]
LDREQH R12, [R13, #-6]
LDRSB R7, [R6, #-1]!
LDRH R3, [R9], #2
LDRSB R1, [R2], R3
LDRH PC, [R0] @×
LDRH R0, [R0], #4 @×
LDRSB PC, [R0] @×
LDRSB R0, [R0], #4 @×
不要以PC作为目标寄存器用在加载半字和字节的加载指令中
在基址要发生变化的指令中,基址寄存器和目标寄存器不要相同的
语法格式
STR{cond}H Rd,<地址模式>
使用示例
STRH R1, [R0]
STRH R8, [R3, #2]
STREQH R12, [R13, #-6]
STRH R7, [R6, #-2]!
STRH R3, [R9], #2
STRH R1, [R2], R3
STRH PC, [R0] @×
STRH R0, [R0], #4 @×
STRH R7, [R6, #-1] @ ?
半字读写时,指定的地址必须半字对齐,地址整除2
基址+偏移量
偏移量:立即数(由8bit来表示),寄存器
1 .零偏移
LDRSH R0, [R1]
R0<-[R1]的低16bit R0的高16bit用符号位填充
2.[<Rn>, #+/-<offset_8>]
LDRH R0, [R1, #0x04]
3.[<Rn>, +/-<Rm>]
LDRSB R0,[R1, R2]
4.[<Rn>, #+/-<offset_8>]!
LDRH R0, [R1, #0x08]!
5.[<Rn>, +/-<Rm>]!
LDRSB R0,[R1, R2]!
6. [<Rn>],#+/-<offset_8>
LDRSH R0, [R1], #0x4
7.[<Rn>], +/-<Rm>
LDRSH R0, [R1], R2
单寄存器字和无符号字节存储加载指令
地址模式:
基址+偏移量
立即数(12bit)
寄存器
寄存器移位
单寄存器半字和有符号字节存储加载指令
地址模式:
基址+偏移量
立即数(8bit)
寄存器
多寄存器存储加载指令
多寄存器加载指令 LDM
LDM{cond}{addressing_mode} Rb{!}, < Reglist >{^}
功能:将Rb基址中数据加载到Reglist表示的寄存器列表中
LDMIA / STMIA 后增加
LDMIB / STMIB 先增加
LDMDA / STMDA 后减小
LDMDB / STMDB 先减小
多寄存器存储指令 STM
STM{cond}{addressing_mode} Rb{!}, < Reglist>{^}
cond : 条件域
addressing_mode
LDMIA /STMIA Increment After(先操作,后增加)
LDMIB /STMIB Increment Before(先增加,后操作)
LDMDA /STMDA Decrement After (先操作,后递减)
LDMDB /STMDB Decrement Before (先递减,后操作)
Rb : 基址寄存器
! : 更新基址寄存器
Reglist: 源/目标寄存器列表(可以是16个寄存器的任何子集)
^ : 1.寄存器列表中没有PC寄存器:特权模式下使用用户模式下的寄存器
2.寄存器列表中有PC寄存器,CPSR=SPSR,异常返回
R10:基址寄存器
{R0,R1,R4}:源操作的寄存器
STMDA R10!, {R0,R1,R4}
LDMIA R10, {R0,R1,R4}
R0=0x20008000 IB地址先增加,然后再加载数据
[0x20008000]=1
[0x20008004]=2
[0x20008008]=3
[0x2000800C]=4
[0x20008010]=5
LDMIB R0! , {R1,R2,R3,R4}
R1=2
R2=3
R3=4
R4=5
R0=0x20008010
R0=0x20008000 IA地址后增加,先加载数据
[0x20008000]=1
[0x20008004]=2
[0x20008008]=3
[0x2000800C]=4
[0x20008010]=5
LDMIA R0!, {R1, R2, R3,R4}
R1=1
R2=2
R3=3
R4=4
R0=0x20008010
LDMIA R0!, {R1-R3}
LDMIB R0, {R1-R3, R7}^ @ x usr/sys
LDMDB SP!,{R1-R3, PC}^ @ x usr/sys
LDMDB R0, {R0-R2}
LDMDA R15, {R1} @x
LDMDB R0!, {R0-R2} @x Rn值
LDM{cond}{addressing_mode} Rb{!}, < Reglist >{^}
功能:将Rb基址中数据加载到Reglist表示的寄存器列表中
多寄存器存储指令 STM
STM{cond}{addressing_mode} Rb{!}, < Reglist>{^}
IA 先存储或加载数据,地址后增加
IB 地址先增加,后存储或加载数据
DA 先存储或加载数据,地址后减小
DB 地址先减小,后存储或加载数据
多寄存器存储加载,只操作字数据
大编号寄存器存放在高地址,小编号寄存器存放在低地址
!:基址要更新
^:1.寄存器列表中包括PC,CPSR=SPSR(异常模式下使用)
2.寄存器列表中不包括PC,特权模式下使用用户模式寄存器
PC不做为基址寄存器
若要更新基址,基址和目标寄存器不使用相同的寄存器
STMIA R0!, {R1-R3}
STMIA SP!, {R1-R3, LR}
STMIB R0, {R1-R3, R9}^ @x usr/sys
STMDB R0, {R0-R2}
STMDB R0!, {R0-R2}
STMDA R15, {R1} @ x
栈的种类:
Descending stacks (减栈)
栈向内存地址减小的方向变化
Ascending stacks (加栈)
栈向内存地址增加的方向变化
Full stacks (满栈)
栈指针指向的栈顶保存有效元素
Empty stacks (空栈)
栈指针指向的栈顶未保存有效元素
综合以上两种特点,有以下4种栈
FD(Full Descending) 满减栈
ED(Empty Descending) 空间栈
FA(Full Ascending) 满加栈
EA(Empty Ascending) 空加栈
STMFD (Push) [多寄存器存储 - STMDB]
LDMFD (Pop) [多寄存器加载 - LDMIA]
STMDB 入栈
LDMIA 出栈
…….
MOV R0, #0
MOV R1,#1
BL loop CPU自动将ADD指令地址存放LR
ADD R3,R4
loop:
STMFD sp!, {r4-r7, lr}
SUBR4, #1
…..
LDMFD sp!, {r4-r7, pc}
STMFD(STMDB\Push):入栈
根据满减栈原则,先减地址,后入栈,高地址存大编号寄存器的原则,依次入栈,栈顶指针永远指向有效元素。如果不先减地址,则将原栈顶有效元素覆盖。
LDMFD(LDMIA\Pop):出栈
根据满减栈原则,先出栈,后加地址,依次出栈,栈顶指针永远指向有效元素。如果不先出栈,则将丢失一个有效元素。
MRS程序状态寄存器读指令
MRS指令语法格式
MRS{cond} Rd, psr
cond 条件码
Rd目标寄存器(不能是R15)
Psr 程序状态寄存器(CPSR,SPSR)
MRS{<cond>} <Rd>, CPSR
MRS{<cond>} <Rd>, SPSR
示例:
MRS R0, CPSR ;将CPSR状态寄存器读取,保存到R0中
MRS R1, SPSR ;将SPSR状态寄存器读取,保存到R1中
MSR程序状态寄存器写指令
指令的语法格式如下
MSR{<cond>}CPSR_<fields>, #<immediate_8>
MSR{<cond>}CPSR_<fields>, <Rm>
MSR{<cond>}SPSR_<fields>, #<immediate_8>
MSR{<cond>}SPSR_<fields>, <Rm>
MRS R0, CPSR @ Read the CPSR
BIC R0, R0, #0xF0000000 @Clear the N, Z, C and V bits
MSR CPSR_f, R0 @ Update the flag bits in the CPSR
@ N, Z, C and V flagsnow all clear
MRS R0, CPSR @Read the CPSR
ORR R0, R0, #0x80 @Set the interrupt disable bit
MSR CPSR_c, R0 @ Update the control bits in the CPSR
@ interrupts (IRQ) nowdisabled
MRS R0,CPSR @Read the CPSR
BIC R0,R0, #0x1F @ Clear the mode bits
ORR R0,R0, #0x11 @ Set the mode bits to FIQmode
MSR CPSR_c, R0 @ Update the controlbits in the CPSR
@ now in FIQ mode
MSR CPSR_c,#0x11
00010001
模式位改为FIQ,T位ARM状态,中断都被打开
只有确定了当前IFTmode需要改成一个确定的值时,才用此方法,否则,
-------------------------------------------------------------------------------------------------------------
伪指令:
ARM伪指令不属于ARM指令集中的指令。
定义这些指令可以使ARM汇编程序设计变得更方便。
ARM伪指令可以像其他ARM指令一样使用。
汇编器会自动用一条或多条ARM指令替换ARM伪指令。
ARM的伪指令包括
(1)ADR 小范围地址加载伪指令
(2)ADRL 中等范围地址加载伪指令
(3)LDR 大范围地址加载伪指令(两种写法)
(4)NOP 空指令伪指令
小范围地址加载伪指令 ADR
语法格式
ADR{cond} register, expr
cond:条件码
register:目标寄存器,如:R0等
expr:地址表达式(相对于pc或寄存器而言,以PC或者寄存器为基址,一般以PC为基址)
加载地址范围
地址字对齐时: +/-1020 bytes(255×4)
地址非字对齐时:+/-255bytes
被编译器编译成一条ADD或者SUB指令
...
ADR R1, Delay
...
Delay:
MOV R0, R14
...
...
0x20 ADD R1, PC,#0x3c R1=PC+0x3C=0x28+0x3C
=0x64
...
...
0x64 MOV R0, R14
...
语法格式
ADRL{cond} register, expr
cond:条件码
register:目标寄存器,如:R0等
expr:地址表达式(相对于pc或寄存器)
加载地址范围
地址字对齐时: -256K~256K
地址非字对齐时: -64K~64K
LDR伪指令
语法格式
LDR{cond} register,=[expr | label_expr]
从指令位置到文字池的偏移量必须小于4KB
示例
...
LDR R1, =TestData //将0x12345678的地址给R1
LDR R0, [R1] //将该地址中的数据加载到R0
...
TestData:
.word 0x12345678
示例2
LDR pc, =label
语法格式
LDR{cond} register, label_expr
从指令位置到文字池的偏移量必须小于4KB
示例
...
LDR R1, TestData 直接将0x12345678给R1
...
TestData:
.word 0x12345678
示例2
LDR pc, jmp_table
jmp_table:
.word func_addr
BL
NOP伪指令在汇编时将会被代替成ARM中的空操作,比如可能是“MOV R0,R0”指令等。NOP可用于延时操作。
示例
MOV R1,#0x1234
Delay:
NOP
NOP
SUBS R1,R1,#1
BNE Delay;
MOV PC,LR
LDR R0,[R1]
----------------------------------------------------------------------------------------------------------
总结:
(1)单寄存器存储加载
(2)多寄存器存储加载(IA IB DA DB )
(3)栈(满减栈 DB IA)
(4)状态寄存器的读写命令
(5)伪指令
明天:
(1)伪操作
(2)C和汇编的混合编程