初識(shí)匯編
匯編語(yǔ)言的發(fā)展
機(jī)器語(yǔ)言
由0和1
組成的機(jī)器指令
搜吧,以下0和1組合分別表示不同的意義。
- 加:0100 0000
- 減:0100 1000
- 乘:1111 0111 1110 0000
- 除:1111 0111 1111 0000
匯編語(yǔ)言(assembly language)
由于使用機(jī)器語(yǔ)言表示時(shí)不直觀且不容易被記憶稳捆,因此就出現(xiàn)了助記符
來(lái)代替機(jī)器語(yǔ)言。如以下助記符:
- 加:
INC EAX
通過(guò)編譯器 0100 0000 - 減:
DEC EAX
通過(guò)編譯器 0100 1000 - 乘:
MUL EAX
通過(guò)編譯器 1111 0111 1110 0000 - 除:
DIV EAX
通過(guò)編譯器 1111 0111 1111 0000
高級(jí)語(yǔ)言(high-level programming language)
雖然有了助記符,但為了更高效的編程揭绑,慢慢開(kāi)始出現(xiàn)了更高級(jí)的語(yǔ)言,例如:C/C++/Java/OC/Swift
等郎哭。這些高級(jí)語(yǔ)言比匯編更加接近人類(lèi)的自然語(yǔ)言他匪。例如:
- 加:
A+B
通過(guò)編譯器 0100 0000 - 減:
A-B
通過(guò)編譯器 0100 1000 - 乘:
A*B
通過(guò)編譯器 1111 0111 1110 0000 - 除:
A/B
通過(guò)編譯器 1111 0111 1111 0000
下圖表明了各語(yǔ)言之間的關(guān)系以及最終如何運(yùn)行在計(jì)算機(jī):
說(shuō)明:
-
匯編語(yǔ)言
與機(jī)器語(yǔ)言
一一對(duì)應(yīng),每一條機(jī)器指令都有與之對(duì)應(yīng)的匯編指令 -
匯編語(yǔ)言
可以通過(guò)編譯
得到機(jī)器語(yǔ)言
夸研,機(jī)器語(yǔ)言
可以通過(guò)反匯編
得到匯編語(yǔ)言
-
高級(jí)語(yǔ)言
可以通過(guò)編譯
得到匯編語(yǔ)言/機(jī)器語(yǔ)言
邦蜜,但匯編語(yǔ)言/機(jī)器語(yǔ)言
幾乎不可能
還原成高級(jí)語(yǔ)言
(因?yàn)椴煌脑O(shè)備,對(duì)應(yīng)不同的CPU架構(gòu)亥至,而CPU架構(gòu)對(duì)應(yīng)不同的指令集)
匯編語(yǔ)言的特點(diǎn)
- 可以
直接訪問(wèn)悼沈、控制各種硬件設(shè)備
,例如存儲(chǔ)器姐扮、CPU等絮供,能最大限度的發(fā)揮硬件的功能 - 能夠
不受編譯器的限制
,對(duì)生成的二進(jìn)制代碼進(jìn)行完全的控制 - 目標(biāo)代碼
簡(jiǎn)潔
茶敏,占用內(nèi)存少
壤靶,執(zhí)行速度快
- 匯編指令是機(jī)器指令的助記符,同機(jī)器指令一一對(duì)應(yīng)惊搏。每一種CPU都有自己的機(jī)器指令集/匯編指令集贮乳,所以
匯編語(yǔ)言不具備可移植性
忧换。 - 知識(shí)點(diǎn)過(guò)多,要求過(guò)高向拆,需要開(kāi)發(fā)者對(duì)CPU等硬件結(jié)構(gòu)有所了解亚茬,
不易于編寫(xiě)、調(diào)試浓恳,以及維護(hù)
-
不區(qū)分大小寫(xiě)
刹缝,例如mov和MOV是一樣的
匯編的用途
-
編寫(xiě)驅(qū)動(dòng)程序、操作系統(tǒng)
(比如Linux內(nèi)核的某些關(guān)鍵部分) - 對(duì)性能要求極高的程序或者代碼片段奖蔓,可與高級(jí)語(yǔ)言混合使用(內(nèi)聯(lián)匯編)
- 用于
軟件安全
方面- 病毒的分析與防治
- 逆向赞草、加殼、脫殼吆鹤、破解厨疙、外掛、免殺疑务、加解密沾凄、黑客等
匯編語(yǔ)言的種類(lèi)
目前討論比較多的匯編語(yǔ)言有:
- 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以后 |
必備常識(shí)
想要學(xué)好匯編保屯,需要以下幾個(gè)認(rèn)識(shí):
- 需要了解CPU等硬件的架構(gòu)
- 程序的執(zhí)行過(guò)程
程序的執(zhí)行過(guò)程.png
程序/App從磁盤(pán)中加載到內(nèi)存中,在內(nèi)存中的文件叫image(鏡像文件)
涤垫,早期都是直接拷貝姑尺,后面為了安全有了加殼加密簽名驗(yàn)證。在cpu眼中所有的數(shù)據(jù)都是0和1蝠猬,那么怎么區(qū)分指令和數(shù)據(jù)呢切蟋?通過(guò)pc寄存器
區(qū)分。
總線
總線是CPU與內(nèi)存
之間的橋梁
榆芦,如下圖所示是iPhone X上的A11(CPU芯片)
- 每一個(gè)CPU芯片都有許多管腳柄粹,這些管腳和總線相連,
CPU通過(guò)總線跟外部器件進(jìn)行交互
- 總線:
一根根導(dǎo)線的集合
- 總線的分類(lèi)
-
地址總線
:CPU是通過(guò)地址總線來(lái)指定存儲(chǔ)單元的 -
數(shù)據(jù)總線
:CPU與內(nèi)存/其他部件之間的數(shù)據(jù)傳送通道 -
控制總線
:CPU通過(guò)控制總線對(duì)外部器件進(jìn)行控制
總線分類(lèi).png
-
下面舉個(gè)小例子說(shuō)明CPU如何從內(nèi)存中讀取數(shù)據(jù)
【第一步】通過(guò)地址總線匆绣,找到需要訪問(wèn)的內(nèi)存地址驻右,假設(shè)此時(shí)需要尋址至內(nèi)存的3號(hào)單元
【第二步】通過(guò)控制總線,告訴內(nèi)存當(dāng)前需要執(zhí)行的操作犬绒,假設(shè)當(dāng)前的操作是
讀
【第三步】通過(guò)控制總線傳遞的內(nèi)容旺入,內(nèi)存知道CPU是想讀取3號(hào)單元的內(nèi)容,因此凯力,內(nèi)存通過(guò)數(shù)據(jù)總線將3號(hào)單元的數(shù)據(jù)返回給CPU
地址總線
地址總線
的寬度
決定了CPU的尋址能力
茵瘾,尋址能力
是指CPU一次所能訪問(wèn)內(nèi)存地址的最大值
。
例如:2根地址線有四種組合:00,01,10,11
咐鹤,于是CPU就最多只能訪問(wèn)這四個(gè)地址00~11拗秘,即2^2 = 4。
同理:10根地址總線能訪問(wèn)的最大內(nèi)存是 2^10 = 1024(即1K)
8086
的地址總線寬度是20祈惶,所以尋址能力是2^20 = 1M
內(nèi)存地址的單元是字節(jié)byte
(簡(jiǎn)寫(xiě)為B)雕旨,每個(gè)字節(jié)里面可以放8位
(即bit),以下是內(nèi)存條的圖示:
數(shù)據(jù)總線
數(shù)據(jù)總線
的寬度決定了CPU的單次數(shù)據(jù)傳送量
(即吞吐量)捧请,也就是數(shù)據(jù)傳送速度凡涩。
每條數(shù)據(jù)線一次
只能傳輸一位
二進(jìn)制數(shù)據(jù),因此傳輸1字節(jié)的數(shù)據(jù)疹蛉,則需要8根數(shù)據(jù)總線活箕。
8086
的數(shù)據(jù)總線寬度是16,所以單次最大傳遞2個(gè)字節(jié)
的數(shù)據(jù)(16/8=2)
通常我們所說(shuō)的32位
CPU指單次最大傳遞32/8=4字節(jié)
可款、64
位CPU指單次最大傳遞64/8=8字節(jié)
育韩,這里的32、64指的就是數(shù)據(jù)吞吐量
控制總線
控制總線
的寬度決定了CPU對(duì)其他器件的控制能力
闺鲸,能有多少種控制筋讨,即CPU對(duì)外部器件的控制能力
總線小練習(xí)
【問(wèn)題1】一個(gè)CPU 的尋址能力為8KB,那么它的地址總線的寬度為?
答:地址總線的寬度決定了CPU的尋址能力
摸恍。
地址總線寬度與尋址能力的關(guān)系為:2^n = 8K悉罕,因此n = 13
【問(wèn)題2】8080,8088,80286,80386 的地址總線寬度分別為16根,20根,24根,32根.那么他們的尋址能力分別為多少____KB, ____MB,____MB,____GB?
答:16根地址總線的尋址能力:2^16 = 64KB
20根地址總線的尋址能力:2^20 = 1024KB = 1MB
24根地址總線的尋址能力:2^16 = 16MB
32根地址總線的尋址能力:2^16 = 4096MB = 4GB
【問(wèn)題3】8080,8088,8086,80286,80386 的數(shù)據(jù)總線寬度分別為8根,8根,16根,16根,32根.那么它們一次可以傳輸?shù)臄?shù)據(jù)為:____B,____B,____B,____B,____B
答:數(shù)據(jù)總線的寬度決定了CPU的單次數(shù)據(jù)傳送量
。
8080有8根數(shù)據(jù)總線立镶,它一次可以傳輸?shù)臄?shù)據(jù)為:8/8 = 1B
8088有8根數(shù)據(jù)總線壁袄,它一次可以傳輸?shù)臄?shù)據(jù)為:8/8 = 1B
8086有16根數(shù)據(jù)總線,它一次可以傳輸?shù)臄?shù)據(jù)為:16/8 = 2B
80286有16根數(shù)據(jù)總線谜慌,它一次可以傳輸?shù)臄?shù)據(jù)為:16/8 = 2B
80386有32根數(shù)據(jù)總線然想,它一次可以傳輸?shù)臄?shù)據(jù)為:32/8 = 4B
【問(wèn)題4】從內(nèi)存中讀取1024字節(jié)的數(shù)據(jù),8086至少要讀____次,80386至少要讀取____次
答:8086有16根數(shù)據(jù)總線,一次可以傳輸?shù)臄?shù)據(jù)為16/8 = 2B欣范,若需要從內(nèi)存中讀取1024字節(jié)变泄,則需要讀1024/2 = 512次
80386有32根數(shù)據(jù)總線,一次可以傳輸?shù)臄?shù)據(jù)為:32/8 = 4B恼琼,若需要從內(nèi)存中讀取1024字節(jié)妨蛹,則需要讀1024/4 = 256次
內(nèi)存
內(nèi)存地址空間的大小受CPU地址總線寬度的限制。8086的地址總線寬度為20晴竞,可以定位2^20個(gè)不同的內(nèi)存單元(內(nèi)存地址范圍0x00000~0xFFFFF)蛙卤,所以8086的內(nèi)存空間大小為1MB
0x00000~0x9FFFF:主存儲(chǔ)器。可讀可寫(xiě)
0xA0000~0xBFFFF:向顯存中寫(xiě)入數(shù)據(jù)颤难,這些數(shù)據(jù)會(huì)被顯卡輸出到顯示器神年。可讀可寫(xiě)
0xC0000~0xFFFFF:存儲(chǔ)各種硬件\系統(tǒng)信息行嗤。只讀
數(shù)據(jù)的寬度
數(shù)學(xué)上
的數(shù)字是沒(méi)有大小限制的已日,可以無(wú)限大
。
但是在計(jì)算機(jī)
中栅屏,由于硬件的制約飘千,數(shù)據(jù)都是有長(zhǎng)度限制
的(稱為數(shù)據(jù)寬度),超過(guò)最多寬度的數(shù)據(jù)會(huì)被丟棄栈雳。
#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]));
}
}
以上代碼护奈,通過(guò)斷點(diǎn)調(diào)度可以發(fā)現(xiàn),當(dāng)cTemp被賦值了一個(gè)超過(guò)int最大值的數(shù)據(jù)時(shí)哥纫,會(huì)發(fā)生溢出霉旗。即超過(guò)的部分被丟棄
計(jì)算機(jī)中常見(jiàn)的數(shù)據(jù)寬度
-
位(Bit)
:1個(gè)位就是1個(gè)二進(jìn)制位,即0或1 -
字節(jié)(Byte)
:1個(gè)字節(jié)由8個(gè)Bit組成磺箕,內(nèi)存中的最小單元Byte -
字(Word)
:1個(gè)字由兩個(gè)字節(jié)組成(16位)奖慌,2個(gè)字節(jié)分別稱為高字節(jié)和低字節(jié) -
雙字(DoubleWord)
:1個(gè)雙字由兩個(gè)字組成(32位)
CPU & 寄存器
內(nèi)部部件之間由總線連接
CPU除了有
控制器
、運(yùn)算器
還有寄存器
松靡。其中寄存器的作用
就是進(jìn)行數(shù)據(jù)的臨時(shí)存儲(chǔ)
简僧。CPU的運(yùn)算速度是非常快的雕欺,為了性能CPU在內(nèi)部開(kāi)辟了一小塊臨時(shí)存儲(chǔ)區(qū)域岛马,并在進(jìn)行運(yùn)算時(shí)先將數(shù)據(jù)從內(nèi)存中復(fù)制到這一小塊臨時(shí)區(qū)域中。運(yùn)算就在這一小塊臨時(shí)存儲(chǔ)區(qū)進(jìn)行屠列,稱這一小塊臨時(shí)存儲(chǔ)區(qū)域?yàn)?code>寄存器
對(duì)于
arm64系
的CPU來(lái)說(shuō)啦逆, 如果寄存器以x開(kāi)頭
則表明的是一個(gè)64位的寄存器
,如果以w開(kāi)頭
則表明是一個(gè)32位的寄存器
笛洛,其中32位的寄存器是64位寄存器的低32位部分并不是獨(dú)立存在的
夏志。對(duì)程序員來(lái)說(shuō),CPU中最主要部件是
寄存器
苛让,可以通過(guò)改變寄存器的內(nèi)容來(lái)實(shí)現(xiàn)對(duì)CPU的控制不同的CPU沟蔑,寄存器的個(gè)數(shù)、結(jié)構(gòu)是不相同的
浮點(diǎn)寄存器
因?yàn)楦↑c(diǎn)數(shù)的存儲(chǔ)以及其運(yùn)算的特殊性狱杰,CPU中專門(mén)提供浮點(diǎn)寄存器
來(lái)處理浮點(diǎn)數(shù)
浮點(diǎn)寄存器
- 64位:D0 - D31
- 32位:S0 - S31
向量寄存器
現(xiàn)在的CPU支持向量運(yùn)算
瘦材。(向量運(yùn)算在圖形處理相關(guān)的領(lǐng)域用得非常的多)為了支持向量計(jì)算系統(tǒng)了也提供了眾多的向量寄存器
。
向量寄存器
- 128位:V0-V31
通用寄存器
通用寄存器也稱
數(shù)據(jù)地址寄存器
仿畸。通常用來(lái)做數(shù)據(jù)計(jì)算的臨時(shí)存儲(chǔ)食棕、做累加朗和、計(jì)數(shù)、地址保存
等功能簿晓。定義這些寄存器的作用主要是用于在CPU指令中保存操作數(shù)眶拉,在CPU中當(dāng)做一些常規(guī)變量來(lái)使用。-
ARM64擁有
32個(gè)64位的通用寄存器x0 到 x30
抢蚀,以及XZR(零寄存器)
镀层,這些通用寄存器有時(shí)也有特定用途镰禾。- w0-w28這些32位的皿曲,因?yàn)?4位CPU可以兼容32位,所以可以只使用64位寄存器的低32位
- 例如w0就是x0的低32位
注意:了解過(guò)8086匯編的一定知道吴侦,還有一種特殊的寄存器段寄存器:CS屋休、DS、SS备韧、ES劫樟。這四個(gè)寄存器主要用來(lái)保存這些段的基地址,是屬于Intel架構(gòu)的CPU的织堂,在arm中并沒(méi)有
- 通常叠艳,
CPU會(huì)先將內(nèi)存中的數(shù)據(jù)存儲(chǔ)到通用寄存器中,然后再對(duì)寄存器中的數(shù)據(jù)進(jìn)行運(yùn)算
假設(shè)內(nèi)存中有塊紅色內(nèi)存空間的值是3易阳,現(xiàn)在想把它的值加1附较,并將結(jié)果存儲(chǔ)到藍(lán)色內(nèi)存空間
【第一步】CPU首先會(huì)將紅色內(nèi)存空間的值放到X0寄存器中:
mov X0,紅色內(nèi)存空間
【第二步】然后讓X0寄存器與1相加:
add X0,1
【第三步】最后將值賦值給內(nèi)存空間:
mov 藍(lán)色內(nèi)存空間,X0
PC寄存器(program counter)
-
指令指針
寄存器,它指示了CPU當(dāng)前要讀取指令的地址
- 在內(nèi)存/磁盤(pán)上潦俺,指令和數(shù)據(jù)沒(méi)有任何區(qū)別拒课,都是二進(jìn)制信息
- CPU在工作時(shí),將有的信息看作指令事示,有的看作數(shù)據(jù)早像,為同樣的信息賦予了不同的意義
例如:1110 0000 0000 0011 0000 1000 1010 1010
可以當(dāng)做數(shù)據(jù) 0xE003008AA,也可以當(dāng)做指令 mov x0, x8 - CPU將
PC寄存器
指向的內(nèi)存單元的內(nèi)容看作指令
- 如果內(nèi)存中的某段內(nèi)容曾經(jīng)
被CPU執(zhí)行過(guò)
肖爵,那么它所在的內(nèi)存單元必然被PC寄存器指向過(guò)
高速緩存
iPhoneX上搭載的arm處理器A11卢鹦,它的1級(jí)緩存的容量是64kb,2級(jí)緩存的容量是8M
CPU每執(zhí)行一條指令前都需要從內(nèi)存中將指令讀取到內(nèi)存并執(zhí)行劝堪,而寄存器的運(yùn)行速度相比內(nèi)存讀寫(xiě)要快很多冀自,為了性能,CPU還集成了一個(gè)
高速緩存區(qū)域
幅聘。當(dāng)程序運(yùn)行時(shí)凡纳,先將要執(zhí)行的指令代碼以及數(shù)據(jù)復(fù)制到高速緩存中(由操作系統(tǒng)完成),然后CPU直接從高速緩存依次讀取指令來(lái)執(zhí)行
bl指令
- CPU從何處執(zhí)行指令帝蒿,是由
PC寄存器
中的內(nèi)容決定的荐糜,可以通過(guò)改變PC寄存器
的內(nèi)容來(lái)控制CPU執(zhí)行目標(biāo)指令
- arm64提供了一個(gè)
mov指令
(傳送指令),可以用來(lái)改變大部分寄存器的值,例如mov x0,#10
(等價(jià)于x0=10)暴氏、mov x1,#20
(等價(jià)于x1=20) -
mov指令并不能用于設(shè)置PC寄存器的值
延塑,arm64沒(méi)有提供這樣的功能 - arm64提供了另外的指令來(lái)修改
PC寄存器
的值,這些指令統(tǒng)一稱為轉(zhuǎn)移指令
答渔,其中最簡(jiǎn)單的是bl指令