ARM汇编

作者: 生产八哥 | 来源:发表于2021-04-14 13:40 被阅读0次

    汇编基本知识

    高级语言可以通过编译得到汇编语言,汇编语言再编译成机器语言,机器语言也可以反汇编成汇编语言。每一条机器指令都有与之对应的汇编指令。在汇编中,大部分指令都是与CPU/内存相关的。

    内存中除了指令,还有数据,但是都是0和1组合,CPU是如何区分的?是通过CPU上的部件PC寄存器来区分。因为在内存里数据和指令本质没有区别,那么要加以区分就是看是否被PC指向过,CPU将pc指向的内存单元的内容看做指令。

    CPU会先将内存中的数据存储到通用寄存器中,然后再对寄存器中的数据进行运算


    寄存器

    针对arm64的CPU来说,
    如果寄存器以x开头,则表明是一个64位的寄存器
    如果寄存器以w开头,则表明是一个32位的寄存器
    32位的寄存器是64位寄存器的低32位部分,并不是独立存在的
    

    ARM64拥有有31个64位的通用寄存器 x0 到 x30,通常用来做数据计算的临时存储、累加、计数、地址保存等功能,和其他三个SP、PC、CPSR寄存器。 因为64位CPU可以兼容32位.所以可以只使用64位寄存器的低32位.w0 就是 x0的低32位。

    FP(x29):保存栈帧地址,指向方法栈的底部
    LR(x30):通常称X30为程序链接寄存器,保存子程序结束后需要执行的下一条指令
    SP :保存栈指针,指向方法栈的顶部,使用 SP/WSP来进行对SP寄存器的访问。

    • X0 - X7:这 8 个寄存器主要用来存储传递参数。如果参数超过 8 个,则会通过栈来传递;X0 也用来存放上文方法的返回值;
    • X29:即我们通常所说的帧指针FP(Frame Pointer),指向当前方法栈的底部(高地址)。帧指针FP保存的为“上一栈帧地址+返回地址”,其中返回地址就是调用者执行调用函数后的下一条指令的地址。
    • X30:即链接寄存器 LR(Link Register)。为什么叫做链接,是因为这个寄存器会记录着当前方法的调用方地址,即当前方法调用完成时应该返回的位置。例如我们遇到 Crash 要获取方法堆栈,其本质就是不断的向上递归每一个 X30 寄存器的记录状态(也就是栈上 X30 寄存器的内容)来找到上层调用方。
      除了这些通用寄存器,还有一个最重要的 SP 寄存器:
    • SP 寄存器:即我们通常说的栈指针 SP(Stack Pointer)。指向当前方法栈的顶部(低地址),与通用寄存器低 32 位的访问方法一样,你也可以通过 WSP 来访问 SP 的低 32 位。当 SP 移动到栈区的最低位置(接近于堆区),则称之为”爆栈“。
    • PC(Program Counter):程序计数器,俗称PC指针,总是指向即将要执行的指令,在arm64中,软件是不能改写PC寄存器的。因为在内存里数据和指令本质没有区别,那么要加以区分就是看是否被PC指向过,CPU将pc指向的内存单元的内容看做指令。mov指令不能更改PC寄存器的值,需要通过bl跳转指令来改变PC寄存器的值。
    • CRSP: 状态寄存器
    • 浮点和向量寄存器

    可以通过register read 寄存器 来打印寄存器地址。

    大部分操作系统栈的增长方向都是从上往下(包括iOS/Mac),Stack Pointer指向栈顶部,Frame Pointer指向上一栈帧的Stack Pointer值,通过Frame Pointer就可以递归回溯获取整个调用栈


    常见命令

    • b:用于不返回的跳转
    • bl:用于子程序跳转,要返回地址,返回地址存于LR中。当发生bl跳转前,会在寄存器 R14 (即LR)中保存当前PC-4,即bl跳转指令的下一条指令的地址。所以在返回时只要 MOV pc,lr 。
    • bl命令可操作PC寄存器
    • callq:方法调用
    • ldr: 将内存中的值读取到寄存器中
    • cmp: 比较指令
    • str: 将寄存器中的值写入到内存中
    • cbz: 和 0 比较,如果结果为零就转移(只能跳到后面的指令)
    • cbnz: 和非 0 比较,如果结果非零就转移(只能跳到后面的指令)
    • ret: 子程序(函数调用)返回指令,返回地址已默认保存在寄存器 lr (x30) 中
    • MOV指令:是数据传送指令,也是最基本的编程指令,用于将一个数据从源地址传送到目标地址(寄存器间的数据传送本质上也是一样的)。其特点是不破坏源地址单元的内容,只能用于寄存器与寄存器或者寄存器 与常量之间传值,不能用于内存地址。不区分大小写,例如mov和MOV是一样的.
    mov x1, x0   将寄存器x0的值复制到寄存器x1中
    
    add x0, x1, x2 将寄存器x1和x2的值相加后保存到寄存器x0中
    
    sub x0, x1, x2 将寄存器x1和x2的值相减后保存到寄存器x0中
    
    and x0, x0, #0x1 将寄存器x0的值和常量1按位与后保存到x0中
    
    orr x0, x0, #0x1 将寄存器x0的值和常量1按位或后保存到寄存器x0中
    
    str x0, [x0, x8] 将寄存器x0中的值保存到栈内存 [x0 + x8]处
    
    ldr x0, [x1, x2] 将寄存器x1和寄存器x2的值相加作为地址,取该内存地址的值放入寄存器x0中
    
    stp x29, x30, [sp, #0x10] ; 将 x29, x30 的值存入 sp 偏移 16 个字节的位置
    
    将内存区域的i值+1并赋值给a的步骤如下
    mov x0, i   先将i值放到x0寄存器中
    add x0, 1   将x0中的值+1
    mov a , x0  赋值给x0
    

    相关文章

      网友评论

          本文标题:ARM汇编

          本文链接:https://www.haomeiwen.com/subject/ariklltx.html