android study 3
Android知识学习
1.ARM汇编指令
之前打交道比较多的是x86指令集,接触过一点Mips指令集,对于arm指令集还没系统学习过
1.1 arm的运行状态
arm分为七种运行模式和两种运行状态。
运行模式即用户模式(类似windows的ring3程序),系统模式(类似ring0),…等
运行状态分为ARM和Thumb状态。
1.1.a. Thumb状态
Thumb状态是2字节,可以看做是ARM指令压缩形式的子集,具有16位的代码密度(也就是2个字节指令长度),但是只能是支持通用功能,必要的时候仍然需要ARM 指令。
1.2 arm寄存器
arm寄存器一共有37个,其中31个通用的,6个是状态寄存器。其中31个中分为未分组寄存器和分组寄存器。
未分组寄存器
1.R0-R7,其意义是在各种运行模式下都可以使用的通用寄存器。R0-R7是通用寄存器,其中R0-R3可以用来传递参数,返回值。如果传参的时候寄存器不够的话就使用压栈来完成了。结果返回的寄存器是R0。
分组寄存器
1.分组寄存器也就是说在不同模式下,会有不同的寄存器,R8-R12是较为特殊的,因为只有在快速模式(FIQ)下,其名字才不一样。也是通用寄存器,可以用来存局部变量之类的。
2. R11寄存器,代表栈底指针。
3.R13寄存器,代表sp栈顶指针。
4.R14寄存器,也叫LR寄存器,即链接寄存器,可以用作保存子程序或者中断的返回地址。
5.R15寄存器,PC寄存器,类似于EIP。
6.CPSR状态寄存器,类似于EFLAGS寄存器。其中的第五位为1时则代表运行在ARM状态,如果T=0则代表运行在Thumb状态。
1.3 arm 64寄存器
本质上没有什么不同,详情可以见https://support.huaweicloud.com/ref-kunpenggrf/kunpenggrffaq_10_0057.html
比较有意思的是X16,X17寄存器
x16~x17是Intra-procedure-call scratch registers。也就是调用的函数里会用到的一些寄存器(又叫IP0,IP1),比如常用于动态链接中的plt寻址等指令。比如以下指令:
1 | 1. adrp x16, 11000 <func22+0x10b30> #adrp会拿到目标地址所在页的基址,这里应该就是相应的got表地址了 |
2.调用约定
2.1 arm/arm64调用约定
ARM和ARM64使用的是ATPCS(ARM-Thumb Procedure Call Standard/ARM-Thumb过程调用标准)的函数调用约定。
ARM会把参数保存到R0-R3寄存器中,剩下的参数从右到左压栈。返回值放在R0中。
ARM64则是参数保存至X0-X7寄存器中,上下的参数从右到左入栈,返回值放在X0中。
2.2 x86调用约定
顺便说一下x86的调用约定,x86可以分为三种调用约定: cdecl/stdcall/fastcall。cdecl/stdcall是直接压栈,参数从右往左依次入栈,返回值放在EAX寄存器中。fastcall则是参数1,2保存在ECX,EDX中,剩下的参数从右往左依次入栈。结果放在EAX寄存器中。
x64则只有fastcall一种调用约定,参数1,2,3,4保存至RCX,RDX,R8,R9中,剩下参数从右往左依次入栈。
2.3 C++函数调用约定
西加加是遵循thiscall函数调用约定,对于x86,会把this指针存入ECX。x64则是参数1,2,3存在RDX,R8,R9,this指针存入ECX。
对于ARM而言,则是把this指针存在R0中,参数1,2,3存在R1,R2,R3。ARM64则是this指针存在X0中,参数1-7存放在X0-X7中,剩下参数从右到左入栈。
3.跳转指令
ARM的跳转指令有B,BL,BX,BLX。
1.跳转指令B就是无条件跳转,类似于jmp指令。用法: B label
2.BL指令则是带返回的跳转指令,跳转之前会在R14(LR寄存器)中存入当前PC的值。类似于call指令。用法: BL label
3.BX则是带状态切换的跳转指令,根据operand的最低位来判断,如果是1则是Thumb状态,如果是0则是ARM状态。用法:BX 寄存器
4.BLX则是带返回和状态切换的,如果用法是BLX label,则一定会更改处理器的状态。如果是BLX 寄存器,则根据其在最低为来决定。
还有BNE,BEQ这些根据状态寄存器的条件跳转指令。。。除了跳转指令之外,还可以通过MOV,LDR指令,把地址直接赋给PC寄存器从而实现跳转。如MOV PC, LR。或者LDR PC,=0xFFFFFFFF(加等号表示是伪指令,直接把0xFFFFFFFF赋值给PC,否则是去该地址上取值)