首页
社区
课程
招聘
系统总结ARM基础
发表于: 2024-4-20 20:35 24077

系统总结ARM基础

2024-4-20 20:35
24077

一般的我们的电脑都是X86架构的机器,这里我们使用clang来对我们的文件进行编译,自己编译文件,放入ida中对照着学习更容易理解一点

我们学习ARM架构的时候,我们常常会听说从arm状态转为thumb状态。这里记录一下龙去脉

随着ARM架构的发展,在许多方面都有所用到,但是我们ARM的指令集都是32位,或者64位的,随着手机等设备对32位处理器需求的不断增加,功耗和成本都变得十分关键。如何减少程序占用空间大小的问题亟待解决,这个时候,arm公司就推出了ARM7TDMI处理器,在其上面就能支持了16位指令集,即thumb。 thumb出现的目的是实现更高的代码密度,本质上是对我们的ARM指令的扩充。

ARM处理器具有从ARM状态到Thumb状态和从Thumb状态到ARM状态的无缝转换能力,可以根据需要动态切换指令集

一些区别:

总得来说,thumb就是实现一个更高性能,更高代码密度的ARM指令分支。

ARM共有37个寄存器,都是32位长度的寄存器(具体可以看后面的工作模式图)
37个寄存器中其中前31个(0~30)是通用寄存器(模式不同,使用的时候有所区别),最后2个(31,32)是专用寄存器(sp 寄存器和 pc 寄存器)。 5个固定用作5种异常模式下的SPSR。

ARM架构的通用寄存器是用于执行大多数指令的寄存器,可存储临时数据、地址和中间计算结果。

R0-R12:通用目的寄存器

R13 (SP):堆栈指针寄存器

R14 (LR):链接寄存器

R15 (PC):程序计数器

CPSR寄存器包含当前程序状态信息,包括:

异常发生(如中断)时,当前CPSR自动保存到SPSR,以便异常处理后恢复先前状态。每种异常模式有自己的SPSR。

Arm-v8架构有31个通用寄存器X0-X30 (64位长),而Arm-v7架构仅有16个通用寄存器R0-R15(32位长)

64寄存器总的来说有两种不同的使用,一种就是当原本的64位的寄存器来访问,另一种就是为了兼容32位,将64位寄存器拆成32位的寄存器来使用

通用寄存器的访问方式有2种:

对于一些专用寄存器的访问方式:

栈帧指针寄存器:32位,使用 WSP 来引用,64位,使用 SP 来引用

零寄存器:32位,使用 WZR 来引用,64位,使用 ZR 来引用。

正常程序执行的默认模式。

用于处理快速中断请求,有额外的寄存器以减少中断服务例程的执行时间。

用于处理普通的中断请求。

用于操作系统的内核级别操作,通常在系统启动或系统调用时进入。

当执行了未定义的指令时进入此模式。 在异常或中断发生时,处理器会自动切换到相应的模式,并使用该模式下的寄存器集。

当发生数据或指令预取中止时进入此模式。

用于运行操作系统的内核代码,与用户模式共享相同的寄存器。

ARM 架构下常见的函数调用约定有两种:

AAPCS(ARM Architecture Procedure Call Standard)

AAPCS-VFP(ARM Architecture Procedure Call Standard with the Vector Floating-Point extension)

AAPCS 是 ARM 架构的默认函数调用约定,适用于大多数 ARM 架构的编译器和操作系统。它定义了函数参数的传递方式、栈的使用规则以及寄存器的分配方式。

AAPCS-VFP 是在 AAPCS 的基础上添加了向量浮点扩展(Vector Floating-Point extension)的函数调用约定。它适用于需要使用浮点运算的函数。

将 R2 中的值移动到 R1 中。

将 0xFF00 立即数移动到 R0 中。

将 R1 左移 3 位的结果移动到 R0 中。

将 R2 指向的地址中的值加载到 R1 中。

将 R2 加上 4 所得的地址中的值加载到 R1 中。

将 R1 中的值加载到 R2-R7 和 R12 中,然后将 R1 加上 32。

将 R2-R7、LR 的值存储到堆栈中,然后将 SP 减去 24。

如果条件码为 EQ,则跳转到标签 flag 处。

B 强制跳转

BL 带返回的跳转,将返回地址放入LR寄存器中

BLX 带返回和带状态的切换跳转指令 arm → thumb

Bx 带状态的跳转

mov 赋值

ADD 加

SUB 减

AND

EOR:异或

ORR:或

BIC:与非 , 可以实现的 Bit Clear的功能

