iOS的程序都是跑在ARM架構(gòu)的機器上,所以iOS的匯編用到的就是ARM匯編
對于iOS開發(fā)匯編的分類:
- x86匯編 模擬器
- ARM64/ARM32匯編 真機64位/真機32位,目前真機大多數(shù)都是64位。
ARM64匯編三個重要概念:
- 寄存器
ARM64 有34個寄存器,包括31個通用寄存器、SP、PC、CPSR。
(lldb) register read
General Purpose Registers:
x0 = 0x000000012c025350
x1 = 0x000000012c025350
x2 = 0x000000000000000d
x3 = 0x0000000000000000
x4 = 0x000000016f43dab8
x5 = 0x0000000000000040
x6 = 0x0000000000000000
x7 = 0x0000000000000d20
x8 = 0x00000001009cd688 (void *)0x00000001009cd790: LGPerson
x9 = 0x56f24077b16c00de
x10 = 0x000000012c025350
x11 = 0x00000000000007fb
x12 = 0x00000000000007fd
x13 = 0x0000000000000000
x14 = 0x000000008afee000
x15 = 0x00000000000003dc
x16 = 0x00000001aa01d4e8 libobjc.A.dylib`objc_autoreleasePoolPop
x17 = 0x000000000ae00000
x18 = 0x0000000000000000
x19 = 0x0000000000000000
x20 = 0x000000012be04110
x21 = 0x00000001efcaf000
x22 = 0x00000001e1bb3984
x23 = 0x0000000000000001
x24 = 0x0000000000000001
x25 = 0x00000001e71bf690 CoreFoundation`__NSArray0__struct
x26 = 0x000000012be0b130
x27 = 0x00000001efc2e000
x28 = 0x00000001e1bbcfae
fp = 0x000000016f43dc60
lr = 0x00000001009c5bac 001-alloc&init探索`-[ViewController viewDidLoad] + 76 at ViewController.m:28:5
sp = 0x000000016f43dc30
pc = 0x00000001009c5bb4 001-alloc&init探索`-[ViewController viewDidLoad] + 84 at ViewController.m:30:20
cpsr = 0x60000000
- 通用寄存器:x0~x28(64位的) (w0~w28(32位)對應(yīng)的的x0~x28的低32位) ,x0~x7一般是用來存儲函數(shù)的參數(shù),更多參數(shù),則用堆棧來傳遞,x0一般用作函數(shù)的返回值
- PC: 程序計數(shù)器:存儲著當(dāng)前執(zhí)行的指令
- FP: x29保存棧幀地址(棧底指針)
- SP:保存棧指針,使用 SP/WSP來進(jìn)行對SP寄存器的訪問
- CPSR:狀態(tài)寄存器
NZCV是狀態(tài)寄存器的條件標(biāo)志位,分別代表運算過程中產(chǎn)生的狀態(tài),其中:
N, negative condition flag,一般代表運算結(jié)果是負(fù)數(shù)
Z, zero condition flag, 指令結(jié)果為0時Z=1,否則Z=0;
C, carry condition flag, 無符號運算有溢出時,C=1。
V, oVerflow condition flag 有符號運算有溢出時,V=1。 - LR:通常稱X30為程序鏈接寄存器,保存子程序結(jié)束后需要執(zhí)行的下一條指令
每個寄存器的大小都是8字節(jié)的 - wzr:32位零寄存器
- xzr:64位零寄存器
- 指令
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的和的地址值內(nèi)的數(shù)據(jù)傳送到X5
LDP x29, x30, [sp, #0x10] ; ldp :load pair ; 一對寄存器, 從內(nèi)存讀取數(shù)據(jù)到寄存器
STR X0, [SP, #0x8] ;st:store,str:往內(nèi)存中寫數(shù)據(jù)(偏移值為正); X0寄存器的數(shù)據(jù)傳送到SP+0x8地址值指向的存儲空間
STUR w0, [x29, #-0x8] ;往內(nèi)存中寫數(shù)據(jù)(偏移值為負(fù))
STP x29, x30, [sp, #0x10] ;store pair,存放一對數(shù)據(jù), 入棧指令
CBZ ;比較(Compare),如果結(jié)果為零(Zero)就轉(zhuǎn)移(只能跳到后面的指令)
CBNZ ;比較,如果結(jié)果非零(Non Zero)就轉(zhuǎn)移(只能跳到后面的指令)
CMP ;比較指令,相當(dāng)于SUBS,影響程序狀態(tài)寄存器CPSR
B ;跳轉(zhuǎn)指令,可帶條件跳轉(zhuǎn)與cmp配合使用
BL ;帶返回的跳轉(zhuǎn)指令, 返回地址保存到LR(X30)
BLR ; 帶返回的跳轉(zhuǎn)指令,跳轉(zhuǎn)到指令后邊跟隨寄存器中保存的地址(例:blr x8 ;跳轉(zhuǎn)到x8保存的地址中去執(zhí)行)
RET ;子程序返回指令,返回地址默認(rèn)保存在LR(X30)
- ret:函數(shù)返回,相當(dāng)于return
- mov:數(shù)據(jù)傳輸指令
mov 目的寄存器 被操作數(shù),被操作數(shù)可以是變量,也可以是寄存器
例如 mov x0 ,#0x08 或者 mov x0, x1 - add: 相加后存儲到目標(biāo)寄存器
例如 :
mov x1 ,#0x09
mov x2 ,#0x010
add x0, x1 ,x2 //x0 = x1 + x2
- sub:相減,與add類似
mov x1 ,#0x09
mov x2 ,#0x010
sub x0, x1 ,x2 //x0 = x1 - x2
- cmp:操作數(shù)1,操作數(shù)2
比較的結(jié)果放在cpsr中
mov x1 ,#0x09
mov x2 ,#0x010
cmp x1, x2 //將x1-x2的結(jié)果放到cpsr狀態(tài)寄存器中
- b 指令 跳轉(zhuǎn)指令 相當(dāng)于goto
b myCode //跳轉(zhuǎn)到myCode
- b指令帶條件
條件域:EQ:相等、NE:不等于、GE:大于等于、LE:小于等于、GT:大于、LT:小于
mov x1 ,#0x09
mov x2 ,#0x010
cmp x1, x2
beq myCode//結(jié)果相等,即cpsr的z位的值為1時,跳轉(zhuǎn)到myCode
- bl指令:帶返回的跳轉(zhuǎn)指令(函數(shù)調(diào)用的匯編代碼跳轉(zhuǎn)實現(xiàn))
mov x1 ,#0x09
mov x2 ,#0x010
cmp x1, x2
bleq myCode//結(jié)果相等,即cpsr的z位的值為1時,跳轉(zhuǎn)到myCode
mov x8 ,#0x09 //myCode執(zhí)行完會返回到這
- ldr指令,從內(nèi)存中加載數(shù)據(jù)
例如:
ldr/ldur x0, [x1] //將x1存儲的地址指向的值存入到x0,x1如果為不存在的地址值,就會報錯,野指針
ldr x0, [x1, #0x04] //將x1存儲的地址值加上0x04后的新地址值指向的值存入到x0
- ldp指令,從內(nèi)存中加載數(shù)據(jù),放在一對寄存器中
例如:
ldp w0,w1, [x2] //將x2存儲的地址指向的值存入到w0、w1,前4字節(jié)存放在w0,后4字節(jié)放在w1
- str/stur指令,往內(nèi)存中寫數(shù)據(jù)
例如:
str x0, [x2] //將x0的數(shù)據(jù),寫入到x2地址指向的內(nèi)存中
- stp 存放一對數(shù)據(jù), 入棧指令
例如
stp x29, x30, [sp, #0x10] //將x29中的值寫入到sp偏移0x10后的地址指向的內(nèi)存的前8個字節(jié),x30寫入后面8個字節(jié)
- 堆棧
對應(yīng)寄存器:
- FP: x29保存棧幀地址(棧底指針)
- LR:通常稱X30為程序鏈接寄存器,保存子程序結(jié)束后需要執(zhí)行的下一條指令
每個寄存器的大小都是8字節(jié)的
函數(shù)的分類: - 葉子函數(shù),內(nèi)部不再調(diào)用其他函數(shù)的函數(shù),匯編代碼如下:
對應(yīng)的c代碼:
void test(){
int a = 2;
int b = 3;
}
匯編代碼
_test: ; @test
.cfi_startproc
; %bb.0:
sub sp, sp, #16 ; =16,sp棧頂指針上移16個字節(jié)
.cfi_def_cfa_offset 16
mov w8, #2 ;將2存入w8寄存器
str w8, [sp, #12] ;將w8寄存器的數(shù)據(jù)存入到sp下移12個字節(jié)的所在位置下面的4字節(jié)
mov w8, #3 ;將3存入w8寄存器
str w8, [sp, #8] ;將w8寄存器的數(shù)據(jù)存入到sp下移8個字節(jié)的所在位置下面的4字節(jié)
add sp, sp, #16 ; =16,sp棧頂指針下移16個字節(jié),恢復(fù)到初始位置
ret
.cfi_endproc
- 非葉子函數(shù),除了葉子函數(shù),其他函數(shù)叫非葉子函數(shù)
對應(yīng)的c代碼:
void test(){
int a = 2;
int b = 3;
}
void testh(){
test();
int a = 4;
int b = 5;
}
匯編代碼
_test: ; @test,與上面的test一致
.cfi_startproc
; %bb.0:
sub sp, sp, #16 ; =16
.cfi_def_cfa_offset 16
mov w8, #2
str w8, [sp, #12]
mov w8, #3
str w8, [sp, #8]
add sp, sp, #16 ; =16
ret
.cfi_endproc
; -- End function
.globl _testh ; -- Begin function testh
.p2align 2
_testh: ; @testh,非葉子函數(shù)
.cfi_startproc
; %bb.0:
sub sp, sp, #32 ; =32 ,開辟32字節(jié)棧空間
stp x29, x30, [sp, #16] ; 16-byte Folded Spill,在一開始分配的32字節(jié)空間上,給fp(x29)寄存器,lr(x30)寄存器各分配8字節(jié)的空間
add x29, sp, #16 ; =16,將fp寄存器指向棧底向上偏移16字節(jié)位置,即存儲fp和lr寄存器后剩余的空間。
.cfi_def_cfa w29, 16
.cfi_offset w30, -8
.cfi_offset w29, -16
bl _test ;跳轉(zhuǎn)到test
mov w8, #4 ;給a,b兩個變量分配內(nèi)存空間,在剩余的16字節(jié)空間上分配,與test類似
stur w8, [x29, #-4]
mov w8, #5
str w8, [sp, #8]
ldp x29, x30, [sp, #16] ; 16-byte Folded Reload,讀取fp,lr
add sp, sp, #32 ; =32,收回函數(shù)調(diào)用棧空間
ret
.cfi_endproc