可可西

ARM64汇编基础

ARM64(也称 AArch64)有如下寄存器:

  • 64 位通用寄存器:X0~X30
  • 栈指针寄存器:SP
  • 链接寄存器(返回地址):LRX30
  • 程序计数器:PC(不可直接读写)

注1:x0~x7 是 ARM64 ABI 规定的函数参数传递寄存器,这里是将原始参数存入栈,后续可用于回调或者做参数修改

注2:x29 是 ARM64 典型的frame pointer,一般用来标记当前栈帧的开始,便于调用栈复杂操作和回溯。例如:mov x29, sp   将当前sp存入x29寄存器

 

函数参数传递

ARM64函数参数是通过寄存器优先传递的(寄存器传递效率高,无需栈操作),参数数量超出寄存器或大对象参数,才用栈传递(多余的参数会压到栈上,由被调函数通过栈来读取)

(1) 前 8 个整数类型或指针类型参数,分别用 x0 ~ x7 这 8 个寄存器传递

(2) 如果参数是浮点类型(floatdouble),用 v0 ~ v7 这 8 个浮点寄存器传递

void foo(int a, int b, int c, int d, int e, int f, int g, int h, int i) { ... } // a,b,c,d,e,f,g,h通过x0,x1...,x7寄存器传递,第9个参数i通过栈传递

(3) 如果参数是小的结构体或数组,ABI 会试图通过一组寄存器传递;如果参数很大(结构体等),可能通过栈或指针传递

 

函数返回值

返回值一般用 x0(整数/指针) 或 v0(浮点) 返回。如果多个返回值(如结构体),会用 x0/x1 等或栈。

 

数据处理类指令

指令作用示例
MOV 数据搬移(赋值)

MOV X0, X1  // X0 = X1;

ADD 加法运算

ADD X0, X1, X2 // X0 = X1 + X2;

SUB 减法运算

SUB X3, X3, #1  // X3 = X3 - 1;

MUL 乘法

MUL X0, X1, X2  // X0 = X1 * X2;

DIV 除法

SDIV X0, X2, #5  // X0 = X2 / 5;

NEG 取反

NEG X1, X2

CMP 比较(设置条件标志位)

CMP X4, #100 

TST 按位与并根据结果设置标志位

TST X0, X1

 

逻辑类指令

指令作用示例
AND 按位与

AND X0, X1, X2

ORR 按位或

ORR X0, X1, X2

EOR 按位异或

EOR X0, X1, X2

LSL 左移

LSL X1, X2, #3

LSR 逻辑右移

LSR X3, X4, #2

ASR 算术右移

ASR X5, X6, #1

 

分支与跳转类指令

指令作用示例
B 无条件跳转

B loop_start  // 跳转到loop_start标签

BL 跳转到子程序(带返回地址)

BL functionA  // 调用functionA函数。会保存返回地址到X30寄存器

RET 返回

RET

CBZ 等于零则跳

CBZ X0, label  // if (X0==0) goto label;

CBNZ 不为零则跳

CBNZ W1, label  // if (w1!=0) goto label;

BEQ/ BNE 条件跳转 (等于/不等于)

BEQ label

BGT/ BLT 条件跳转 (大于/小于)

BGT label

 

内存访问类(读写)指令

指令作用示例
LDR 加载(从内存到寄存器) LDR X0, [X1, #8] // 加载地址为X1+8的数据到X0寄存器
STR 存储(从寄存器到内存) STR W2, [X3]  // 将W2数据写到为X3的地址的内存中
LDUR 非对齐加载 LDUR W5, [X6, #2]
STUR 非对齐存储 STUR X7, [X8, #4]

 

栈操作类指令

指令作用示例
PUSH * 压栈(用 STP 模拟)

STP X1, X2, [SP, #-16]! // 将当前的帧指针(x1)和返回地址(x2)压入栈,同时为当前函数开辟栈空间(这里是 16字节),[sp, #-16]! 表示先把 SP 指针向下移动 16 字节(为局部变量等腾空间),再把 x1/x2 存到新位置

stp x0, x1, [sp, #0x90] // 将x0、x1的值存储到栈的特定偏移[sp, #0x90] 上

POP * 出栈(用 LDP 模拟)

LDP X0, X1, [X17, #0x10]  // 把 X17+0x10 处的两个 64 位内容装载到 X0、X1。这一般用于取"调用接口参数"(CIF,一种 FFI 调用描述结构)和"函数指针(fn)"

ldp x17, x16, [x16]   // 以 x16 为地址,从 [x16] 取出 16 字节数据,前8字节放到 x17,后8字节放到 x16 自己

注:ARM64 没有直接 PUSH/POP 指令,用 STP/LDP 结合 SP 操作模拟。

其它常见指令

指令作用示例
NOP 空操作(无结果) NOP
ADR 计算地址寄存到寄存器 adr    x16, #-0x4000  // 把当前指令地址减去 0x4000,存到 x16
BR 跳转到寄存器地址 br x16   // 无条件跳转到 x16 中保存的地址处继续执行代码

posted on 2025-12-24 20:35  可可西  阅读(3)  评论(0)    收藏  举报

导航