ARMv8之arm64架构汇编知识

1. 寄存器

1.1. 通用寄存器

    31R0~R30,每一个寄存器能够存取一个64位大小的数。 当使用 x0~x30访问时,是一个 64位的数;当使用 w0~w30访问时,是一个 32 位的数,访问的是寄存器的低32位,如下图所示:


1.2. 向量寄存器

(也可以叫做浮点寄存器)每一个寄存器的大小是 128 位的。 分别能够用Bn、Hn、Sn、Dn、Qn的方式来访问不一样的位数。如下图:

  • Bn: 一个 Byte的大小,即 8 位
  • Hn: half word,即 16 位
  • Sn: single word,即 32 位
  • Dn: double word,即 64 位
  • Qn: quad word,即128 位

1.3. 特殊寄存器

  • sp: (Stack Pointer),栈顶寄存器,用于保存栈顶地址;
  • fp(x29): (Frame Pointer)为栈基址寄存,用于保存栈底地址;
  • lr(x30): (Link Register) ,保存调用跳转指令 bl 指令的下一条指令的内存地址;
  • zr(x31): (Zero Register),xzr/wzr分别表明 64/32 位,其做用就是 0,写进去表明丢弃结果,读出来是 0
  • pc: 保存将要执行的指令的地址(有操做系统决定其值,不能改写)。

1.4. 状态寄存器

    CPSR (Current Program Status Register)和其余寄存器不同,其余寄存器是用来存放数据的,都是整个寄存器具备一个含义;而 CPSR 寄存器是按位起做用的,即,每一位都有专门的含义,记录特定的信息;以下图数据结构

  • CPSR 的 低8位(包括 IFT 和 M[4:0])称为控制位,程序没法修改,除非 CPU 运行于 特权模式 下,程序才能修改控制位。
  • NZCV 均为条件码标志位;其内容可被算术或逻辑运算的结果所改变,而且能够决定某条指令是否被执行。

    • N(Negative)标志: CPSR 的第 31 位是 N,符号标志位;记录相关指令执行后其结果是否为负数,若是为负数,则 N = 1;若是是非负数,则 N = 0
    • Z(Zero)标志: CPSR 的第 30 位是 Z,0标志位;记录相关指令执行后,其结果是否为0,若是结果为0,则 Z = 1;若是结果不为0,则 Z = 0
    • C(Carry)标志: CPSR 的第 29 位是C,进位标志位

      • 加法运算:当运算结果产生了 进位 时(无符号数溢出),C = 1,不然 C = 0 ;
      • 减法运算(包括 CMP): 当运算时产生了 借位 时(无符号数溢出),C = 0,不然 C = 1 。
    • V(Overflow)标志: CPSR 的第 28 位是 V,溢出标志位;在进行有符号数运算的时候,若是超过了机器所能标识的范围,称为溢出。

注: CPSR 寄存器是 32 位的。


2. arm64函数调用约定

  • x0~x7寄存器分别存放函数的前 8个参数,从左到右依次使用x0~x7;若是参数个数超过了8个,多余的参数压栈,被调用函数通过栈来读取。
  • 函数的返回值通常都在x0上;若函数返回值是一个较大的数据结构时,结果会存在x8执行的地址上。

3. 常见汇编指令

  • mov: 将某一寄存器的值复制到另外一寄存器(只能用于寄存器与寄存器或者寄存器与常量之间传值,不能用于内存地址)

    mov x1, x0        ; 将寄存器 x0 的值复制到寄存器x1中
  • add: 将某一寄存器的值和另外一寄存器的值相加 并将结果保存在另外一寄存器中

add x0, x0, #1    ; 将寄存器 x0 的值和常量 1 相加后保存在寄存器 x0 中 
add x0, x1, x2    ; 将寄存器 x1 和 x2 的值相加后保存到寄存器 x0 中 
add x0, x1, [x2]  ; 将寄存器 x1 的值加上寄存器 x2 的值做为地址,再取该内存地址的内容放入寄存器 x0 中
  • sub: 将某一寄存器的值和另外一寄存器的值 相减 并将结果保存在另外一寄存器中
sub x0, x1, x2        ; 将寄存器 x1 和 x2 的值相减后保存到寄存器 x0 中 
  • mul: 将某一寄存器的值和另外一个寄存器的值 相乘 并将结果保存在另外一寄存器中
mul x0, x1, x2        ; 将寄存器 x1 和 x2 的值相乘后结果保存到寄存器 x0 中
  • sdiv:(有符号数,对应 udiv: 无符号数)将某一寄存器的值和另外一个寄存器的值 相除 并将结果保存在另外一寄存器中
sdiv x0, x1, x2       ; 将寄存器 x1 和 x2 的值相除后结果保存到寄存器 x0 中
  • and: 将某一寄存器的值和另外一寄存器的值 按位与 并将结果保存到另外一寄存器中
and x0, x0, #0xf      ; 将寄存器 x0 的值和常量 0xf 按位与后保存到寄存器 x0 中 
  • orr: 将某一寄存器的值和另外一寄存器的值 按位或 并将结果保存到另外一寄存器中
orr x0, x0, #9        ; 将寄存器 x0 的值和常量 9 按位或后保存到寄存器 x0 中
  • eor: 将某一寄存器的值和另外一寄存器的值 按位异或 并将结果保存到另外一寄存器中
