前言
從本篇文章開始,即將給大家分享關(guān)于iOS逆向安全攻防等相關(guān)的知識點(diǎn),在分析逆向之前,我們必須掌握關(guān)于匯編的相關(guān)的知識點(diǎn),作為逆向?qū)W習(xí)的一個準(zhǔn)備。這篇文章首先給大家講解一下匯編的一些基礎(chǔ)知識點(diǎn),希望大家能夠掌握。
一、初識匯編
1.1匯編發(fā)展史
我們先來看看匯編語言的發(fā)展史??
機(jī)器語言
機(jī)器語言 ?? 由0和1組成的機(jī)器指令。例如下面的指令??
- 加:0100 0000
- 減:0100 1000
- 乘:1111 0111 1110 0000
- 除:1111 0111 1111 0000
匯編語言
匯編語言稱作assembly language,使用助記符代替機(jī)器語言,例如??
- 加:
INC EAX通過編譯器 0100 0000 - 減:
DEC EAX通過編譯器 0100 1000 - 乘:
MUL EAX通過編譯器 1111 0111 1110 0000 - 除:
DIV EAX通過編譯器 1111 0111 1111 0000
那什么是助記符呢?你可以這么理解,助記符就是幫助我們(程序猿)將上面的加減乘除等指令翻譯成機(jī)器語言0和1的一些符號。
高級語言
接下來就是我們?nèi)粘i_發(fā)中使用的高級語言了,稱作High-level programming language。例如C\C++\Java\OC\Swift,它們是更加接近于人類的自然語言。??
- 加:
A+B通過編譯器 0100 0000 - 減:
A-B通過編譯器 0100 1000 - 乘:
A*B通過編譯器 1111 0111 1110 0000 - 除:
A/B通過編譯器 1111 0111 1111 0000
綜上所述,語言的一個發(fā)展過程大致就是??
機(jī)器語言0和1 -->助記符-->編譯器(負(fù)責(zé)讀取助記符)產(chǎn)生匯編-->高級語言(接近人類的自然語言)
補(bǔ)充:代碼執(zhí)行的過程
代碼執(zhí)行的過程如下圖??

上圖可知:
- 匯編與機(jī)器是
一一對應(yīng),每一條機(jī)器指令都有與之對應(yīng)的匯編指令-
編譯:匯編語言可以通過編譯得到機(jī)器語言 -
反編譯:機(jī)器語言可以通過反匯編得到匯編語言
-
-
高級語言可以通過編譯得到匯編語言 \ 機(jī)器語言,但匯編語言\機(jī)器語言幾乎不可能還原成高級語言
1.2匯編語言的特點(diǎn)
- 可以
直接訪問、控制各種硬件設(shè)備,比如存儲器、CPU等,能最大限度地發(fā)揮硬件的功能 - 能夠
不受編譯器的限制,對生成的二進(jìn)制代碼進(jìn)行完全的控制 - 目標(biāo)代碼
簡短,占用內(nèi)存少,執(zhí)行速度快 - 匯編指令是機(jī)器指令的
助記符,同機(jī)器指令一一對應(yīng)。每一種CPU都有自己的機(jī)器指令集\匯編指令集,所以匯編語言不具備可移植性 - 知識點(diǎn)
過多,開發(fā)者需要對CPU等硬件結(jié)構(gòu)有所了解,不易于編寫、調(diào)試、維護(hù) -
不區(qū)分大小寫,比如mov和MOV是一樣的
用途
再來安利一下,學(xué)習(xí)匯編語言能干啥????
- 編寫驅(qū)動程序、操作系統(tǒng)(比如Linux內(nèi)核的某些關(guān)鍵部分)
- 對性能要求極高的程序或者代碼片段,可與高級語言混合使用(內(nèi)聯(lián)匯編)
- 軟件安全
- 病毒分析與防治
- 逆向\加殼\脫殼\破解\外掛\免殺\加密解密\漏洞\黑客
- 理解整個計算機(jī)系統(tǒng)的最佳起點(diǎn)和最有效途徑
- 為編寫高效代碼打下基礎(chǔ)
- 弄清代碼的本質(zhì)
最后來句裝13的話
越底層越單純!真正的程序員都需要了解的一門非常重要的語言,匯編!
1.3匯編語言的種類
目前討論比較多的匯編語言有
- 8086匯編(8086處理器是16bit的CPU)
- Win32匯編
- Win64匯編
- ARM匯編(嵌入式、Mac、iOS)
我們iPhone里面用到的是ARM匯編??,但是不同的設(shè)備也有差異,因CPU的架構(gòu)不同。
| 架構(gòu) | 設(shè)備 |
|---|---|
| armv6 | iPhone, iPhone2, iPhone3G, 第一代、第二代 iPod Touch |
| armv7 | iPhone3GS, iPhone4, iPhone4S,iPad, iPad2, iPad3(The New iPad), iPad mini, iPod Touch 3G, iPod Touch4 |
| armv7s | iPhone5, iPhone5C, iPad4(iPad with Retina Display) |
| arm64 | iPhone5S 以后 iPhoneX , iPad Air, iPad mini2以后 |
二、必要常識點(diǎn)
在學(xué)好匯編之前,首先需要了解CPU等硬件結(jié)構(gòu)

