一般的我们的电脑都是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
clang -target armv-linux-android21 demo.c -o demo
clang -target armv7a-linux-android21 demo.c -o demo
clang -target aarch64-linux-android21 1.cpp -o demo
clang -target armv-linux-android21 demo.c -o demo
clang -target armv7a-linux-android21 demo.c -o demo
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 r0, #0xFF00
mov r0, r1, lsl #3
ldr r1, [r2]
ldr r1, [r2, #4] ; r1=*(r2+4)
ldr r1, [r2, #4] ; r1=*(r2+4)
ldmia r1!, {r2-r7, r12}
stmfd sp!, {r2-r7, lr}
beq flag
flag:
B label
BL label
BLX label
BX R1
MOV R0, R1
ADD R0, R1, R2
SUB R0, R1, R2
AND R0, R1, R2
EOR R0, R1, R2
ORR R0, R1, R2
BIC R0, R1, #0xf
MUL r0 r1,r2
MLA r0,r1,r2,r3
SMULL r0,r1 ,r2 ,r3
SMLAL r0,r1 ,r2 ,r3
UMULL r0,r1 ,r2 ,r3
UMLAL r0,r1 ,r2 ,r3
LSL R0, R1, #2
LSR R0, R1, #3
ROR R0, R1, #4
ASR R0, R1, #5
RRX R0, R1
ldr r0,=0x12
ldr r0, .lable1
ldr r0,[r3]
ldr r0,[r3,#4]
ldr r0,[r3,r2,LSL #2]
ldr r0,=0x12
ldr r0, .lable1
ldr r0,[r3]
ldr r0,[r3,#4]
ldr r0,[r3,r2,LSL #2]
STR R0,[R1],#8
STR R0,[R1,#8]
STR R1, [r0]
STR R0,[R1],#8
STR R0,[R1,#8]
STR R1, [r0]
在32位中会读4个字节 在64位中会读8个字节
读取
ldr
ldrb
ldrh
ldm
存储
str
strb
strh
stm
在32位中会读4个字节 在64位中会读8个字节
读取
ldr
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2024-4-20 20:54
被二木先生编辑
,原因: