arm指令

ARM处理器共有37个寄存器。这37个寄存器按其在用户编程中的功能划分,可分为2类寄存器,即31个通用寄存器和6个状态寄存器。这6个状态寄存器在ARM公司文件中其名称分别为:CPSR、SPSR_svc、SPSR_abt、SPSR_und、SPSR_irq和SPSR_fig。这12的作用分别如图1所示:

 所有处理器模式下都可访问当前程序状态寄存器CPSR。CPSR中包含条件码标志、中断禁止位、当前处理器模式以及其他状态和控制信息。在每种异常模式下都有一个对用的程序状态寄存器SPSR。当异常出现时,SPSR用于保存CPSR的状态,以便异常返回后恢复异常发生时的工作状态。

(1)条件码标志

N、Z、C、V,最高4位称为条件码标志。ARM的大多数指令可以条件执行的,即通过检测这些条件码标志来决定程序指令如何执行。

各个条件码的含义如下:

N:在结果是有符号的二进制补码情况下,如果结果为负数,则N=1;如果结果为非负数,则N=0。

Z:如果结果为0,则Z=1;如果结果为非零,则Z=0。

C:其设置分一下几种情况:

               对于加法指令(包含比较指令CMN),如果产生进位,则C=1;否则C=0。

               对于减法指令(包括比较指令CMP),如果产生借位,则C=0;否则C=1。

               对于有移位操作的非法指令,C为移位操作中最后移出位的值。

               对于其他指令,C通常不变。

V:对于加减法指令,在操作数和结果是有符号的整数时,如果发生溢出,则V=1;如果无溢出发生,则V=0;对于其他指令,V通常不发生变化。

(2)控制位的作用在图1中可以看出,在这里就不阐述了。

其中cpsr_c代表的是这32位中的低8位,也就是控制位
当你看到有些程序里这样写
msr cpsr_c 0xd2                                       //msr是arm汇编中专门用来修改cpsr这样有特定功能的寄存器的指令

                                                                  //具体请参考Arm汇编手册和Arm体系架构手册

这样的语句时,就是在更改这8位的状态

4.ARM 处理器工作模式:
User : 非特权模式, 大部分任务执行在这种模式
FIQ : 当一个高优先级(fast) 中断产生时将会进入这种模式
IRQ : 当一个低优先级(normal) 中断产生时将会进入这种模式
Supervisor :当复位或软中断指令执行时将会进入这种模式
Abort : 当存取异常时将会进入这种模式
Undef : 当执行未定义指令时会进入这种模式
System : 使用和 User 模式相同寄存器集的特权模式
5.ARM 总共有 37 个寄存器, 但是每种模式下最多只能看到 18 个寄存器。37 个寄存器中 30 个为“通用” 型, 1 个固定用作 PC, 一个固定用作 CPSR, 5 个固定用作 5 种异常模式下的 SPSR