上圖是程序(APP)的執(zhí)行過程
- 硬件相關(guān)最為重要是CPU/內(nèi)存
- 在匯編中,大部分指令都是和CPU與內(nèi)存相關(guān)的
補(bǔ)充:鏡像文件
我們知道,在磁盤中我們的應(yīng)用程序被稱作可執(zhí)行文件,例如pc端的exe,iOS端的exc等,而這個可執(zhí)行文件被加載到內(nèi)存中就是鏡像文件了。鏡像文件其實(shí)和可執(zhí)行文件是一模一樣的,因?yàn)槭菑拇疟Pcopy到內(nèi)存中,所以稱作鏡像。
2.1 總線
總線是什么?先看下圖??

上圖是蘋果A11的CPU芯片,每一個CPU芯片都有很多管腳,這些管腳和總線相連,CPU通過總線跟外部器件進(jìn)行交互,所以總線是CPU與內(nèi)存之間的橋梁。
總線:是一根根導(dǎo)線的集合。
總線的分類
總線主要分為三類,如下圖所示??

- 地址總線:CPU是通過地址總線來指定存儲單元的
- 數(shù)據(jù)總線:CPU與內(nèi)存/其他部件之間的數(shù)據(jù)傳送通道
- 控制總線:CPU通過控制總線對外部器件進(jìn)行控制
舉例說明

上圖是CPU從內(nèi)存的3號單元讀取數(shù)據(jù),大致過程是這樣的??
- CPU首先要找到內(nèi)存地址,才能讀寫內(nèi)存中的數(shù)據(jù)。CPU通過
地址總線,將3這個地址傳遞給內(nèi)存,即尋址到內(nèi)存的3號單元; - 需要操作3單元的數(shù)據(jù),還需要確定是
讀還是寫。CPU通過控制總線告訴內(nèi)存需要進(jìn)行的操作,例如示例中的是讀; - 內(nèi)存接收了CPU想要進(jìn)行的操作,將
3號單元的數(shù)據(jù)通過數(shù)據(jù)總線傳遞給CPU。
至此,整個CPU和內(nèi)存交互的過程結(jié)束。
2.1.1地址總線
地址總線的寬度決定了尋址的能力。
例如:8086的地址總線寬度是20,那么尋址能力就是2的20次方 = 1M(1048576),這是數(shù)量單位。
數(shù)量單位和數(shù)值單位的區(qū)別:
1M和1MB
- 1M是數(shù)量單位,大小就是上面說的1048576。
- 1MB是數(shù)值單位,例如 ?? 內(nèi)存的單位是B(byte字節(jié)),市面上賣的內(nèi)存條512MB,就是512x1024x1024字節(jié),每個字節(jié)占8bit大小的空間,即8位。
請看內(nèi)存條圖示??

