寄存器
CPU的运算速度是非常快的,为了性能CPU在内部开辟一小块临时存储区域,并在进行运算时先将数据从内存复制到这一小块临时存储区域中,运算时就在这一小快临时存储区域内进行。我们称这一小块临时存储区域为寄存器。
常用的寄存器
寄存器 | 描述 |
---|---|
r0 - r30 | 通用整型寄存器,64 位,当使用 x0 - x30 访问时,代表的是 64 位的数;当使用 w0 - w30 访问的时候,访问的是这些寄存器的低 32 位 |
fp(x29) | 保存栈帧地址(栈底指针) |
lr(x30) | 通常称x30为程序链接寄存器,保存子程序结束后需要执行的下一条指令 |
sp(x31) | 保存栈指针,使用 sp/wsp 来进行对 sp 寄存器的访问 |
PC | PC寄存器存的是当前执行的指令的地址。在 arm64 中,软件是不能改写 pc 寄存器的 |
SPRs | 状态寄存器,存放状态标识,可分为 CPSR (The Current Program Status Register) 和 SPSRs(The Save Program Status Registers)。一般都是使用 CPSR,当发生异常时,CPSR 会存入 SPSR。当异常恢复,再拷贝回 CPSR |
zr | 零寄存器,里面存的是 0 (zero register)一般使用 wzr/xzr ,w 代表 32位,x 代表 64 位 |
v0 - v31 | 向量寄存器,也可以说是浮点型寄存器,每个寄存器大小是 128 位,可以用 Bn Hn Sn Dn Qn 来访问不同的位数(8 16 32 64 128) |
常用的运算指令
运算指令 | 描述 | 含义 |
---|---|---|
mov x1,x0 | 将寄存器x0的值赋值给x1 | 数据传送 |
add x0,x1,x2 | x0 = x1 + x2 | 加法 |
sub x0,x1,x2 | x0 = x1 - x2 | 减法 |
mul x0,x1,x2 | x0 = x1 * x2 | 乘法 |
sdiv x0,x1,x2 | x0 = x1 / x2 | 除法 |
and x0,x0,#0xF | x0 = x0 & #0xF | 与操作 |
orr x0,x0,#9 | x0 = x0 或 #9 | 或操作 |
eor x0,x0,#0xF | x0 = x0 ^ #0xF | 异或操作 |
lsl x0, #1 | x0<<1 | 逻辑左移 |
add x0, x1, x2; // 把 x1 + x2 = x0 这样一个操作。
sub sp, sp, 0x30; // 把 sp - 30 存入sp.
cmp x11, #4; // 相当于 subs xzr, x11, #4.
// 如果 x11 - 4 == 0, 那么状态寄存器NZCV.Z = 1
// 如果 x11 - 4 < 0, 那么 NZCV.N = 1
NZCV是状态寄存器中存的几个状态值,分别代表运算过程中产生的状态,其中:
- N, negative condition flag,一般代表运算结果是负数
- Z, zero condition flag, 运算结果为0
- C, carry condition flag, 无符号运算有溢出时,C=1。
- V, oVerflow condition flag 有符号运算有溢出时,V=1。
寻址指令
分为两种,存和取
L 打头的基本都是取值指令,如 LDR(Load Register)、LDP(Load Pair)
S 打头的基本都是存值指令,如 STR(Store Register)、STP(Store Pair)
ldr x0,[x1] ;从 x1 指向的地址里面取出一个64位大小的数存入x0
ldp x1,x2,[x10, #0x10] ;从 x10+0x10 指向的地址里面取出2个64位的数,分别存入x1、x2
str x5,[sp, #24] ;往内存中写数据(偏移值为正), 把 x5 的值(64位的数值)存到 sp+24 指向的地址内存上
stur w0,[x29, #0x8] ;往内存中写数据(偏移值为负),将 w0 的值存储到 x29 - 0x8 这个地址里
stp x29,x30,[sp, #-16]! ;把 x29、x30 的值存到 sp-16 的地址上,并且把sp-=16 Note:后面有个感叹号的,然后没有stup这个指令哈
ldp x29,x30,[sp],#16 ;从 sp 地址取出16 byte数据,分别存入x29、x30,然后 sp+=16
注:ldr既可以当读取地址的伪指令,也可以是内存访问指令。当第二个参数前面有”=”时,表示伪指令。否则表示内存访问指令。操作数都是32bits的。
其中寻址的格式由分为下面这3种类型:
[x10, #0x10] // signed offset。 意思是从 x10 + 0x10的地址取值
[sp, #-16]! // pre-index。 意思是从 sp-16地址取值,取值完后在把 sp-16 writeback 回 sp
[sp], #16 // post-index。 意思是从 sp 地址取值,取值完后在把 sp+16 writeback 回 sp
跳转指令
bl/b bl 是有返回的跳转;b 是无返回的跳转,BL的L也可以理解为Lr
1.存了LR也就意味着可以返回到本方法继续执行。一般用于不同方法直接的调用
2.B相关的跳转没有LR,一般是本方法内的跳转,如while循环,if else等。
跳转相关的指令还会有种逻辑运算,就是condition code。配合状态寄存器中的状态标示,以实心点.开头的都是表示条件,如 b.ne ,一般用于 if else 。 常见的条件码有以下这些:
adrp指令
adrp x0, x1
1. 将1的值,左移12位 1 0000 0000 0000 == 0x1000
2.将PC寄存器的低12位清零 0x1045228b0 ==> 0x104522000
3.将将1 和 2 的结果相加 给 X0 寄存器
注:地址为pc寄存器左边的地址,adrp是找出要获取参数的地址范围,然后下个pc寄存器执行的代码会定位到准确的物理地址。(一般找到范围后下一句会add 后三位的具体地址从而确定具体值)。
参考资料