MUL 一般乘法:

MLA 带加法的乘法:

由于32位寄存器 没有办法存64位的大数,因此需要两个寄存器来存储,64位的乘法操作就会发送改变

SMULL 64位乘法:

SMLAL 64位带加法的乘法

UMULL 64位无符号乘法

UMLAL 64位无符号带加法的乘法

LSL:逻辑左移指令,将寄存器中的值向左移动指定的位数,移动时右侧空出的位补零。

LSR:逻辑右移指令,将寄存器中的值向右移动指定的位数,移动时左侧空出的位补零。

ROR:循环右移指令,将寄存器中的值向右移动指定的位数,移动时左侧空出的位补上右侧的位。

ASR:算术右移指令,将寄存器中的值向右移动指定的位数,移动时左侧空出的位补上符号位。

RRX:扩展的循环右移指令,将寄存器中的值向右移动一位,同时将 C 标志位的值作为最低位插入到左侧。

ARM汇编采用RISC架构,CPU本身并不能直接的读取内存,而是需要先将内存中的内存加载进入CPU通用寄存器之中,才能被我们的CPU进行处理

ldr 读取

str 存储

ldr与 str 指令的后缀与变种

CMP  比较两个操作数的值

CMN 比较两个操作数的值的补码

TST 将两个操作数进行按位与运算,并根据结果设置条件码。

TEQ 将两个操作数进行按位异或运算,并根据结果设置条件码。

空栈:栈指针指向空位,每次存入时可以直接存入然后栈指针移动一格;而取出时需要先移动一格才能取出
满栈:栈指针指向栈中最后一格数据,每次存入时需要先移动栈指针一格再存入;取出时可以直接取出,然后再移动栈指针

增栈:栈指针移动时向地址增加的方向移动的栈
减栈:栈指针移动时向地址减小的方向移动的栈