2.1.2數(shù)據(jù)總線
數(shù)據(jù)總線的寬度決定了CPU的單次數(shù)據(jù)傳送量,也就是數(shù)據(jù)傳送速度。
-
每條數(shù)據(jù)線一次只能傳輸一位二進(jìn)制數(shù)據(jù),例如 8根數(shù)據(jù)線一次可傳送一個8位二進(jìn)制數(shù)據(jù)(即1個字節(jié)的數(shù)據(jù)) - 數(shù)據(jù)總線是
數(shù)據(jù)線數(shù)量之和
例如:8086的數(shù)據(jù)總線寬度是16,所以單次最大傳遞2個字節(jié)的數(shù)據(jù)。
吞吐量
還有一個名詞叫吞吐量,其實(shí)就是CPU的單次數(shù)據(jù)傳送的總量,和寬度是一個意思。
2.1.3控制總線
- 控制總線的寬度決定了CPU對其他器件的
控制能力,能有多少種控制,即CPU對外部器件的控制能力 - 控制總線是控制線數(shù)量之和
2.2 內(nèi)存
上面分析總線的時候,提到了內(nèi)存,那么內(nèi)存究竟是如何與CPU以及其它設(shè)備進(jìn)行交互的呢?我們先來看看下面這張內(nèi)存物理結(jié)構(gòu)分布圖??

上圖可知??
- CPU是通過總線和其它硬件設(shè)備連接的
- 內(nèi)存有
RAM主存儲器、RAM主存儲器(內(nèi)存條)
下圖是按照物理地址劃分的內(nèi)存,有主存儲器、顯存地址、顯卡地址、網(wǎng)卡地址

其中內(nèi)存中的低地址是給用戶用的,高地址是給系統(tǒng)用的??

