条件执行:
EQ:相等则执行
NE:不相等则执行
GE:大于等于执行
LE:小于等于执行
GT:大于执行
LT:小于执行
AL:无条件执行
伪指令: 是有一些指令,不方便用汇编去实现,汇编器就提供一些指令,用于去实现一些
不好实现的一些功能,最终这些伪指令都要生成相应的汇编指令
操作数2 : 可以是一下几种情况:
1. 可以是寄存器
2. 可以使寄存器移位
3. 可以是立即数
立即数是存在于指令当中,
指令中是有12位,范围0~4095 ,这个数小,实际意义不大,因此发明立即数
什么是立即数: 一个字节的数循环右移(ROR)0 到30 之间的偶数位
装载32 bit常数到寄存器时
ldr rd ,= const (伪指令)
1. const 是立即数时,会变成mov指令
2. const 是有效数时,会变成mvn指令 //这个数本身是立即数或它取反后的数是立即数
3. const 不是有效数时,会变成ldr访问内存,先把这个数放到存储器中,然后再读回来
建议把常数装载到寄存器中时一律使用该伪指令。
ARM处理器的八种寻址方式
1.
立即数寻址
也叫立即寻址,操作数本身就在指令中给出,去出指令也就取到了操作数。
立即数要求以#或$开头
mov r1,#15 //十进制
mov r2,$3
mov r3,#0x10 //十六进制
mov r4,#011 //八进制
mov r5,#0b01010000 //二进制 @0x50
2.
寄存器寻址
寄存器寻址就是利用寄存器中的数值作为操作数,这种寻址方式是各类微处理器经常采用的一种的方式。
ADD R0,R1,R2 @R0=R1+R2
MOV R0,R1 @R0=R1
3.
寄存器移位寻址
ADD R0,R1,R2,LSL #2
mov r0,r1,lsl #2
4.
寄存器间接寻址
ldrb r1,[r0] @ r1 = *r0 r1 = 0x11
mov r2,#5
str r2,[r0] @ *r0 = r2 0x11->0x5
LDR STR Word
LDRB STRB Byte
LDRH STRH Halfword
LDRSB 带符号的byte load
LDRSH 带符号的halfword load
5.
基址变址寻址
基址变址寻址就是将基址寄存器的内容与指令中给出的偏移量相加,
得到一个有效的操作数的地址。通常用于访问连续的地址空间
前索引: LDR R1 , [R0 , #4] @ R0 表示的基地址, #4 偏移量,+-4K -4095 ~ 4095
@ r1 = *( r0 + 4 )
STR R1 , [R0 , #4]
自动索引: LDR R1 , [R0 , #4]! @ R0 表示的基地址, #4 偏移量,+-4K -4095 ~ 4095
@ r1 = *( r0 + 4 ),r0 +=4;
STR R1 , [R0 , #4]!
后索引: LDR R1 , [R0], #4 @ R0 表示的基地址, #4 偏移量,+-4K -4095 ~ 4095
@ r1 = *r0 ,r0 +=4;
STR R1 , [R0], #4
6.
相对寻址
b和bl
b和bl指令的解析:
00020000 <step-0x10>:
20000: e3a01001 mov r1, #1
20004: ea000001 b 20010 <step>
20008: e3a02002 mov r2, #2
2000c: e3a03003 mov r3, #3
00020010 <step>:
20010: e3a04004 mov r4, #4
20014: eafffffe b 20014 <step+0x4>
b lable <==> add pc ,pc #偏移量
偏移量: 0x1
偏移量左移两位: 0x1<<2 (偏移量是按照指令进行计算)
pc = 0x200c
pc + 偏移量 = 0x200c + 4
= 0x20010
跳转范围: 0到23 的范围: 0 ~ 16M ,去除符号位 +-8M 个指令
+-32Mbytes
如何执行长跳转:
ldr pc ,=lable (伪指令) 0~ 4G 范围装载
7.
多寄存器寻址
LDMIA R0!,{R1-R5} @ *r0 = R1,R2,R3,R4,R5 ,r0 +=4 ; i++
STMIA R0!,{R1-R5}
LDMIB R0!,{R1-R5} @ r0 +=4 ,*r0 = R1,R2,R3,R4,R5 ; ++i
STMIB R0!,{R1-R5}
LDMDA R0!,{R1-R5} @ *r0 = R1,R2,R3,R4,R5 ,r0 -=4 ; i--
STMDA R0!,{R1-R5}
LDMDB R0!,{R1-R5} @ r0 -=4 , *r0 = R1,R2,R3,R4,R5 ; --i
STMDB R0!,{R1-R5}
I : 增 D : 减
A : 后 B : 先
规则1: 内存的地址和寄存器的标号是对齐的
内存的高地址对应寄存器的大编号
内存的地地址对应寄存器的小编号
规则2: 用什么方式存,用相反的方式取 例如STMDA与LDMIB
8.
堆栈寻址
LDMFD R0!,{R1-R5} @ r0 -=4 , *r0 = R1,R2,R3,R4,R5 ; --i
STMFD R0!,{R1-R5}
LDMFA R0!,{R1-R5} @ r0 +=4 , *r0 = R1,R2,R3,R4,R5 ; ++i
STMFA R0!,{R1-R5}
LDMED R0!,{R1-R5} @ *r0 = R1,R2,R3,R4,R5, r0 -=4 ; i--
STMED R0!,{R1-R5}
LDMEA R0!,{R1-R5} @ *r0 = R1,R2,R3,R4,R5, r0 +=4 ; i++
STMEA R0!,{R1-R5}
F : 满 E : 空
A : 增 D : 减
规则1:
内存的地址和寄存器的标号是对其的
内存的高地址对应寄存器的大编号
内存的地地址对应寄存器的小编号
规则2:
用什么方式存(压栈),用相同的方式读(出栈)
规则3:
atpcs 标准是用FD方式入栈 FD 方式出栈 例如:STMFD与LDMFD
规则4: stmfd sp!,{r1-r5} <==> push {r1-r5}
ldmfd sp!,{r1-r5} <==> pop {r1-r5}
乘法指令:
32位乘法:
mov r1,#100
mov r2,#200
mul r3,R1,R2
乘加指令
mov r1,#100
mov r2,#200
mov r3,#100
mla r4,r1,r2,r3 @r4=r1*r2+r3
64位的乘法指令:
ldr r1,=0xffffffff
ldr r2,=0xffff
umull r4,r3,r1,r2 @ r4 存放低32位 r3存放高32位
smull r4,r3,r1,r2 @ r4 存放低32位 r3存放高32位
单寄存器数据传送
ldr r0,=myarry
@ 伪指令 取标号所在地址 r0 = myarry
ldr r1,myarry
@ 但寄存器数据传送指令,取标号所在地址内的值 r1 = *myarry
LDR STR Word
LDRB STRB Byte
LDRH STRH Halfword
LDRSB 带符号的byte load
LDRSH 带符号的halfword load
交换指令: SWP
在寄存器和存储器之间,由一次存储器读和一次存储器写组成的原子操作。
完成一个字节或字的交换。
ldr r0,=myarry @ 伪指令 取标号所在地址 r0 = myarry
mov r1,#5
swp r2,r1,[r0] @ r0 基地址,r1 要写入内存的值 ,r2要从内存中读出值 r2=*r0 ,*r0= r1
swpb r2,r1,[r0] @ r0 基地址,r1 要写入内存的值 ,r2要从内存中读出值 r2=*r0 ,*r0= r1
软件中断指令:
swi 0x1000000-1 @ pc -> lr_svc = 0x20018 A: 0x20014 (0x1000000-1 软中断号)
@ pc = 0x08
psr指令:
mrs r0,cpsr @ mov r0,cpsr
mrs r0,spsr @用户模式下不能操作spsr
mov r0,#0xd3
msr cpsr,r0 @ mov cpsr , r0
msr cpsr_c,r0
伪指令:
adr r0,myarry @ 伪指令 r0 = 20018 <myarry>: 基于pc的偏移量 +-1K
adrl r1,myarry @ 伪指令 r1 = 20018 <myarry>: 基于pc的偏移量 +-256K
ldr r2,myarry @ 但寄存器数据传送 取标号所在地址内的值 r2 = * myarry
ldr r3,=myarry @ 伪指令 ,取编号所在的地址 r3 = myarry 0~4G
gnu的伪指令集:
.arch armv7-a cpu的体系结构
.fpu softvfp 软件浮点库
.file "1.c" 文件名
.global a 声明一个符号为全局符号
.data 用来定义一个数据段
.type a, %object 这个a是一个数据类型的
.type main, %function 函数类型
.size a, 1 占用内存的大小,以字节计算
a:
.byte 10 申请一个字节的存储空间,把存储空间赋值为10
.align 1
字节对其 2权次方 2个字节对其
align 2 4个字节对齐
.section .rodata
用来定义一个段
movw r3, #:lower16:a 传送a变量值的低16位
movt r3, #:upper16:a 传送a变量值的高16位
uxtb r2, r3 把r3寄存器内的(一个字节的数)值扩展成一个32值,即对高24位清零 ,放到r2当中
.equ aaaa , 0x0 汇编的宏定义
.if aaaa 预编译
mov r1,#1
mov r2,#2
.else
mov r1,#2
mov r2,#3
.endif
.macro func 宏函数
mov r3,#3
mov r4,#4
.endm
局部标号:局部标号 主要在局部范围内使用而且局部标号可以重复出现。
它由两部组成开头是一个0-99直接的数字局部标号 后面加“:”
1:
mov r1,#1
1:
mov r2,#2
b 1b
mov r3,#3
1:
mov r4,#4
1:
mov r5,#5
F:
向地址增加的增加或则行号增加的方向
B:地址减少的方向或则是行号减少的方向
异常处理的异常向量: 基地址 + 偏移量
基地址: arm7 arm9 arm10基地址可以是0地址也可以是0xffff0000
arm11 cortex-a 这个基地址可以是任意地址
ldr r0,=0x20000 @
设置异常向量表的基地址
mcr p15,0,r0,c12,c0,0 @ c12, Vector Base Address Register,
偏移量: 固定不变的
ldr r0,=0x20000 @ 设置异常向量表的基地址
mcr p15,0,r0,c12,c0,0 @ c12, Vector Base Address Register,
mov r1,#1
mov r2,#2
mov r3,#3
mov r4,#4
mov r5,#5
swi 0x0
@ pc --> lr_svc = 0x20028 - 4 = 0x20024
@ pc = 基地址 + 偏移量
@ = 0x20000 +0x08(SWI偏移量)
@ = 0x20008
异常向量表存放的指令(4种):
1. b handler @+-32M bytes 快
2. mov pc, #立即数 @#立即数 必须是立即数 快
3. ldr pc,=handler @0到4G 慢
4. ldr pc ,lable @0到4G 慢
lable:
.word handler
gnu内联汇编
int a = 10,b = 5,sum =0;
__asm__(
"mov r0,%1\n\t"
"add %0,%1,%2\n\t"
:"+r"(sum)
:"r"(a),"r"(b)
:"r0"
);
/*
* 1. 内联汇编 使用关键字 asm 或者是 __asm__
* 2. 组成 括号使用引号的部分是指令部分,
* 3. 冒号部分: 第一个是输出参数列表
* 第二个是输入参数列表
* 第三个是修饰列表
* 4. %0 表示的是输出和输入参数列表的第1个参数(从上到下,从左到右) sum
* %1表示的是 输出和输入参数列表的第2个参数(从上到下,从左到右) a
* %2表示的是 输出和输入参数列表的第3个参数(从上到下,从左到右) b
* 5. "r" : 表示参数的是用一个寄存器去存放
* "m" : 表示的是一个以有效的内存
* "I" : 表示的一个立即数
* 6. + 表示的是这个参数可读可写
* = 表示的是这个参数只可写
* 无 表示的是这个参数只读
* & 被修饰的操作符只能作为输出
*/