寻址方式

ARM汇编转换网站:https://armconverter.com/

寄存器间接寻址

LDR指令

将内存中的数据加载到寄存器中

ARM32: LDR R1, [R2] --> R1 = *R2
处理器执行 LDR R1, [R2] 时,它会查看寄存器 R2 里存储的数值,将其作为一个内存地址,然后从这个内存地址对应的存储单元中读取数据,最后把读取到的数据存放到寄存器 R1 中。
ARM64: LDR X1, [X2] --> X1 = *X2
LDP X1, X2, [X0]
从 X0 寄存器的值所表示的内存地址处,读取一个 64 位的数据,并将其存储到寄存器 X1 中。
接着,从 X0 + 8(因为每个 64 位数据占 8 字节)所指向的内存地址处,再读取一个 64 位的数据,并将其存储到寄存器 X2 中。

STR指令

将寄存器的数据存入内存中

ARM32: STR R1, [R2] --> *R2 = R1
该指令会把寄存器 R1 里的数据存到以寄存器 R2 的值作为地址的内存单元中。比如,若 R1 中的值是 0x1234,R2 中的值是 0x40000000,那么就会把 0x1234 存到内存地址 0x40000000 处。
ARM64: STR X1, [X2] --> *X2 = X1
STP X1, X2, [X0]
STP:表明这是一条存储一对寄存器值到内存的指令。
X1, X2:这是要存储的寄存器对。X1 和 X2 属于 64 位通用寄存器。此指令会把 X1 和 X2 中的值存到指定的内存地址。
[X0]:这是内存地址,它由寄存器 X0 中的值来确定。指令会把 X1 的值存到 X0 指向的内存地址,将 X2 的值存到 X0 + 8 所指向的内存地址(因为在 64 位系统中,每个寄存器是 8 字节)。

基址变址寻址

ARM32: LDR R1, [R2, #4] --> R1 = *(R2+4);
ARM64: LDR X1, [X2, #4] --> X1 = *(X2+4);
LDR R4, [R10, R2, LSL #1] -->R4 = *(R10 + R2<<1)

ARM32栈寻址

入栈	STMFD SP!, {R0-R3} 从右往左 --> PUSH{R!!, LR}
出栈 LDMFD SP!,{R4-R7} 从左往右 --> POP{R11, LR} / POP {R11, PC}

ARM64栈寻址

STP X29, X30, [SP, #0x10]
STP:代表这是一条存储一对寄存器值到内存的指令。
X29, X30:X29 和 X30 属于 64 位通用寄存器。在 ARM64 架构里,X29 一般作为帧指针(Frame Pointer,FP),用于标记当前函数栈帧的起始位置;X30 通常作为链接寄存器(Link Register,LR),用来保存子程序的返回地址。此指令会把 X29 和 X30 中的值存到指定的内存地址。
[SP, #0x10]:这是内存地址的表达方式。SP 是栈指针(Stack Pointer),指向当前栈的栈顶。#0x10 是一个偏移量,也就是 16 字节。所以,[SP, #0x10] 指的是从 SP 所指向的地址偏移 16 字节后的内存地址。具体而言,X29 的值会被存到 SP + 0x10 这个地址,X30 的值会被存到 SP + 0x10 + 8(因为在 64 位系统中,每个寄存器是 8 字节)这个地址。
LDP X29, X30, [SP, #0X10]

ARM32读写PC寄存器

ARM32可以直接读写PC

ARM32:写PC寄存器 写多少就是多少

MOV PC, #0x6000

写PC寄存器相当于无条件跳转

ARM32:读PC寄存器,ARM指令+8, Thumb指令+4

ADD PC, PC, #4c

跳转指令相当于间接读写PC寄存器

ARM64读写PC寄存器

ARM64不能直接读写PC寄存器,只能间接读写PC寄存器

ADR、ADRP、ADRL相当于间接读PC

一般定位全局资源会用到,字符串、全局变量等

跳转指令相当于间接读写PC寄存器

ARM64读PC,就是当前指令的地址,不需要额外加值

MOV指令

指令里的立即数不是随便放的,常规情况下可以携带16个bit位

ARM64

movz w8, #0x5678	会将其他bit位清零
movz w8, #0x5678, LSL 16 左移4位
movk w8, #0x5768, LSL 16 不会将其他bit位清零

ARM32

MOV R0, #0x5678
MOVT R0, #0x1234

读内存,地址需要四字节对齐,如果不齐就需要向下取整

主要出现在ARM32中,ARM64除了数据以外基本都是4字节的,很少有这个问题

比如,[0x14c6]相当于读[0x14c4]

指令后缀

同一指令附带不同后缀,具有额外作用

常用后缀

B(byte)功能不变,操作长度变成8位,LDRB

H(half word) 功能不变,长度变为16位,LDRH

S(signed)功能不变,操作数变为有符号,LDRSB

S(S标志)功能不变,影响CPSR标志位,MOVS

SPSR标志位

N:结果为负数时N=1,结果为正数或零时N=0

Z:结果为0时Z=1,否则Z=0

C:一般情况下加法进位,减法无借位时C=1,对于结合以为操作的非加/减法指令,C为最后移出的值

V:当进行加法/减法运算,并且有符号溢出时V=1,否则V=0,其它指令V通常不变

条件执行后缀

ARM32

CMP R0, R1
ADDNE R0, R0, #0x10 不相等执行
SUBEQ R0, R1, #0x10 相等执行

ARM64

B.NE loc_1730

调用约定

参数的传递

ARM32:前四几个寄存器R0-R3存参数,更多的存栈中

ARM64:前八个寄存器X0-X7存参数,更多的存栈中

结果的传递

ARM32:R0,不够就加上R1

ARM64:X0,返回结构体有可能存放在X8里面

汇编c逆向