內(nèi)存地址空間的大小受CPU地址總線寬度的限制。例如:8086的地址總線寬度為20,可以定位2^20個不同的內(nèi)存單元(即內(nèi)存地址范圍0x00000~0xFFFFF),所以8086的內(nèi)存空間大小為1MB
- 0x00000~0x9FFFF:主存儲器,
可讀可寫 - 0xA0000~0xBFFFF:向顯存中寫入數(shù)據(jù),這些數(shù)據(jù)會被顯卡輸出到顯示器,
可讀可寫 - 0xC0000~0xFFFFF:存儲各種硬件/系統(tǒng)信息,
只讀
2.3 進(jìn)制
我們最熟悉的進(jìn)制就是十進(jìn)制,接觸編程后,又知道了二進(jìn)制、八進(jìn)制、十六進(jìn)制等,具體的意思??
- 八進(jìn)制由
8個符號組成:0 1 2 3 4 5 6 7逢八進(jìn)一 - 十進(jìn)制由
10個符號組成:0 1 2 3 4 5 6 7 8 9逢十進(jìn)一 - 以此類推:N進(jìn)制就是由
N個符號組成:逢N進(jìn)一
2.3.1學(xué)習(xí)進(jìn)制的障礙
很多人學(xué)不好進(jìn)制,原因是總以十進(jìn)制為依托去考慮其他進(jìn)制,需要運(yùn)算的時候也總是先轉(zhuǎn)換成十進(jìn)制,這種學(xué)習(xí)方法是錯誤的!
為什么一定要轉(zhuǎn)換十進(jìn)制呢?僅僅是因?yàn)槲覀儗κM(jìn)制最熟悉,所以才轉(zhuǎn)換。
每一種進(jìn)制都是完美的,想學(xué)好進(jìn)制首先要忘掉十進(jìn)制,也要忘掉進(jìn)制間的轉(zhuǎn)換!
練習(xí):1 + 1 在____情況下等于 3 ?
當(dāng)然有人會回答 ?? 在算錯的情況下等于3!哈哈!
我們拋開約定俗成的十進(jìn)制規(guī)則,重新定義10個符號,例如??
0 1 3 2 8 A B E S 7 逢十進(jìn)一
那么,此時1+1=3嗎?肯定YES!那么,這么做的目的何在呢?
傳統(tǒng)定義的十進(jìn)制和自定義的十進(jìn)制不一樣。如果我們不告訴別人這10個符號的表,別人是沒辦法拿到我們的具體數(shù)據(jù)的,所以這樣我們可以用自定義的符號表來加密!
綜上所述??
十進(jìn)制由十個符號組成,逢十進(jìn)一,符號是可以自定義的??!
2.3.2進(jìn)制的運(yùn)算規(guī)則
做個練習(xí) ?? 八進(jìn)制運(yùn)算
2 + 3 = __ , 2 * 3 = __ ,4 + 5 = __ ,4 * 5 = __.
277 + 333 = __ , 276 * 54 = __ , 237 - 54 = __ , 234 / 4 = __ .
八進(jìn)制加法表
0 1 2 3 4 5 6 7
10 11 12 13 14 15 16 17
20 21 22 23 24 25 26 27
...
1+1 = 2
1+2 = 3 2+2 = 4
1+3 = 4 2+3 = 5 3+3 = 6
1+4 = 5 2+4 = 6 3+4 = 7 4+4 = 10
1+5 = 6 2+5 = 7 3+5 = 10 4+5 = 11 5+5 = 12
1+6 = 7 2+6 = 10 3+6 = 11 4+6 = 12 5+6 = 13 6+6 = 14
1+7 = 10 2+7 = 11 3+7 = 12 4+7 = 13 5+7 = 14 6+7 = 15 7+7 = 16
八進(jìn)制乘法表
0 1 2 3 4 5 6 7 10 11 12 13 14 15 16 17 20 21 22 23 24 25 26 27...
1*1 = 1
1*2 = 2 2*2 = 4
1*3 = 3 2*3 = 6 3*3 = 11
1*4 = 4 2*4 = 10 3*4 = 14 4*4 = 20
1*5 = 5 2*5 = 12 3*5 = 17 4*5 = 24 5*5 = 31
1*6 = 6 2*6 = 14 3*6 = 22 4*6 = 30 5*6 = 36 6*6 = 44
1*7 = 7 2*7 = 16 3*7 = 25 4*7 = 34 5*7 = 43 6*7 = 52 7*7 = 61
實(shí)戰(zhàn):四則運(yùn)算
277 236 276 234
+ 333 - 54 * 54 / 4
-------- -------- -------- --------
請大家算算!
2.3.3 二進(jìn)制的簡寫形式
二進(jìn)制: 1 0 1 1 1 0 1 1 1 1 0 0
三個二進(jìn)制一組: 101 110 111 100
八進(jìn)制: 5 6 7 4
四個二進(jìn)制一組: 1011 1011 1100
十六進(jìn)制: b b c
使用二進(jìn)制從0寫到1111:0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
發(fā)現(xiàn)這樣使用二進(jìn)制太麻煩,所以將其改為更簡單一點(diǎn)的符號
0 1 2 3 4 5 6 7 8 9 A B C D E F 這就是十六進(jìn)制了
2.4 數(shù)據(jù)的寬度
數(shù)學(xué)上的數(shù)字,是沒有大小限制的,可以無限的大。但在計算機(jī)中,由于受硬件的制約,數(shù)據(jù)都是有長度限制的(我們稱為數(shù)據(jù)寬度),超過最多寬度的數(shù)據(jù)會被丟棄。
示例??
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int test(){
int cTemp = 0x1FFFFFFFF;
return cTemp;
}
int main(int argc, char * argv[]) {
printf("%x\n",test());
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

斷點(diǎn)調(diào)試結(jié)果可見,cTemp溢出了。
也可以通過獲取的地址,然后在菜單欄選擇Debug --> Debug Workflow --> ViewMemory中輸入地址查看??



2.4.1計算機(jī)中常見的數(shù)據(jù)寬度
- 位(Bit):1個位就是1個二進(jìn)制位,即0或1
- 字節(jié)(Byte):1個字節(jié)由8個Bit組成,內(nèi)存中的最小單元Byte
- 字(Word):1個字由兩個字節(jié)組成(16位),第2個字節(jié)分別稱為高字節(jié)和低字節(jié)
- 雙字(DoubleWord):1個雙字由兩個字組成(32位)
那么計算機(jī)存儲數(shù)據(jù),它會分為有符號數(shù)和無符號數(shù)。那么關(guān)于這個看下圖就理解了!??

- 無符號數(shù),直接換算
- 有符號數(shù),符號放在第1位,第1位是0即正數(shù),為1即負(fù)數(shù):
正數(shù):0 1 2 3 4 5 6 7
負(fù)數(shù):F E D B C A 9 8
表示:-1 -2 -3 -4 -5 -6 -7 -8
練習(xí)
- 現(xiàn)在有10進(jìn)制數(shù) 10個符號分別是:2,9,1,7,6,5,4, 8,3 , A 逢10進(jìn)1 那么: 123 + 234 = ____
AA6
我們可以把自定義的十進(jìn)制寫出來,然后查表,逢十進(jìn)一,??
十進(jìn)制: 0 1 2 3 4 5 6 7 8 9
自定義: 2 9 1 7 6 5 4 8 3 A
92 99 91 97 96 95 94 98 93 9A
12 19 11 17 16 15 14 18 13 1A
72 79 71 77 76 75 74 78 73 7A
62 69 61 67 66 65 64 68 63 6A
52 59 51 57 56 55 54 58 53 5A
42 49 41 47 46 45 44 48 43 4A
82 89 81 87 86 85 84 88 83 8A
32 39 31 37 36 35 34 38 33 3A
922
對照著常規(guī)的十進(jìn)制,做一個轉(zhuǎn)換,即可得出答案。
- 現(xiàn)在有9進(jìn)制數(shù) 9個符號分別是:2,9,1,7,6,5,4, 8,3 逢9進(jìn)1 那么: 123 + 234 = ____
9926
同理??
十進(jìn)制: 0 1 2 3 4 5 6 7 8
自定義: 2 9 1 7 6 5 4 8 3
92 99 91 97 96 95 94 98 93
12 19 11 17 16 15 14 18 13
72 79 71 77 76 75 74 78 73
62 69 61 67 66 65 64 68 63
52 59 51 57 56 55 54 58 53
42 49 41 47 46 45 44 48 43
82 89 81 87 86 85 84 88 83
32 39 31 37 36 35 34 38 33
922
2.5 CPU&寄存器
內(nèi)部部件之間由總線連接??

CPU除了有控制器、運(yùn)算器還有寄存器。其中寄存器的作用就是進(jìn)行數(shù)據(jù)的臨時存儲。
什么是寄存器?它的作用是什么???
CPU的運(yùn)算速度是非??斓?,為了性能CPU在內(nèi)部開辟一小塊臨時存儲區(qū)域,并在進(jìn)行運(yùn)算時先將數(shù)據(jù)從內(nèi)存復(fù)制到這一小塊臨時存儲區(qū)域中,運(yùn)算時就在這一小快臨時存儲區(qū)域內(nèi)進(jìn)行。我們稱這一小塊臨時存儲區(qū)域?yàn)榧拇嫫鳌?/p>
對于arm64系的CPU來說, 如果寄存器以x開頭則表明的是一個64位的寄存器,如果以w開頭則表明是一個32位的寄存器,在系統(tǒng)中沒有提供16位和8位的寄存器供訪問和使用。其中32位的寄存器是64位寄存器的低32位部分,并不是獨(dú)立存在的。注意下面2點(diǎn)??
- 對程序員來說,CPU中最主要部件是寄存器,可以通過改變寄存器的內(nèi)容來實(shí)現(xiàn)對CPU的控制
- 不同的CPU,寄存器的個數(shù)、結(jié)構(gòu)是不相同的
2.5.1浮點(diǎn)和向量寄存器
因?yàn)楦↑c(diǎn)數(shù)的存儲以及其運(yùn)算的特殊性,CPU中專門提供浮點(diǎn)數(shù)寄存器來處理浮點(diǎn)數(shù)
- 浮點(diǎn)寄存器 64位: D0 - D31 32位: S0 - S31
現(xiàn)在的CPU支持向量運(yùn)算.(向量運(yùn)算在圖形處理相關(guān)的領(lǐng)域用得非常的多)為了支持向量計算系統(tǒng)了也提供了眾多的向量寄存器.
- 向量寄存器 128位:V0-V31
2.5.2通用寄存器
- 通用寄存器也稱
數(shù)據(jù)地址寄存器,通常用來做數(shù)據(jù)計算的臨時存儲、做累加、計數(shù)、地址保存等功能。定義這些寄存器的作用主要是用于在CPU指令中保存操作數(shù),在CPU中當(dāng)做一些常規(guī)變量來使用。 - ARM64擁有
32個64位的通用寄存器x0 到 x30,以及XZR(零寄存器),這些通用寄存器有時也有特定用途`。- w0 到 w28 這些是32位的。因?yàn)?4位CPU可以兼容32位,所以可以只使用64位寄存器的低32位。
- 比如 w0 就是 x0的低32位!
注意:
了解過8086匯編的同學(xué)應(yīng)該知道,有一種特殊的寄存器段寄存器:CS,DS,SS,ES四個寄存器來保存這些段的基地址,這個屬于Intel架構(gòu)CPU中,在ARM中并沒有。
通常,CPU會先將內(nèi)存中的數(shù)據(jù)存儲到通用寄存器中,然后再對通用寄存器中的數(shù)據(jù)進(jìn)行運(yùn)算??聪旅媸纠??
假設(shè)內(nèi)存中有塊紅色內(nèi)存空間的值是3,現(xiàn)在想把它的值加1,并將結(jié)果存儲到藍(lán)色內(nèi)存空間??

- CPU首先會將紅色內(nèi)存空間的值放到X0寄存器中:
mov X0 紅色內(nèi)存空間 - 然后讓X0寄存器與1相加:
add X0,1 - 最后將值賦值給內(nèi)存空間:
mov 藍(lán)色內(nèi)存空間,X0
2.5.3pc寄存器(program counter)
- pc寄存器也稱作
指令指針寄存器,它指示了CPU當(dāng)前要讀取指令的地址 - 在內(nèi)存或者磁盤上,指令和數(shù)據(jù)
沒有任何區(qū)別,都是二進(jìn)制信息 - CPU在工作的時候把有的信息看做指令,有的信息看做數(shù)據(jù),為同樣的信息賦予了不同的意義
- 比如 1110 0000 0000 0011 0000 1000 1010 1010
- 可以當(dāng)做數(shù)據(jù) 0xE003008AA
- 也可以當(dāng)做指令 mov x0, x8
- CPU根據(jù)什么將內(nèi)存中的信息看做指令?
- CPU將pc指向的
內(nèi)存單元的內(nèi)容看做指令 - 如果內(nèi)存中的某段內(nèi)容曾
被CPU執(zhí)行過,那么它所在的內(nèi)存單元必然被pc指向過
- CPU將pc指向的
案例演示
下面通過一個例子來演示下pc寄存器的讀和寫,還是上面的溢出的例子??
注意:真機(jī)聯(lián)調(diào)!
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int test(){
int cTemp = 0x1FFFFFFFF;
return cTemp;
}
int main(int argc, char * argv[]) {
printf("%x\n",test());
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
運(yùn)行,demo中寄存器種類如下所示??


然后我們來看看匯編代碼??


pc寄存器調(diào)試
接下來我們嘗試調(diào)試下pc寄存器。首先在控制臺打印pc寄存器地址,指令??
register read pc

當(dāng)前pc寄存器的內(nèi)存地址是0x0000000100ac9520。按住control+Step into,走到下一步指令,繼續(xù)打印

pc寄存器的內(nèi)存地址是0x0000000100ac9524,再繼續(xù)??

pc寄存器的內(nèi)存地址是
0x0000000100ac9528。
所以,一條指令在內(nèi)存中占用
4字節(jié)大小的空間。
寫
除了讀pc寄存器地址外,當(dāng)然還可以寫。
首先斷點(diǎn)端在第一行??

接著輸入寫的指令??
register write pc 0x10260151c

上圖中,register read pc 此時是讀不出來的,因?yàn)?code>斷點(diǎn)斷住了,如果step into,此時斷點(diǎn)斷在哪里???

最終通過驗(yàn)證發(fā)現(xiàn),會斷在0x10260151c的下一行,說明pc寄存器中執(zhí)行完成了0x10260151c這個地址對應(yīng)的指令,然后走到下一條指令,所以0x102601520中的指令是沒有執(zhí)行的。
高速緩存
iPhoneX上搭載的ARM處理器A11它的1級緩存的容量是64KB,2級緩存的容量8M.
CPU每執(zhí)行一條指令前都需要從內(nèi)存中將指令讀取到CPU內(nèi)并執(zhí)行。而寄存器的運(yùn)行速度相比內(nèi)存讀寫要快很多,為了性能,CPU還集成了一個高速緩存存儲區(qū)域.當(dāng)程序在運(yùn)行時,先將要執(zhí)行的指令代碼以及數(shù)據(jù)復(fù)制到高速緩存中去(由操作系統(tǒng)完成).CPU直接從高速緩存依次讀取指令來執(zhí)行.
2.5.4 bl指令
- CPU從何處執(zhí)行指令是由pc中的內(nèi)容決定的,我們可以通過改變pc的內(nèi)容來控制CPU執(zhí)行目標(biāo)指令
- ARM64提供了一個
mov指令(傳送指令),可以用來修改大部分寄存器的值,比如- mov x0,#10、mov x1,#20
- 但是,mov指令
不能用于設(shè)置pc的值,ARM64沒有提供這樣的功能 - ARM64提供了另外的指令來修改PC的值,這些指令統(tǒng)稱為
轉(zhuǎn)移指令,最簡單的是bl指令
bl指令練習(xí)
現(xiàn)在有兩段代碼!假設(shè)程序先執(zhí)行A,請寫出指令執(zhí)行順序.最終寄存器x0的值是多少?
_A:
mov x0,#0xa0
mov x1,#0x00
add x1, x0, #0x14
mov x0,x1
bl _B
mov x0,#0x0
ret
_B:
add x0, x0, #0x10
ret
我們直接上機(jī)實(shí)操。
首先將上面的匯編代碼寫到工程之中 ?? com+n --> empty --> asm.s(.s代表是匯編代碼文件)??


接著寫入?yún)R編代碼??
.text
.global _A,_B
_A:
mov x0,#0xa0
mov x1,#0x00
add x1, x0, #0x14
mov x0,x1
bl _B
mov x0,#0x0
ret
_B:
add x0, x0, #0x10
ret
注意:需要聲明下面2行
.text
.global _A,_B
接著執(zhí)行 ?? 如何讓匯編代碼跑起來呢?
- 在你需要調(diào)用的地方,先聲明函數(shù)??(例如VC中)

cmd+b編譯,能成功!
- 在A()執(zhí)行處加斷點(diǎn),并執(zhí)行程序,開啟匯編調(diào)試??



上圖可見,進(jìn)入的匯編就是我們之前寫的_A函數(shù)匯編代碼!??????
調(diào)試匯編
接下來開始lldb調(diào)試,下面是一步步到0x0的過程??
首先執(zhí)行下一步,查看寄存器的值??

接著往下走??

再接下來走??

接著進(jìn)入函數(shù)B??(按住control鍵step into到B函數(shù))

接著往下執(zhí)行指令??

繼續(xù)往下執(zhí)行,回到了A函數(shù)??

再接著往下走,會發(fā)現(xiàn)在最后2條指令之間死循環(huán)了!why?請看下一篇!
總結(jié)
本篇文章開始帶大家了解了下匯編的發(fā)展史和特點(diǎn),然后探討了cpu和內(nèi)存及其他硬件,是通信總線進(jìn)行數(shù)據(jù)的交換處理,最后重點(diǎn)示例分析了寄存器,帶大家通過lldb指令對pc寄存器進(jìn)行讀和寫,以及bl指令的調(diào)試,希望大家能夠動手實(shí)操一遍,加深印象,感謝閱讀!