eor x0, x0, #0xf      ; 将寄存器 x0 的值和常量 0xf 按位异或后保存到寄存器 x0 中 
  • str: (store register) 将寄存器中的值写入到内存中
str w9, [sp, #0x8]    ; 将寄存器 w9 中的值保存到栈内存 [sp + 0x8] 处
  • strb: (store register byte) 将寄存器中的值写入到内存中(只存储一个字节)
strb w8, [sp, #7]     ; 将寄存器 w8 中的低 1 字节的值保存到栈内存 [sp + 7] 处
  • ldr: (load register) 将内存中的值读取到寄存器中
ldr x0, [x1]          ; 将寄存器 x1 的值做为地址,取该内存地址的值放入寄存器 x0 中 
ldr w8, [sp, #0x8]    ; 将栈内存 [sp + 0x8] 处的值读取到 w8 寄存器中 
ldr x0, [x1, #4]!     ; 将寄存器 x1 的值加上 4 做为内存地址, 取该内存地址的值放入寄存器 x0 中, 而后将寄存器 x1 的值加上 4 放入寄存器 x1 中 
ldr x0, [x1], #4      ; 将寄存器 x1 的值做为内存地址,取内该存地址的值放入寄存器 x0 中, 再将寄存器 x1 的值加上 4 放入寄存器 x1 中 
ldr x0, [x1, x2]      ; 将寄存器 x1 和寄存器 x2 的值相加做为地址,取该内存地址的值放入寄存器 x0 中 
  • ldrsb: (load register byte) 将内存中的值(只读取一个字节)读取到寄存器中
ldrsb	w8, [sp, #7]    ; 将栈内存 [sp + 7] 出的 低 1 字节的值读取到寄存器 w8 中
  • stur: 同 str 将寄存器中的值写入到内存中(通常用于地址运算中)
stur w10, [x29, #-0x4]    ; 将寄存器 w10 中的值保存到栈内存 [x29 - 0x04] 处 
  • ldur: 同 ldr 将内存中的值读取到寄存器中(通常用于  地址运算中)
ldur w8, [x29, #-0x4]     ; 将栈内存 [x29 - 0x04] 处的值读取到 w8 寄存器中
  • stp: 入栈指令(str 的变种指令,能够同时操做两个寄存器)
stp x29, x30, [sp, #0x10] 	; 将 x29, x30 的值存入 sp 偏移 16 个字节的位置 
  • ldp: 出栈指令(ldr 的变种指令,能够同时操做两个寄存器)
ldp x29, x30, [sp, #0x10] 	; 将 sp 偏移 16 个字节的值取出来,存入寄存器 x29 和寄存器 x30
  • scvtf: (Signed Convert To Float)带符号 定点数 转换为 浮点数
scvtf	d1, w0      ; 将寄存器 w0 的值(顶点数,转化成 浮点数) 保存到 向量寄存器/浮点寄存器 d1 中
  • fcvtzs: (Float Convert To Zero Signed)浮点数 转化为 定点数 (舍入为0)
fcvtzs w0, s0	    ; 将向量寄存器 s0 的值(浮点数,转换成 定点数)保存到寄存器 w0 中
  • cbz: 和 0 比较(Compare),若是结果为零(Zero)就转移(只能跳到后面的指令)
  • cbnz: 和非 0 比较(Compare),若是结果非零(Non Zero)就转移(只能跳到后面的指令)
  • cmp: 比较指令,至关于 subs,影响程序状态寄存器 CPSR
  • cset: 比较指令,知足条件,则并置 1,不然置 0
cmp w8, #2        ; 将寄存器 w8 的值和常量 2 进行比较
cset w8, gt       ; 若是是大于(grater than),则将寄存器 w8 的值设置为 1,不然设置为 0
  • brk: 能够理解为跳转指令特殊的一种
  • LSL: 逻辑左移
  • LSR: 逻辑右移
  • ASR: 算术右移
  • ROR: 循环右移
  • adrp: 用来定位数据段中的数据用, 由于 aslr 会致使代码及数据的地址随机化, 用 adrp 来根据 pc 作辅助定位
  • b: (branch)跳转到某地址(无返回), 不会改变 lr (x30) 寄存器的值;通常是本方法内的跳转,如 while 循环,if else 等
b LBB0_1      ; 直接跳转到标签 ‘LLB0_1’ 处开始执行
  • bl: 跳转到某地址(有返回),先将下一指令地址(即函数返回地址)保存到寄存器 lr (x30)中,再进行跳转 ;通常用于不一样方法直接的调用
bl 0x100cfa754	; 先将下一指令地址(‘0x100cfa754’ 函数调用后的返回地址)保存到寄存器 ‘lr’ 中,而后再调用 ‘0x100cfa754’ 函数
  • blr: 跳转到 某寄存器 (的值)指向的地址(有返回),先将下一指令地址(即函数返回地址)保存到寄存器 lr (x30)中,再进行跳转
blr x20       ; 先将下一指令地址(‘x20’指向的函数调用后的返回地址)保存到寄存器 ‘lr’ 中,而后再调用 ‘x20’ 指向的函数
  • br: 跳转到某寄存器(的值)指向的地址(无返回), 不会改变 lr (x30) 寄存器的值。
  • brk: 能够理解为跳转指令特殊的一种。
  • ret: 子程序(函数调用)返回指令,返回地址已默认保存在寄存器 lr (x30) 中

参考资料

arm64 架构之入栈/出栈操做 - JavaShuo

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>