ia(increase after :先传输,再地址+4
ib(increase before : 先地址+4,再传输
da(decrease after: 先传输,再地址-4
db(decrease befor : 先地址-4,再传输

fd(full decrease):满递减堆栈
ed(empty decrease):空递减堆栈
fa:满递增堆栈
ea:空递增堆栈

在理解的时候我们就可以将其拆开理解,比如LDMIA 就是LDM IA 两部分理解一些例子:

从地址 r0 开始读取 4 个字(word),分别存储到 r1-r4 寄存器中,然后将地址 r0 增加 4。

将地址 r0 增加 4,然后从新地址开始读取 3 个字,分别存储到 r1-r3 寄存器中。

从地址 r0 开始读取 2 个字,分别存储到 r1-r2 寄存器中,然后将地址 r0 减少 4,并将读取的最后一个字存储到 lr 寄存器中。

将 r1-r3 寄存器中的数据存储到地址 sp 指向的存储器中,然后将 sp 减少 16(4 个字),并将 lr 寄存器中的数据存储到新的地址 sp 指向的存储器中。

一般的,当感叹号 "!" 出现在寄存器名称后面时,就表示在执行指令后会更新该寄存器的值。如果没有!,表示执行指令前不更新该寄存器的值。

这里感叹号的作用就是r0的值在ldm过程中发生的增加或者减少最后写回到r0去,第二句的ldm时会改变r0的值,而第一句,没有!,运行之后不会更新 r0 的值

^的作用:在目标寄存器中有pc时,会同时将spsr写入到cpsr,一般用于从异常模式返回。

偏移量方法

实现的操作:

r0= *(r1 + 4)

事先更新

实现的操作:

r0 = *(r1 + 4)

r1 = r1 +4

事后更新:

实现的操作:

r0=*r1
r1=r1+4

//将我们的文件编译成ARMv5架构的文件(32位)
clang -target armv-linux-android21 demo.c -o demo
//将我们的文件编译成ARMv7-A架构的文件 (32位)
clang -target armv7a-linux-android21 demo.c -o demo
//将我们的文件编译成AArch64 架构的文件(64位)
clang -target aarch64-linux-android21 1.cpp -o demo
//将我们的文件编译成ARMv5架构的文件(32位)
clang -target armv-linux-android21 demo.c -o demo
//将我们的文件编译成ARMv7-A架构的文件 (32位)
clang -target armv7a-linux-android21 demo.c -o demo
//将我们的文件编译成AArch64 架构的文件(64位)
clang -target aarch64-linux-android21 1.cpp -o demo
clang -target arm-linux-android21 -E demo.c -o demo.i
clang -target arm-linux-android21 -E demo.c -o demo.i
clang -target arm-linux-android21eabi -S demo.i -o demo.s 
clang -target arm-linux-android21eabi -S demo.i -o demo.s 
clang -target arm-linux-android21eabi -S demo.s -o demo.o
clang -target arm-linux-android21eabi -S demo.s -o demo.o
clang -target arm-linux-android21eabi -S demo.o -o demo
clang -target arm-linux-android21eabi -S demo.o -o demo
clang -target arm-linux-android21 -S -mthumb demo.c -o demo.s
clang -target arm-linux-android21 -S -mthumb demo.c -o demo.s
寄存器 说明
X0 寄存器 用来保存返回值(或传参)
X1 ~ X7 寄存器 用来保存函数的传参
X8寄存器 也可以用来保存返回值
X9 ~ X28寄存器 一般寄存器,无特殊用途
x29(FP)寄存器 用来保存栈底地址
X30 (LR)寄存器 用来保存返回地址
X31(SP) 寄存器 用来保存栈顶地址
X31(ZR)寄存器 零寄存器,恒为0
X32(PC)寄存器 用来保存当前执行的指令的地址
mov r1, r2
mov r1, r2
mov r0, #0xFF00
mov r0, #0xFF00
mov r0, r1, lsl #3
mov r0, r1, lsl #3
ldr r1, [r2]     //r1=*r2
ldr r1, [r2]     //r1=*r2
ldr r1, [r2, #4]  ; r1=*(r2+4)
ldr r1, [r2, #4]  ; r1=*(r2+4)
ldmia r1!, {r2-r7, r12}
ldmia r1!, {r2-r7, r12}
stmfd sp!, {r2-r7, lr}
stmfd sp!, {r2-r7, lr}
beq flag
flag:
beq flag
flag:
B label  //无条件跳转到标签 label 处
B label  //无条件跳转到标签 label 处
BL label //跳转到标签 label 处,并将返回地址存储在 LR 中
BL label //跳转到标签 label 处,并将返回地址存储在 LR 中
BLX label  //跳转到标签 label 处,并将返回地址存储在 LR 中。可以实现 ARM 和 Thumb 之间的切换
BLX label  //跳转到标签 label 处,并将返回地址存储在 LR 中。可以实现 ARM 和 Thumb 之间的切换
BX R1   // 跳转到地址存储在 R1 中的位置,并切换到相应的指令集模式
BX R1   // 跳转到地址存储在 R1 中的位置,并切换到相应的指令集模式
MOV R0, R1 //将 R1 中的值赋值到 R0 中。
MOV R0, R1 //将 R1 中的值赋值到 R0 中。
ADD R0, R1, R2 //将 R1 和 R2 中的值相加,然后将结果存储到 R0 中。
ADD R0, R1, R2 //将 R1 和 R2 中的值相加,然后将结果存储到 R0 中。
SUB R0, R1, R2  //
SUB R0, R1, R2  //
AND R0, R1, R2 //将 R1 和 R2 中的值进行按位与操作,然后将结果存储到 R0 中。
AND R0, R1, R2 //将 R1 和 R2 中的值进行按位与操作,然后将结果存储到 R0 中。
EOR R0, R1, R2 //将 R1 和 R2 中的值进行按位异或操作,然后将结果存储到 R0 中。
EOR R0, R1, R2 //将 R1 和 R2 中的值进行按位异或操作,然后将结果存储到 R0 中。
ORR R0, R1, R2  //将 R1 和 R2 中的值进行按位或操作,然后将结果存储到 R0 中。
ORR R0, R1, R2  //将 R1 和 R2 中的值进行按位或操作,然后将结果存储到 R0 中。
BIC R0, R1, #0xf  //将 R1 和立即数 #0xf 进行按位与非操作,然后将结果存储到 R0 中。
 
//将R1   低4位清0
BIC R0, R1, #0xf  //将 R1 和立即数 #0xf 进行按位与非操作,然后将结果存储到 R0 中。
 
//将R1   低4位清0
MUL  r0 r1,r2   //r0 = r1 * r2  乘法
MUL  r0 r1,r2   //r0 = r1 * r2  乘法
MLA  r0,r1,r2,r3  //r0 = r1 * r2 + r3   带加法的乘法
MLA  r0,r1,r2,r3  //r0 = r1 * r2 + r3   带加法的乘法
SMULL  r0,r1 ,r2 ,r3  // r0 = (r2 * r3)的低32位   r1 = (r2 * r3)的高32位
SMULL  r0,r1 ,r2 ,r3  // r0 = (r2 * r3)的低32位   r1 = (r2 * r3)的高32位
SMLAL  r0,r1 ,r2 ,r3  //r0 = (r2 * r3)的低32位 + r0    r1 = (r2 * r3)的高32位 + r1
SMLAL  r0,r1 ,r2 ,r3  //r0 = (r2 * r3)的低32位 + r0    r1 = (r2 * r3)的高32位 + r1
UMULL r0,r1 ,r2 ,r3  // r0 = (r2 * r3)的低32位   r1 = (r2 * r3)的高32位 
UMULL r0,r1 ,r2 ,r3  // r0 = (r2 * r3)的低32位   r1 = (r2 * r3)的高32位 
UMLAL   r0,r1 ,r2 ,r3  //r0 = (r2 * r3)的低32位 + r0    r1 = (r2 * r3)的高32位 + r1 
UMLAL   r0,r1 ,r2 ,r3  //r0 = (r2 * r3)的低32位 + r0    r1 = (r2 * r3)的高32位 + r1 
LSL R0, R1, #2 // 将 R1 中的值左移 2 位,结果存储到 R0 中
LSL R0, R1, #2 // 将 R1 中的值左移 2 位,结果存储到 R0 中
LSR R0, R1, #3 // 将 R1 中的值右移 3 位,结果存储到 R0 中
LSR R0, R1, #3 // 将 R1 中的值右移 3 位,结果存储到 R0 中
ROR R0, R1, #4 // 将 R1 中的值循环右移 4 位,结果存储到 R0 中
ROR R0, R1, #4 // 将 R1 中的值循环右移 4 位,结果存储到 R0 中
ASR R0, R1, #5 // 将 R1 中的值算术右移 5 位,结果存储到 R0 中
ASR R0, R1, #5 // 将 R1 中的值算术右移 5 位,结果存储到 R0 中
RRX R0, R1 // 将 R1 中的值扩展的循环右移 1 位,结果存储到 R0 中
RRX R0, R1 // 将 R1 中的值扩展的循环右移 1 位,结果存储到 R0 中
ldr r0,=0x12  //将0x12赋值给r0
ldr r0, .lable1 //获得.lable1的地址,存储在r0之中
ldr r0,[r3] // r0 = *r3
ldr r0,[r3,#4]  // r0 = *(r3 + 4)
ldr r0,[r3,r2,LSL #2] // r0 = *(r3+(r2 << 2))
ldr r0,=0x12  //将0x12赋值给r0
ldr r0, .lable1 //获得.lable1的地址,存储在r0之中
ldr r0,[r3] // r0 = *r3
ldr r0,[r3,#4]  // r0 = *(r3 + 4)
ldr r0,[r3,r2,LSL #2] // r0 = *(r3+(r2 << 2))
STR R0,[R1],#8      // 将R0中的字数据写入以R1为地址的存储器中,并将新地址R1+8写入R1。
STR R0,[R1,#8]      // 将R0中的字数据写入以R1+8为地址的存储器中。”
STR  R1, [r0]         // 将r1寄存器的值,传送到地址值为r0的(存储器)内存中
STR R0,[R1],#8      // 将R0中的字数据写入以R1为地址的存储器中,并将新地址R1+8写入R1。
STR R0,[R1,#8]      // 将R0中的字数据写入以R1+8为地址的存储器中。”
STR  R1, [r0]         // 将r1寄存器的值,传送到地址值为r0的(存储器)内存中
在32位中会读4个字节 在64位中会读8个字节
读取
ldr 
ldrb  //读一个字节  一个字节的读取
ldrh //读一个数 两个字节的读取
ldm  //批量进行处理 (根据一些组合有着不同的方式,后面写)
 
存储
str  //四字节写入
strb //一个字节写入
strh //两个字节写入
stm  // 批量处理
在32位中会读4个字节 在64位中会读8个字节
读取
ldr 

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2024-4-20 20:54 被二木先生编辑 ,原因:
收藏
免费 14
支持
分享
最新回复 (6)
雪    币: 3004
活跃值: (30866)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2024-4-20 21:58
3
雪    币: 4437
活跃值: (6666)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
可以的
2024-4-21 00:49
1
雪    币: 1329
活跃值: (1430)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
感谢分享,一直想学习这个
2024-4-22 09:50
0
雪    币: 1194
活跃值: (1894)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
好文!
2024-7-12 02:27
0
雪    币:
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
2024-7-12 12:51
0
雪    币: 498
活跃值: (4186)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
感谢分享
2024-7-12 18:08
0
游客
登录 | 注册 方可回帖
返回
//