- iOS 中的 armv7,armv7s,arm64 这些都代表什么?
ARMv7|ARM7s|ARM64都是ARM处理器的指令集
真机32位处理器需要ARMv7,或者ARMv7s架构,
真机64位处理器需要ARM64架构。
- 处理器和寄存器的位数
32位处理器,能同时处理32位的数据,所以对应寄存器为32位的;
64位处理器,能同时处理64位的数据,所以对应寄存器为64位的;
寄存器位数一般会对应处理器位数,两者一般相等,但也有例外8086
- ARM 指令长度
ARM处理器用到的指令集分为 ARM 和 THUMB 两种。ARM指令长度固定为32bit,THUMB指令长度固定为16bit。所以 ARM64指令集的指令长度为32bit
- ARM中字的长度
ARM中 一个word是32位,也就是4Byte大小
字(Word):32位系统字长就是32,64位系统字长就是64。stdint.h
文件中定义了宏__WORDSIZE
表示字的位数:
#if __LP64__
#define __WORDSIZE 64
#else
#define __WORDSIZE 32
#endif
// 注:那么 LP64 是什么意思呢?
在64位机器上,如果int是32位,long是64位,pointer也是64位,那么该机器就是LP64的,其中的L表示Long,P表示Pointer,64表示Long和Pointer都是64位的。
半字(Half-Word):半字永远是字的一半,双字永远是字的2倍大小
字节(Byte):8位
寄存器
ARM64 有34个寄存器,包括31个通用寄存器、SP、PC、CPSR。
寄存器 | 位数 | 描述 |
---|---|---|
x0-x30 | 64bit | 通用寄存器,如果有需要可以当做32bit使用:WO-W30 |
FP(x29) | 64bit | 保存栈帧地址(栈底指针) |
LR(x30) | 64bit | 通常称X30为程序链接寄存器,保存子程序结束后需要执行的下一条指令 |
SP | 64bit | 保存栈指针,使用 SP/WSP来进行对SP寄存器的访问。 |
PC | 64bit | 程序计数器,俗称PC指针,总是指向即将要执行的下一条指令,在arm64中,软件是不能改写PC寄存器的。 |
CPSR | 64bit | 状态寄存器 |
x0-x7: 用于子程序调用时的参数传递,X0还用于返回值传递
-
x0 - x30
是31个通用整形寄存器。每个寄存器可以存取一个64位大小的数。 当使用x0 - x30
访问时,它就是一个64位的数。当使用w0 - w30
访问时,访问的是这些寄存器的低32位,如图:
CPSR(状态寄存器)
NZCV是状态寄存器的条件标志位,分别代表运算过程中产生的状态,其中:
- N, negative condition flag,一般代表运算结果是负数
- Z, zero condition flag, 指令结果为0时Z=1,否则Z=0;
- C, carry condition flag, 无符号运算有溢出时,C=1。
- V, oVerflow condition flag 有符号运算有溢出时,V=1。
-
Xcode在真机中运行项目,添加断点,lldb中查看各寄存器状态register read
指令
- ARM64经常用到的汇编指令
MOV X1,X0 ;将寄存器X0的值传送到寄存器X1
ADD X0,X1,X2 ;寄存器X1和X2的值相加后传送到X0
SUB X0,X1,X2 ;寄存器X1和X2的值相减后传送到X0
AND X0,X0,#0xF ; X0的值与0xF相位与后的值传送到X0
ORR X0,X0,#9 ; X0的值与9相位或后的值传送到X0
EOR X0,X0,#0xF ; X0的值与0xF相异或后的值传送到X0
LDR X5,[X6,#0x08] ;ld:load; X6寄存器加0x08的和的地址值内的数据传送到X5
LDP x29, x30, [sp, #0x10] ; ldp :load pair ; 一对寄存器, 从内存读取数据到寄存器
STR X0, [SP, #0x8] ;st:store,str:往内存中写数据(偏移值为正); X0寄存器的数据传送到SP+0x8地址值指向的存储空间
STUR w0, [x29, #-0x8] ;往内存中写数据(偏移值为负)
STP x29, x30, [sp, #0x10] ;store pair,存放一对数据, 入栈指令
CBZ ;比较(Compare),如果结果为零(Zero)就转移(只能跳到后面的指令)
CBNZ ;比较,如果结果非零(Non Zero)就转移(只能跳到后面的指令)
CMP ;比较指令,相当于SUBS,影响程序状态寄存器CPSR
B ;跳转指令,可带条件跳转与cmp配合使用
BL ;带返回的跳转指令, 返回地址保存到LR(X30)
BLR ; 带返回的跳转指令,跳转到指令后边跟随寄存器中保存的地址(例:blr x8 ;跳转到x8保存的地址中去执行)
RET ;子程序返回指令,返回地址默认保存在LR(X30)
其中 MOV
指令只能用于寄存器之间传值,寄存器和内存之间传值通过 LDR
和 STR
-
ARM指令又一个重要特点就是所有指令都是带有条件的,就是说汇编中就需要根据状态寄存器中的一些状态来控制分支的执行。例如:
图中指令b
是跳转指令,后边跟着跳转的条件eq
,那么这个eq
是什么意思呢? -
ARM指令的结构
上图列出了不同种类ARM指令的编码格式,文章开头讲过ARM指令长度固定为 32bit即图中的0-31位。
28-31位是条件码,21-24为操作码,12-19为寄存器编号
上边提到的跳转条件eq
实际就是28-31位对应的条件码,但是28-31位都是二进制数据不好记,所以就对二进制的条件码取了好记的助记符,例如 eq
。
eq
英文单词equal
的意思,注意这里equal
并不是c语言当中==
的意思,这里根据状态寄存器的条件标志位Z
来判断,如果Z = 1
则eq
成立,如果Z = 0
则eq
不成立,就是NE
。
- ARM指令包含4位的条件码列表:
操作码 | 条件码助记符 | 标志 | 含义 |
---|---|---|---|
0000 | EQ | Z=1 | 相等 |
0001 | NE(Not Equal) | Z=0 | 不相等 |
0010 | CS/HS(Carry Set/High or Same) | C=1 | 无符号数大于或等于 |
0011 | CC/LO(Carry Clear/LOwer) | C=0 | 无符号数小于 |
0100 | MI(MInus) | N=1 | 负数 |
0101 | PL(PLus) | N=0 | 正数或零 |
0110 | VS(oVerflow set) | V=1 | 溢出 |
0111 | VC(oVerflow clear) | V=0 | 没有溢出 |
1000 | HI(HIgh) | C=1,Z=0 | 无符号数大于 |
1001 | LS(Lower or Same) | C=0,Z=1 | 无符号数小于或等于 |
1010 | GE(Greater or Equal) | N=V | 有符号数大于或等于 |
1011 | LT(Less Than) | N!=V | 有符号数小于 |
1100 | GT(Greater Than) | Z=0,N=V | 有符号数大于 |
1101 | LE(Less or Equal) | Z=1,N!=V | 有符号数小于或等于 |
1110 | AL | 任何 | 无条件执行(默认) |
1111 | NV | 任何 | 从不执行 |
ARM指令所有指令都是带有条件的,默认是AL
即无条件执行,当指令带有默认条件时不需要明确写出。
看个例子:
OC代码:
汇编代码:
汇编代码注释:
- 后续添加:
adrp是计算指定的符号地址到run time PC值的相对偏移
- STR Wt, addr
Store Register: stores word from Wt to memory addressed by
addr.
- STR Xt, addr
Store Register (extended): stores doubleword from Xt to
memory addressed by addr.
- STUR Wt, [base,#simm9]
Store (Unscaled) Register: stores word from Wt to memory addressed by base+simm9.
- STUR Xt, [base,#simm9]
Store (Unscaled) Register (extended): stores doubleword
from Xt to memory addressed by base+simm9.
- SCVTF Sm, Ro
Converts an integer value to a floating-point value.
- FCVTSty Rn, Sm
Converts a floating-point value to an integer value (ty specifies type of rounding).
- FMUL Sd, Sn, Sm
Multiplies two values.
- LDRSB Wt, addr
Load Signed Byte: loads a byte from memory addressed by
addr, then sign-extends it into Wt.
- CBZ Wn, label
Compare and Branch Zero: conditionally jumps to label if
Wn is equal to zero.
MOVZ 、MOVK 和MOVN
MOVZ 赋值一个16位的立即数到寄存器中,该寄存器中除了立即数占用到的位之外的其他位都设为0,立即数可以设置向左移位0、16、32或者48(lsl:向左移位):
instruction value of x0
movz x0, #0x1234 | 0x1234
movz x0, #0x1234, lsl #16 | 0x12340000
MOVK 赋值一个立即数到寄存器,保持立即数没用到的位保持不变。
instruction value of x0
mov x0, xzr | 0x0000000000000000
movk x0, #0x0123, lsl #48 | 0x0123000000000000
movk x0, #0x4567, lsl #32 | 0x0123456700000000
movk x0, #0x89ab, lsl #16 | 0x0123456789ab0000
movk x0, #0xcdef | 0x0123456789abcdef
MOVN 用于赋值立即数的位掩码,例如想要将0xffffffff0000ffff赋值给x0,只需要使用MOVN将向左移位16的0xffff赋值位寄存器就可以实现,会自动求移位后的立即数位掩码然后赋值:
instruction value of x0
MOVN x0, 0xFFFF, lsl 16 | 0xffffffff0000ffff
参考
iOS 中的 armv7,armv7s,arm64,i386,x86_64 都是什么
ARM 指令的条件码
ARM视频教程
iOS开发同学的arm64汇编入门
iOS逆向第五篇(ARM64 汇编)
《iOS应用逆向工程》
LP64是什么意思