八种寻址方式:
    寄存器寻址 mov r1, r2
    立即寻址 mov r0, #0xFF00
    寄存器移位寻址 mov r0, r1, lsl #3 //r1 左移 3 位给 r0 --> r0=r1*8
    寄存器间接寻址 ldr r1, [r2] //r2 存放的内容指向的地址的值给 r1
    基址变址寻址 ldr r1, [r2, #4] //r2 存放的内容加 4 指向的地址的值给 r1
    多寄存器寻址 ldmia r1!, {r2-r7, r12} //将 r1 内容指向的地址(相当于数组的首地址)依次加载到 r2 到 r7 和 r12 寄存器
    堆栈寻址 stmfd sp!, {r2-r7, lr} //从栈里面依次连续访问多个字节放的寄存器了(即用于压栈操作)
    相对寻址 beq flag //跳转到标号处
    flag: //标号(跳转点)

9.指令后缀:
    同一指令经常附带不同后缀, 变成不同的指令。 经常使用的后缀有:
    B(byte) 功能不变, 操作长度变为 8 位
    H(half word) 功能不变, 长度变为 16 位
    S(signed) 功能不变, 操作数变为有符号
    如 ldr ldrb ldrh ldrsb ldrsh
    S(S 标志) 功能不变, 影响 CPSR 标志位(条件位 N、 Z、 C、 V)
    如 mov 和 movs movs r0, #0 (这里条件位取决于 r0)

条件执行后缀

moveq r0, r1 @ 如果 eq 后缀成立, 则直接执行 mov r0, r1; 如果 eq不成立则本句代码直接作废, 相当于没有  @ 类似于 C 语言中 if (eq){r0 = r1;}
条件后缀执行注意 2 点:
1、 条件后缀是否成立, 不是取决于本句代码, 而是取决于这句代码之前的代码运行后的结果(CPSR 标志位)。
2、 条件后缀决定了本句代码是否被执行, 而不会影响上一句和下一句代码是否被执行。

11.多级指令流水线:
PC 指向正被取指的指令, 而非正在执行的指令.
若 PC 指向的指令地址是 0x3000_0008 则正在执行的指令地址是0x3000_0000(所以 PC 指向某指令则该指令之前的第二条指令正在执行)。

12.数据处理指令:
数据传输指令 mov mvn
算术指令 add sub rsb adc sbc rsc
逻辑指令 and orr eor bic
比较指令 cmp cmn tst teq
乘法指令 mvl mla umull umlal smull smlal
前导零计数 clz
mov r1, r0 @两个寄存器之间数据传递
mov r1, #0xff @ 将立即数赋值给寄存器
mvn 和 mov 用法一样, 区别是 mov 是原封不动的传递, 而 mvn是按位取反后传递


and 逻辑与
orr 逻辑或
eor 逻辑异或
bic 位清除指令
bic r0,r1,#0x1f @ 将 r1 中的数的 bit0 到 bit4 清零后赋值给 r0


13.比较指令:
cmp 例如cmp r0, r1 等价于 sub r2, r0, r1 (r2 = r0 - r1),并根据结果设置CPSR的标志位。
cmn 例如cmn r0, r1 等价于 add r0, r1,并根据结果设置CPSR的标志位
tst 例如tst r0, #0xf @测试 r0 的 bit0~bit3 是否全为 0
teq 测试等价(注意: teq 是对 2 个数, 进行 eor(异或) )
比较指令用来比较 2 个寄存器中的数
注意: 比较指令不用后加 s 后缀就可以影响 cpsr 中的标志位。
实例:
CMP R1,R0 ;将寄存器R1的值与寄存器R0的值相减,并根据结果设置CPSR的标志位
CMP R1,#100 ;将寄存器R1的值与立即数100相减,并根据结果设置CPSR的标志位
CMN R1,R0 ;将寄存器R1的值与寄存器R0的值相加,并根据结果设置CPSR的标志位
CMN R1,#100 ;将寄存器R1的值与立即数100相加,并根据结果设置CPSR的标志位


14.cpsr 访问指令:
mrs 用来读 psr, msr 用来写 psr
cpsr 和 spsr 的区别和联系:
cpsr 是程序状态寄存器, 整个 SoC 中只有 1 个; 而 spsr 有 5 个, 分别在 5 种异常模式下。
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr, r0
等价于
msr cpsr_c, #0xd3 @I & F disable, Mode: 0x13 - svc
说明:
msr cpsr_cxsf,r1 ;这里的 cxsf 表示从低到高分别占用的 4 个 8bit 的数据域
CPSR 有 4 个 8 位区域:
标志域(F)、状态域(S)、扩展域(X)、控制域(C)
指令中有时还有出现 cpsr_cf, cpsr_all, cpsr_c 等, 这里:
c 指 CPSR 中的 control field ( PSR[7:0])
f 指 flag field (PSR[31:24])
x 指 extend field (PSR[15:8])
s 指 status field ( PSR[23:16])
其中 cpsr 的位表示为:
31 30 29 28 --- 7 6 - 4 3 2 1 0
N Z C V I F M4 M3 M2 M1 M0

15.跳转(分支)指令:
b  直接跳转(就没打开算返回)
bl (branch and link), 跳转前把返回地址放入 lr 中, 以便返回, 以便用于函数调用
bx 跳转同时切换到 ARM 模式, 一般用于异常处理的跳转。

16.访存指令:
ldr/str & ldm/stm & swp
单个字/半字/字节访问 ldr/str
例: ldr ldrb ldrh
多字批量访问 ldm/stm
swp 内存与寄存器互换指令,一边读一边写
例:
swp r1, r2, [r0] @把 r0 中内存的地址的值给 r1,同时把 r2 寄存器的值写入内存。
swp r1, r1, [r0] @把内存中的值给 r1, 同时把 r1 原来的值给内存


17.汇编函数调用方法:
   mov r14, r15  //保存函数返回地址到lr
   ldr r15, show //pc指针赋值执行函数
   mov r0,r0
show:
   .word 0x33f94aa8   //假设这个地址存放printf函数
   
   
18.合法立即数与非法立即数:
ARM汇编立即数构成规则:必须是一个8位的二进制数,前面补上24位二进制0,扩展为32位;然后将这个32位的扩展数首尾相连循环偶数位得到。
给定一个立即数,判断其是否合法可以分三步:
首先将给定的立即数写成32位二进制的形式;然后看能不能用一个8位的二进制数包括所有含1的部分,如不能则非法;最后看这个8位二进制数能不能循环移动偶数位得到给定的立即数,不能数则非法。 1的个数超过8个一定不合法。
举例如下:
0xff=00000000 00000000 00000000 11111111:相当于8位二进制11111111循环右移0位得到,合法;
0x104=00000000 00000000 00000001 00000100:相当于8位二进制01000001循环右移2位得到,合法;
0x101=00000000 00000000 00000001 00000001:包含所有1的部分是100000001,无法用一个8位二进制表示,非法;
0x102=00000000 00000000 00000001 00000010:包含所有1的部分是10000001,但10000001只能循环右移奇数位得到给定的数,非法;
0xfC000002 =11111100 00000000 00000000 00000010:相当于8位二进制10111111循环移动6位得到,合法。
0x8000007E=10000000 00000000 00000000 01111110:包含所有1的部分是11111101,但10000001只能循环移动奇数位得到给定的数,非法。
   
19.软中断指令:
swi(software interrupt):
软中断指令用来实现操作系统中系统调用。


20.协处理器 cp15 操作指令:
mcr & mrc
mrc 用于读取 CP15 中的寄存器
mcr 用于写入 CP15 中的寄存器
协处理器和 MMU、 cache、 TLB 等处理有关, 功能上和操作系统的虚拟地址映射、 cache 管理等有关。


21.MRC & MCR 的使用方法:
mcr{<cond>} p15, <opcode_1>, <Rd>, <Crn>, <Crm>, {<opcode_2>}
opcode_1: 对于 cp15 永远为 0
Rd: ARM 的普通寄存器
Crn: cp15 的寄存器, 合法值是 c0~c15
Crm: cp15 的寄存器, 一般均设为 c0
opcode_2: 一般省略或为 0
例:
/***disable MMU stuff and caches*****/
mrc p15, 0, r0, c1, c0, 0 @将 CP15 的寄存器 C1 的值读到 r0 中
bic r0, r0, #0x00002000 @clear bits 13 (--v-)
bic r0, r0, #0x00000007 @clear bits 2:0 (-CAM)
orr r0, r0, #0x00000002 @set bit 1 (--A-) Align
orr r0, r0, #0x00000800 @set bit 11 (Z---) BTB
mcr p15, 0, r0, c1, c0, 0 @将 r0 的值写到 CP15 的寄存器 C1 中

22.CP15 的寄存器 C1
访 问主标识符寄存器的指令格式如下所示:
mrc p15, 0, r0, c1, c0{, 0} ; 将 CP15 的寄存器 C1 的值读到 r0 中
mcr p15, 0, r0, c1, c0{, 0} ; 将 r0 的值写到 CP15 的寄存器 C1 中

CP15 中的寄存器 C1 的编码格式及含义说明如下:
31 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
附 加 L4 RR V I Z F R S B L D P W C A M

位 说 明:
M  0 : 禁止 MMU 或者 PU ; 1 : 使能 MMU 或者 PU
A  0 : 禁止地址对齐检查; 1 : 使能地址对齐检查
C  0 : 禁止数据 / 整个 cache ; 1 : 使能数据 / 整个 cache
W  0 : 禁止写缓冲; 1 : 使能写缓冲
P  0 : 异常中断处理程序进入 32 位地址模式; 1 : 异常中断处理程序进入 26 位地址模式
D  0 : 禁止 26 位地址异常检查; 1 : 使能 26 位地址异常检查
L  0 : 选择早期中止模型; 1 : 选择后期中止模型
B  0 : little endian ; 1 : big endian
S  在基于 MMU 的存储系统中, 本位用作系统保护
R  在基于 MMU 的存储系统中, 本位用作 ROM 保护
F  0 : 由生产商定义
Z  0 : 禁止跳转预测功能; 1 : 使能跳转预测指令
I  0 : 禁止指令 cache ; 1 : 使能指令 cache
V  0 : 选择低端异常中断向量 0x0~0x1c ; 1 : 选择高端异常中断向量 0xffff0000~ 0xffff001c
RR  0 : 常规的 cache 淘汰算法, 如随机淘汰; 1 : 预测性淘汰算法,如 round-robin 淘汰算法
L4  0 : 保持 ARMv5 以上版本的正常功能; 1 : 将 ARMv5 以上版本与以前版本处理器 兼容, 不根据跳转地址的 bit[0] 进行 ARM 指令和 Thumb 状态切换: bit[0] 等于 0 表示 ARM 指令, 等于 1 表示 Thumb 指令。

举例(来自于 uboot)
/********使能 MMU*********/
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #1 @M 位置 1
mcr p15, 0, r0, c1, c0, 0

23.多寄存器访问指令:
ldr/str 每周期只能访问 4 字节内存, 如果需要批量读取、 写入内存时太慢, 解决方案是 stm/ldm。
sdm (load register mutiple)
stm (store register mutiple)
举例(uboot start.S 537 行) :
stmia sp, {r0 - r12}
--将r0存入sp 指向的内存处(假设为0x30001000);然后地址+4(即指向0x30001004),将r1存入该地址;然后地址再+4(指向0x30001008 ),将r2存入该地址······直到r12内容放入(0x30001030),指令完成。
--一个访存周期同时完成13个寄存器的读写。


24.8 种后缀:
ia(increase after)  先传输,再地址+4。  空增栈
ib(increase before) 先地址+4,再传输。 满增栈
da(decrease after)  先传输,再地址-4。  空减栈
db(decrease before) 先地址-4,再传输。 满减栈
fd(full decrease)   满递减堆栈。
ed(empty decrease)  空递减堆栈。
fa(·······) 满递增堆栈。
ea(·······) 空递增堆栈。

25.四种栈:
空栈: 栈指针指向空位, 每次存入时可以直接存入然后栈指针移动一格;而取出时需要先移动一格才能取出。
满栈: 栈指针指向栈中最后一格数据, 每次存入时需要先移动栈指针一格再存入;取出时可以直接取出, 然后再移动栈指针。
增栈: 栈指针移动时向地址增加的方向移动的栈。
减栈: 栈指针移动时向地址减小的方向移动的栈。


26.! 的作用:
ldmia r0, {r2 - r3}//因为 ld 是读内存(r0 是内存指向的地址) ia 是先传输, 再地址加 4, 即先把 r0 指向的地址里的内容放到 r2,再地址加 4, 后地址里的内容读到 r3 (注意: 因为不加“!” 所以地址加 4 的结果不存放在 r0 中, 是临时变量不保存)
ldmia r0! , {r2 - r3}
(注意:“!” 的作用是把地址变化的结果存放在 r0 中保存)
感叹号的作用:就是 r0 的值在 ldm 过程中发生的增加或者减少最后写回到 r0 去, 也就是说 ldm 时会改变 r0 的值。


27.^的作用:
ldmfd sp!, {r0 - r6, pc} //满递减 ”fd”先传输再减
ldmfd sp!, {r0 - r6, pc}^
^的作用: 在目标寄存器中有 PC 时, 会同时将 SPSR 写入到 CPSR,一般用于从异常模式返回。

28.伪指令的意义:
--伪指令和指令的根本区别是经过编译后会不会生成机器码。
--伪指令的意义在于指导编译过程。

29.gnu 汇编中的一些符号:
@ 用来做注释。 可以在行首也可以在代码后面同一行直接跟, 和 C语言中//类似
# 做注释, 一般放在行首, 表示这一行都是注释而不是代码。
: 以冒号结尾的是标号
. 点号在 gnu 汇编中表示当前指令的地址
# 立即数前面要加#或$, 表示这是个立即数

30.常用 gnu 伪指令:
.global _start @ 给_start 外部链接属性(类似于 c 语言中的 extern 的全局声明)
.section .text @ 指定当前段为代码段
.ascii .byte .short .long .word @用于定义数据变量(常用)
.quad .float .string @ 定义数据变量(不常用)
.align 4 @ 以 16 字节对齐
.balignl 16, 0xabcdefgh @ 16 字节对齐填充
.equ @ 类似于 C 中宏定义(实际上在 arm-gcc 中可以用define 定义所以.equ 不常用)
实例:
IRQ_STACK_START:
.word 0x0badc0de
等价于 unsigned int IRQ_STACK_START = 0x0badc0de;

 

31.字节对齐

.align 4 @ 16 字节对齐
.align 2 @ 4 字节对齐
.balignl 16, 0xdeadbeef @ 对齐 + 填充
b 表示位填充; align 表示要对齐; l 表示 long, 以 4 字节为单位填充; 16 表示
16 字节对齐; 0xdeadbeef 是用来填充的原料。
例: .balignl 16, 0xdeadbeef 执行后(伪指令编译后会不会生成机器码) 代码指令存放如下:
0x00000008: 上一条指令
0x0000000c 0xdeadbeef
0x00000010: 下一条指令


32.标签使用:
ldr r0, lable    //取标签处的值即88888
ldr r1, =lable   //取标签的地址
lable:
    .word 88888

33.偶尔会用到的 gnu 伪指令:
.end     @标识文件结束
.include @ 头文件包含
.arm / .code32   @声明以下为 arm 指令
.thumb / .code16 @声明以下为 thubm 指令

34.最重要的几个伪指令:
ldr 大范围的地址加载指令(不用考虑是不是合法立即数)。
adr 小范围的地址加载指令。
adrl 中等范围的地址加载指令。
nop 空操作。
ARM 中有一个 ldr 指令, 还有一个 ldr 伪指令。
一般都使用 ldr 伪指令而不用 ldr 指令。
ldr 如果是指令则立即数前是 “#”。
ldr 如果是伪指令则立即数前是“=”, 如果是标号就不用加“=” 了。

例:
ldr 指令: ldr r0, #0xff
伪指令:   ldr r0, =0xfffl @涉及到合法/非法立即数, 涉及到 ARM 文字池

35.adr 与 ldr:
--adr 编译时会被 1 条 sub 或 add 指令替代, 而 ldr 编译时会被一条mov 指令替代或者文字池方式处理;
--adr 总是以 PC 为基准来表示地址, 因此指令本身和运行地址有关,可以用来检测程序当前的运行地址在哪里。
--ldr 加载的地址和链接时给定的地址有关, 由链接脚本决定。

36.adr 和 ldr 的差别:
ldr 加载的地址在链接时确定,而adr加载的地址在运行时确定;所以我们可以通过adr和ldr加载的地址比较来判断当前程序是否在链接时指定的地址运行。

2)CPU不会对内存中的数据进行直接操作,所有的计算都要求在寄存器(里面存放着指令、数据和地址供CPU计算使用)中运行,而寄存器与内存的通信则有专有的指令(ldr,str,ldm,stm,swp)来完成。所以相比CISC,它有更多的通用寄存器可以使用,每个寄存器都可以进行数据存储或者寻址

就是每家银行在自己的卡片里面放了一个只有自己认可的卡信息,我们称为磁道(35、36域)或者ICdate(55域),这里面究竟放了什么,只有每家银行自己知道(连银联也不知道),我们平时在POS上面消费,是刷卡or插卡or挥卡,机器读到这张卡信息后,输入密码,完成支付。银行收到卡信息和密码后,一比对,发现这是一笔合法的交易,然后就成功了。所以对于POS机来说,只要读到了卡信息,输入了密码,它就把这笔交易往后仍,返回成功就成功,POS机本身是没有校验卡信息里面的具体内容是否合法的功能的,校验都是在银行自己那里



 

 

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值