ARM架构基础知识

ARM下的寄存器

函数的 1 - 4 个参数分别由 R0 - R3 寄存器来保存,剩下的参数则是从右往左依次压入栈中
R0 同时还被用于存储函数的返回值
注意:虽然arm为32位架构,但是它和x86不同,它不是单纯使用栈来传递参数

R0 <-> rdi 以及 存储函数返回值
R1 <-> rsi
R2 <-> rdx
R3 <-> rcx
R7 -> 用于存放系统调用号
R11 -> ebp(FP)
R13 -> esp(SP)
R14(LP) -> 存放函数返回地址
R15(PC) -> eip 存储着当前指令往后两个指令
不使用ret,而是直接使用pop指令对PC进行赋值

ARM下的指令(主要记录x86_64架构下没有的指令)

LDR指令

LDR{条件} <目标寄存器>, <addr>
作用:
加载指定地址上的数据放入到指定寄存器中
举例:
LDR R0,[R1] ;将存储器地址为R1的字数据读入寄存器R0
LDR R0,[R1,R2] ;将存储器地址为R1+R2的字数据读入寄存器R0 
LDR R0,[R1,#8] ;将存储器地址为R1+8的字数据读入寄存器R0 
LDR R0,[R1,R2] ! ;将存储器地址为R1+R2的字数据读入寄存器R0,并将新地址R1+R2写入R1
LDR R0,[R1,#8] ! ;将存储器地址为R1+8的字数据读入寄存器R0,并将新地址R1+8写入R1
LDR R0,[R1],R2 ;将存储器地址为R1的字数据读入寄存器R0,并将新地址R1+R2写入R1
LDR R0,[R1,R2,LSL#2]! ;将存储器地址为R1+R2×4的字数据读入寄存器R0,并将新地址R1+R2×4写入R1 
LDR R0,[R1],R2,LSL#2 ;将存储器地址为R1的字数据读入寄存器R0,并将新地址R1+R2×4写入R1

TEQ指令

TEQ{条件} 操作数1,操作数2
作用:
将操作数1和操作数2进行异或,并将结果存储在标志位Z中。若操作数12相等则Z=1若果不相等Z=0
举例:
TEQ R0, R1

STR指令

STR{条件} 源寄存器,<存储器地址>
作用:
STR指令用于从源寄存器中将一个32位的字数据传送到存储器中。该指令在程序设计中比较常用,且寻址方式灵活多样,使用方式可参考指令LDR
举例:
STR R0,[R1],#8 ;将R0中的字数据写入以R1为地址的存储器中,并将新地址R1+8写入R1
STR R0,[R1,#8] ;将R0中的字数据写入以R1+8为地址的存储器中

LDM(Load Multiple)与STM(Store Multiple)指令
LDM和STM指令(可以用于替代PUSH和POP,但在aarch64中被舍弃)
功能概述

  • LDM:从连续内存地址加载多个数据到寄存器组。
  • STM:将寄存器组中的多个数据存储到连续内存地址。
  • 核心作用:批量数据传输,适用于数组操作、栈管理、函数调用时的现场保护等场景

寻址模式

模式全称操作描述典型用途
IAIncrement After加载/存储后地址递增4字节正向遍历内存块
IBIncrement Before加载/存储前地址递增4字节较少使用(ARM模式特有)
DADecrement After加载/存储后地址递减4字节反向遍历内存块
DBDecrement Before加载/存储前地址递减4字节栈操作(满递减栈)

指令条件
cond :条件码(如EQ、NE),控制指令是否执行
mode :寻址模式(如IA、IB、DA、DB)或堆栈模式(如FD、ED)
Rn :基址寄存器,存储内存起始地址
! :可选后缀,表示更新基址寄存器(Rn)的值
register_list :寄存器列表,用逗号分隔或范围表示(如{r0-r3, r5}
^ :特权模式标志(仅在系统模式下使用)

LDM指令

LDM{cond}<mode> Rn{!}, <register_list>{^}

举例:
LDMIA R0!, {r1-r4} ;从R0指向的地址依次加载到r1→r4,完成后R0 += 16

STM指令

STM{cond}<mode> Rn{!}, <register_list>{^}

举例:
STMDB R1!, {r5-r8} ;将r5→r8逆序存储到R1-16地址,完成后R1 -= 16

ARM支持四种堆栈类型,通过LDM/STM的不同模式实现

类型全称栈指针指向操作指令
FDFull Descending最后一个入栈项STMDB(压栈)
LDMIA(弹栈)
EDEmpty Descending下一个空位STMDA(压栈)
LDMIB(弹栈)
FAFull Ascending最后一个入栈项极少使用
EAEmpty Ascending下一个空位极少使用

默认使用FD栈,对应:

  • 压栈:STMDB SP!, {reglist}(地址递减前存储)
  • 弹栈:LDMIA SP!, {reglist}(地址递增后加载)

PUSH与POP指令
功能概述

  • PUSH:将寄存器内容压入栈顶
  • POP:从栈顶恢复寄存器内容
  • 本质:PUSH和POP是STM和LDM的语法糖,专为栈操作优化

条件
reglist:支持 低寄存器(r0-r7)或 高寄存器(r8-r12, lr, pc等),具体取决于指令集(ARM/Thumb)

PUSH指令

PUSH {reglist} ;等效于 STMDB SP!, {reglist}

举例:
PUSH {r0-r3, lr} 压栈保存r0-r3和返回地址

POP指令

POP {reglist} 等效于 LDMIA SP!, {reglist}

举例:
POP {r0-r3, pc} 恢复r0-r3并跳转返回(将lr弹入pc)

栈操作细节

  • 地址更新:每次压栈后SP减4×N字节(N为寄存器数量),弹栈后SP增4×N字节。
  • Thumb模式限制:Thumb指令集的PUSH/POP仅支持低寄存器和特定高寄存器 (比如 lr, pc)

其他指令
add r1, r2, #2 相当于 r1 = r2 + 2
sub r1, r2, r3 相当于 r1 = r2 - r3
还有跳转指令B相关的一些指令,相当于jmp
B Label :无条件跳转到Label
BL Label:当程序跳转到标号Label处执行时,同时将当前的PC值保存到R14
还有一些带判断的跳转指令:
1.b.ne是不等则跳转
2.b.eq是等于则跳转
3.b.le是大于则跳转
4.b.ge是小于则跳转
5.b.lt是大于等于则跳转
6.b.gt是小于等于则跳转
7.cbz为结果等于零则跳转
8.cbnz为结果非零则跳转
MOV R0, R1 ; 将R1的值复制到R0
MOV R0, R1, LSL#3 ; R0 = R1左移3位后的值(等效乘以8)
MOV PC, LR ; 从子程序返回(跳转至LR保存的地址)

AARCH64下的寄存器

aarch64 实际上就是 arm 的64位版本
它的寄存器在64位下都叫作Xn寄存器,其对应的低32位叫作Wn寄存器
X0 ~ X7用来依次传递参数,同时X0存放着函数返回值
X8常用来存放系统调用号或一些函数的返回结果,
X30存放着函数的返回地址(aarch64中的RET指令返回X30寄存器中存放的地址)
其中栈顶是X31(SP)寄存器,栈帧是X29(FP)寄存器
X32PC寄存器

x0 <-> rdi 或 函数返回值
x1 <-> rsi
x2 <-> rdx
x3 <-> rcx
x4 <->5个参数
x5 <->6个参数
x6 <->7个参数
x7 <->8个参数
x29 <-> (FP) 栈帧寄存器
x30 <-> 存放返回地址(aarch64中的RET指令返回X30寄存器中存放的地址)
x31 <-> rsp 栈顶寄存器
x32 <-> rip(PC)

注意:arm架构中的ret只是返回,并不会改变sp指针

AARCH64下与ARM不同的指令

aarch64架构下指令的一大变化就是,不再使用pushpop指令压栈和弹栈了,也没有LDMSTM指令,而是使用STPLDP指令

STP和LDP指令

STP指令

STP x4, x5, [sp, #0x20] 将sp+0x20处依次覆盖为x4,x5即x4入栈到sp+0x20,x5入栈到sp+0x28最后sp的位置不变

LDP指令

LDP x29, x30, [sp], #0x40 将sp弹栈到x29,sp+0x8弹栈到x30最后sp += 0x40

其中,STPLDP中的Ppair(一对)的意思,也就是说,仅可以同时读/写两个寄存器

在aarch64架构下比arm架构新增了BLR指令,也是用于跳转的指令,下面是它对比BL指令

特征BL指令BLR指令
跳转目标类型静态地址(PC相对偏移)动态地址(寄存器存储的绝对地址)
地址范围限制±32MB(AArch64)无限制(支持全64位地址空间)
返回地址保存将PC+4存入X30(LR)同BL
典型应用场景直接调用固定位置的函数函数指针调用、虚表跳转、动态链接库调用
安全性机制目标地址固定,不易被篡改需配合BTI/PAC防御ROP攻击
编译器优化可内联展开或尾调用优化通常无法优化,需保留完整调用链
流水线行为目标地址可预测,分支预测效率高目标地址动态变化,依赖BTB(Branch Target Buffer)缓存
使用方法对比:
BL指令
BL target_label ;arget_label为符号地址,编码为PC + 偏移量
LR = PC + 4; // 保存返回地址 
PC = PC + offset; // 跳转到目标标签地址

BLR指令

BLR Xn ;Xn寄存器存储目标函数地址

X30(LR) = PC + 4; // 保存返回地址 
PC = Xn; // 跳转到寄存器指向的地址

ARM架构下的系统调用号

基于arm架构的linux系统调用号:
unistd32.h - arch/arm64/include/asm/unistd32.h - Linux source code v5.13.19 - Bootlin Elixir Cross Referencer
基于aarch64架构的linux系统调用号:
unistd.h - include/uapi/asm-generic/unistd.h - Linux source code v5.13.19 - Bootlin Elixir Cross Referencer

参考:
1.arm-pwn 学习 · De4dCr0w’s Blog
2.[原创] CTF 中 ARM & AArch64 架构下的 Pwn-Pwn-看雪-安全社区|安全招聘|kanxue.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值