匯編語(yǔ)言的發(fā)展
機(jī)器語(yǔ)言
由0和1組成的機(jī)器指令.
- 加:0100 0000
- 減:0100 1000
- 乘:1111 0111 1110 0000
- 除:1111 0111 1111 0000
為什么是0和1來表示?
就是高低電平咧织,1表示有電,0表示沒電
匯編語(yǔ)言(assembly language)
使用助記符代替機(jī)器語(yǔ)言
如:
- 加:INC EAX 通過編譯器 0100 0000
- 減:DEC EAX 通過編譯器 0100 1000
- 乘:MUL EAX 通過編譯器 1111 0111 1110 0000
- 除:DIV EAX 通過編譯器 1111 0111 1111 0000
因?yàn)镃PU是不會(huì)識(shí)別助記符的奇适,所以有了編譯器,把助記符轉(zhuǎn)換成一串由0和1組成的語(yǔ)言
高級(jí)語(yǔ)言(High-level programming language)
C\C++\Java\OC\Swift,更加接近人類的自然語(yǔ)言
比如C語(yǔ)言:
- 加:A+B 通過編譯器 0100 0000
- 減:A-B 通過編譯器 0100 1000
- 乘:A*B 通過編譯器 1111 0111 1110 0000
-
除:A/B 通過編譯器 1111 0111 1111 0000
我們的代碼在終端設(shè)備上是這樣的過程:
- 匯編語(yǔ)言與機(jī)器語(yǔ)言一一對(duì)應(yīng)本姥,每一條機(jī)器指令都有與之對(duì)應(yīng)的匯編指令
- 匯編語(yǔ)言可以通過編譯得到機(jī)器語(yǔ)言,機(jī)器語(yǔ)言可以通過反匯編得到匯編語(yǔ)言
- 高級(jí)語(yǔ)言可以通過編譯得到匯編語(yǔ)言 \ 機(jī)器語(yǔ)言杭棵,但匯編語(yǔ)言\機(jī)器語(yǔ)言幾乎不可能還原成高級(jí)語(yǔ)言
匯編語(yǔ)言的特點(diǎ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)過多,開發(fā)者需要對(duì)CPU等硬件結(jié)構(gòu)有所了解街图,不易于編寫浇衬、調(diào)試、維護(hù)
不區(qū)分大小寫餐济,比如mov和MOV是一樣的
匯編的用途
- 編寫驅(qū)動(dòng)程序耘擂、操作系統(tǒng)(比如Linux內(nèi)核的某些關(guān)鍵部分)
- 對(duì)性能要求極高的程序或者代碼片段,可與高級(jí)語(yǔ)言混合使用(內(nèi)聯(lián)匯編)
- 軟件安全
- 病毒分析與防治
- 逆向\加殼\脫殼\破解\外掛\免殺\加密解密\漏洞\黑客
- 理解整個(gè)計(jì)算機(jī)系統(tǒng)的最佳起點(diǎn)和最有效途徑
- 為編寫高效代碼打下基礎(chǔ)
- 弄清代碼的本質(zhì)
- 函數(shù)的本質(zhì)究竟是什么?
- ++a + ++a + ++a 底層如何執(zhí)行的?
- 編譯器到底幫我們干了什么?
- DEBUG模式和RELEASE模式有什么關(guān)鍵的地方被我們忽略
- ......
匯編語(yǔ)言的種類
-
目前討論比較多的匯編語(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以后 |
幾個(gè)必要的常識(shí)
- 要想學(xué)好匯編,首先需要了解CPU等硬件結(jié)構(gòu)
-
APP/程序的執(zhí)行過程
- 硬件相關(guān)最為重要是CPU/內(nèi)存
- 在匯編中,大部分指令都是和CPU與內(nèi)存相關(guān)的
總線
- 每一個(gè)CPU芯片都有許多管腳篙悯,這些管腳和總線相連蚁阳,CPU通過總線跟外部器件進(jìn)行交互
- 總線:一根根導(dǎo)線的集合
- 總線的分類
- 地址總線
- 數(shù)據(jù)總線
-
控制總線
內(nèi)存里面最小單位是字節(jié) 1Byte = 8bit
舉個(gè)例子
-
地址總線
- 它的寬度決定了CPU的尋址能力,尋址能力直接影響了你能用多大的內(nèi)存條
- 8086的地址總線寬度是20,所以尋址能力是1M( 2^20 )
-
數(shù)據(jù)總線
- 它的寬度決定了CPU的單次數(shù)據(jù)傳送量鸽照,也就是數(shù)據(jù)傳送速度
- 8086的數(shù)據(jù)總線寬度是16螺捐,所以單次最大傳遞2個(gè)字節(jié)的數(shù)據(jù)
-
控制總線
- 它的寬度決定了CPU對(duì)其他器件的控制能力、能有多少種控制
內(nèi)存
內(nèi)存地址空間的大小受CPU地址總線寬度的限制矮燎。8086的地址總線寬度為20定血,可以定位2^20個(gè)不同的內(nèi)存單元(內(nèi)存地址范圍0x00000~0xFFFFF),所以8086的內(nèi)存空間大小為1MB
0x00000~0x9FFFF:主存儲(chǔ)器诞外】返浚可讀可寫
0xA0000~0xBFFFF:向顯存中寫入數(shù)據(jù),這些數(shù)據(jù)會(huì)被顯卡輸出到顯示器浅乔【笪梗可讀可寫
0xC0000~0xFFFFF:存儲(chǔ)各種硬件\系統(tǒng)信息铝条。只讀
進(jìn)制
學(xué)習(xí)進(jìn)制的障礙
很多人學(xué)不好進(jìn)制,原因是總以十進(jìn)制為依托去考慮其他進(jìn)制席噩,需要運(yùn)算的時(shí)候也總是先轉(zhuǎn)換成十進(jìn)制班缰,這種學(xué)習(xí)方法是錯(cuò)誤的.
我們?yōu)槭裁匆欢ㄒD(zhuǎn)換十進(jìn)制呢??jī)H僅是因?yàn)槲覀儗?duì)十進(jìn)制最熟悉悼枢,所以才轉(zhuǎn)換.
每一種進(jìn)制都是完美的,想學(xué)好進(jìn)制首先要忘掉十進(jìn)制埠忘,也要忘掉進(jìn)制間的轉(zhuǎn)換!
進(jìn)制的定義
- 八進(jìn)制由8個(gè)符號(hào)組成:0 1 2 3 4 5 6 7 逢八進(jìn)一
- 十進(jìn)制由10個(gè)符號(hào)組成:0 1 2 3 4 5 6 7 8 9逢十進(jìn)一
- N進(jìn)制就是由N個(gè)符號(hào)組成:逢N進(jìn)一
做個(gè)練習(xí)
- 1 + 1 在____情況下等于 3 ?
十進(jìn)制由10個(gè)符號(hào)組成: 0 1 3 2 8 A B E S 7 逢十進(jìn)一
如果這樣定義十進(jìn)制: 1 + 1 = 3!就對(duì)了!
這樣的目的何在?
傳統(tǒng)我們定義的十進(jìn)制和自定義的十進(jìn)制不一樣.那么這10個(gè)符號(hào)如果我們不告訴別人這個(gè)符號(hào)表,別人是沒辦法拿到我們的具體數(shù)據(jù)的!用于加密!
十進(jìn)制由十個(gè)符號(hào)組成,逢十進(jìn)一,符號(hào)是可以自定義的!!
數(shù)據(jù)的寬度
數(shù)學(xué)上的數(shù)字馒索,是沒有大小限制的莹妒,可以無限的大。但在計(jì)算機(jī)中绰上,由于受硬件的制約旨怠,數(shù)據(jù)都是有長(zhǎng)度限制的(我們稱為數(shù)據(jù)寬度),超過最多寬度的數(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]));
}
}
計(jì)算機(jī)中常見的數(shù)據(jù)寬度
- 位(Bit): 1個(gè)位就是1個(gè)二進(jìn)制位.0或者1
- 字節(jié)(Byte): 1個(gè)字節(jié)由8個(gè)Bit組成(8位).內(nèi)存中的最小單元Byte.
- 字(Word): 1個(gè)字由2個(gè)字節(jié)組成(16位),這2個(gè)字節(jié)分別稱為高字節(jié)和低字節(jié).
- 雙字(Doubleword): 1個(gè)雙字由兩個(gè)字組成(32位)
寄存器
內(nèi)部部件之間由總線連接
- 對(duì)程序員來說鉴腻,CPU中最主要部件是寄存器,可以通過改變寄存器的內(nèi)容來實(shí)現(xiàn)對(duì)CPU的控制
- 不同的CPU百揭,寄存器的個(gè)數(shù)爽哎、結(jié)構(gòu)是不相同的
通用寄存器
-
ARM64擁有有31個(gè)64位的通用寄存器 x0 到 x30,這些寄存器通常用來存放一般性的數(shù)據(jù),稱為通用寄存器(有時(shí)也有特定用途)
- 那么w0 到 w28 這些是32位的. 因?yàn)?4位CPU可以兼容32位.所以可以只使用64位寄存器的低32位.
-
比如 w0 就是 x0的低32位!
通常器一,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)存或者磁盤上,指令和數(shù)據(jù)沒有任何區(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根據(jù)什么將內(nèi)存中的信息看做指令获印?
- CPU將pc指向的內(nèi)存單元的內(nèi)容看做指令
- 如果內(nèi)存中的某段內(nèi)容曾被CPU執(zhí)行過述雾,那么它所在的內(nèi)存單元必然被pc指向過
bl指令
CPU從何處執(zhí)行指令是由pc中的內(nèi)容決定的,我們可以通過改變pc的內(nèi)容來控制CPU執(zhí)行目標(biāo)指令
-
ARM64提供了一個(gè)mov指令(傳送指令)兼丰,可以用來修改大部分寄存器的值玻孟,比如
- mov x0,#10、mov x1,#20
但是鳍征,mov指令不能用于設(shè)置pc的值黍翎,ARM64沒有提供這樣的功能
ARM64提供了另外的指令來修改PC的值,這些指令統(tǒng)稱為轉(zhuǎn)移指令艳丛,最簡(jiǎn)單的是bl指令
bl指令 -- 練習(xí)
現(xiàn)在有兩段代碼!假設(shè)程序先執(zhí)行A,請(qǐng)寫出指令執(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