匯編語言百度百科詞條:
機(jī)器語言
由0和1組成的機(jī)器指令.
匯編語言(assembly language)
由于機(jī)器語言指令都是由01組成,難以編寫,記憶和維護(hù)程序.所以匯編語言為了解決這一問題產(chǎn)生。
匯編語言的主體是匯編指令,匯編指令是機(jī)器指令的助記符。
使用助記符代替機(jī)器語言
高級(jí)語言(High-level programming language)
C\C++\Java\OC\Swift,更加接近人類的自然語言
比如C語言:
大家都知道我們的代碼在終端設(shè)備上執(zhí)行的過程,如下:
- 匯編語言與機(jī)器語言一一對(duì)應(yīng),每一條機(jī)器指令都有與之對(duì)應(yīng)的匯編指令
- 匯編語言可以通過編譯得到機(jī)器語言,機(jī)器語言可以通過反匯編得到匯編語言
- 高級(jí)語言可以通過編譯得到匯編語言 \ 機(jī)器語言,但匯編語言\機(jī)器語言幾乎不可能還原成高級(jí)語言
匯編語言的組成
- 1、匯編指令(機(jī)器碼的助記符,有對(duì)應(yīng)的機(jī)器碼);
- 2、偽指令(由編譯器執(zhí)行)和其他符號(hào)(由編譯器識(shí)別)。
匯編語言的特點(diǎn)
可以直接訪問、控制各種硬件設(shè)備,比如存儲(chǔ)器、CPU等,能最大限度地發(fā)揮硬件的功能
能夠不受編譯器的限制,對(duì)生成的二進(jìn)制代碼進(jìn)行完全的控制
目標(biāo)代碼簡短,占用內(nèi)存少,執(zhí)行速度快
匯編指令是機(jī)器指令的助記符,同機(jī)器指令一一對(duì)應(yīng)。每一種CPU都有自己的機(jī)器指令集\匯編指令集,所以匯編語言不具備可移植性
知識(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í)語言混合使用(內(nèi)聯(lián)匯編)
- 軟件安全
- 病毒分析與防治
- 逆向\加殼\脫殼\破解\外掛\免殺\加密解密\漏洞\黑客
- 理解整個(gè)計(jì)算機(jī)系統(tǒng)的最佳起點(diǎn)和最有效途徑
- 為編寫高效代碼打下基礎(chǔ)
- 弄清代碼的本質(zhì)
- 函數(shù)的本質(zhì)究竟是什么?
- ++a + ++a + ++a 底層如何執(zhí)行的?
- 編譯器到底幫我們干了什么?
- DEBUG模式和RELEASE模式有什么關(guān)鍵的地方被我們忽略
匯編語言的種類
-
目前討論比較多的匯編語言有
- 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)行交互
總線:總線是連接CPU和其他芯片的導(dǎo)線,可以理解為一根根導(dǎo)線的集合
-
總線按邏輯劃分為:
- 地址總線
- 數(shù)據(jù)總線
- 控制總線
-
地址總線
- 它的寬度決定了CPU的尋址能力
- 8086的地址總線寬度是20,所以尋址能力是1M( 2^20 )
-
數(shù)據(jù)總線
- 它的寬度決定了CPU的單次數(shù)據(jù)傳送量,也就是數(shù)據(jù)傳送速度
- 8086的數(shù)據(jù)總線寬度是16,所以單次最大傳遞2個(gè)字節(jié)的數(shù)據(jù)
注:一次能傳送的數(shù)據(jù)量也稱為吞吐量,32位 CPU 一次可以傳 4 個(gè)字節(jié)的數(shù)據(jù), 64 位的可以傳 8個(gè)字節(jié),OC 中的對(duì)象傳送的即為 指針,在 64 位 CPU 中位8個(gè)字節(jié),通電一次即可傳送完畢,所以效率高,32位的則需要兩次。
-
控制總線
- 它的寬度決定了CPU對(duì)其他器件的控制能力、能有多少種控制
-
CPU從內(nèi)存單元中讀寫數(shù)據(jù)的過程:
- CPU 通過地址總線獲取要讀或?qū)懙膬?nèi)存地址。
- 控制總線發(fā)出讀或?qū)懙拿睢?/li>
- 數(shù)據(jù)總線接收到命令,通過地址總線傳輸?shù)牡刂啡ハ鄳?yīng)的內(nèi)存中讀出/寫入數(shù)據(jù)。
注:CPU 讀取數(shù)據(jù)并不會(huì)直接運(yùn)算,先放入寄存器中,再進(jìn)行運(yùn)算,運(yùn)算完成以后再寫入內(nèi)存。
小結(jié)
1、匯編指令是機(jī)器指令的助記符,與機(jī)器指令一一對(duì)應(yīng)。
2、每一種CPU都有自己的匯編指令集,因?yàn)镃PU 的架構(gòu)不同。
3、CPU可以直接使用的信息在寄存器中存放。
4、在存儲(chǔ)器中指令和數(shù)據(jù)都是二進(jìn)制信息。
5、存儲(chǔ)單元從0開始順序編號(hào)。
6、一個(gè)存儲(chǔ)單元可以存儲(chǔ)8個(gè)bit,即 1B。
7、bit 、B、KB、MB、GB等單位之間的轉(zhuǎn)換。
1 GB == 1024 MB
1 MB == 1024 KB
1 KB = 1024 B(Byte 字節(jié))
1 B(Byte) = 8bit(二進(jìn)制位)
8、CPU管腳和總線相連。總線的寬度表示CPU不同方面的性能:
- 地址總線的寬度決定了CPU的尋址能力;
- 數(shù)據(jù)總線的寬度決定了CPU與其他器件進(jìn)行一次數(shù)據(jù)傳送的量;
- 控制總線寬度決定了CPU對(duì)系統(tǒng)中其他器件的控制。
小練習(xí)
- 一個(gè)CPU 的尋址能力為8KB,那么它的地址總線的寬度為____
- 8080,8088,80286,80386 的地址總線寬度分別為16根,20根,24根,32根.那么他們的尋址能力分別為多少____KB, ____MB,____MB,____GB?
- 8080,8088,8086,80286,80386 的數(shù)據(jù)總線寬度分別為8根,8根,16根,16根,32根.那么它們一次可以傳輸?shù)臄?shù)據(jù)為:____B,____B,____B,____B,____B,
- 從內(nèi)存中讀取1024字節(jié)的數(shù)據(jù),8086至少要讀____次,80386至少要讀取____次.
答案
闡釋:
1 GB == 1024 MB
1 MB == 1024 KB
1 KB = 1024 B(Byte 字節(jié))
1 B(Byte) = 8bit(二進(jìn)制位)
(1)地址總線的寬度決定了CPU的尋址能力
如:
8086的地址總線寬度是20,所以尋址能力是1M( 2^20 )
2 跟總線的話,能表達(dá)最大地址就是二進(jìn)制 11 ,也就是四個(gè)字節(jié)Byte ==4 個(gè)內(nèi)存單元 == 4B(0-3) == 2^2.
>再例如:8 根地址總線,2^8 == 256,能表示的數(shù)字就是 0—255.
256個(gè)字節(jié)。
8 KB == 8*1024 字節(jié)(Byte) == 8192 == 2^13.
(5)直接算:2^16 = 64 *1024 B = 64 KB
2^20 == 1 MB
2^24 = 16 MB
2^32 = 4096 MB = 4G
(6) 8 根就是 8 bit (二進(jìn)制位)== 1 個(gè)內(nèi)存單元 == 1 B
(7) 8086 數(shù)據(jù)總線是 16 根,一次最多讀取 2 B,那么
1024 字節(jié)/Byte 就需要 1024/2 = 512 次。
80386 是 32 根,數(shù)據(jù)總線剛好比 8086 多了一倍,就需要512/2 = 256 次。
內(nèi)存
(從上至下,低地址—>高地址:FFFFF == 16^5 == 245==1 MB,低地址給主存儲(chǔ)器使用,高地址供系統(tǒng)使用)
內(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)制呢?僅僅是因?yàn)槲覀儗?duì)十進(jìn)制最熟悉,所以才轉(zhuǎn)換.
每一種進(jìn)制都是完美的,想學(xué)好進(jìn)制首先要忘掉十進(jìn)制,也要忘掉進(jìn)制間的轉(zhuǎ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)一
進(jìn)制的運(yùn)算
做個(gè)練習(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
百度文庫各進(jìn)制乘法表
https://wenku.baidu.com/view/ee774a731ed9ad51f01df252.html
實(shí)戰(zhàn)四則運(yùn)算
(查表,跟小學(xué)學(xué)的加減乘除背的九九乘法表一個(gè)道理)
277 236 276 234
+ 333 - 54 * 54 / 4
-------- -------- -------- --------
答案:(自己算的,如果要專業(yè)的背下來最好,可能一時(shí)有點(diǎn)轉(zhuǎn)不過來)
632、162、20250、47
二進(jìn)制的簡寫形式
二進(jìn)制、八進(jìn)制、十六進(jìn)制之間的轉(zhuǎn)換。
二進(jìn)制: 1 0 1 1 1 0 1 1 1 1 0 0
三個(gè)二進(jìn)制一組: 101 110 111 100
八進(jìn)制: 5 6 7 4
四個(gè)二進(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
這種二進(jìn)制使用起來太麻煩,改成更簡單一點(diǎn)的符號(hào):
0 1 2 3 4 5 6 7 8 9 A B C D E F 這就是十六進(jìn)制了
(古稱:半斤八兩)
數(shù)據(jù)的寬度
數(shù)學(xué)上的數(shù)字,是沒有大小限制的,可以無限的大。但在計(jì)算機(jī)中,由于受硬件的制約,數(shù)據(jù)都是有長度限制的(我們稱為數(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位)
那么計(jì)算機(jī)存儲(chǔ)數(shù)據(jù)它會(huì)分為有符號(hào)數(shù)和無符號(hào)數(shù).那么關(guān)于這個(gè)看圖就理解了!
無符號(hào)數(shù),直接換算!
有符號(hào)數(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
寄存器 (register)
內(nèi)部部件之間由總線連接
- 對(duì)程序員來說,CPU中最主要部件是寄存器,可以通過改變寄存器的內(nèi)容來實(shí)現(xiàn)對(duì)CPU的控制
- 不同的CPU,寄存器的個(gè)數(shù)、結(jié)構(gòu)是不相同的
通用寄存器
-
ARM64擁有有31個(gè)64位的通用寄存器 x0 到 x30(其實(shí)是x0—x28),這些寄存器通常用來存放一般性的數(shù)據(jù),稱為通用寄存器(有時(shí)也有特定用途)
- 那么w0 到 w28 這些是32位的. 因?yàn)?4位CPU可以兼容32位.所以可以只使用64位寄存器的低32位.
- 比如 w0 就是 x0的低32位!
注:x0-x28,還有 fp 、lr 一共31 個(gè)寄存器,一般把 fp 看做 x29, lr 看做 x30 寄存器,下圖 pc 寄存器可以看到,sp 和 pc 不屬于通用寄存器
通常,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)存空間
讀取運(yùn)算過程
* 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指向過
注:匯編沒有開辟、銷毀空間一說,它是直接操控 CPU 和內(nèi)存。
如果調(diào)試過程中要查看某個(gè)內(nèi)存地址的值,可以在Debug->Debug workflow->ViewMemory 中查看,快捷鍵 Command + shift + M
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)移指令,最簡單的是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
C4
關(guān)于CPU的補(bǔ)充
寄存器
CPU除了有控制器、運(yùn)算器還有寄存器。其中寄存器的作用就是進(jìn)行數(shù)據(jù)的臨時(shí)存儲(chǔ)。
CPU的運(yùn)算速度是非常快的,為了性能CPU在內(nèi)部開辟一小塊臨時(shí)存儲(chǔ)區(qū)域,并在進(jìn)行運(yùn)算時(shí)先將數(shù)據(jù)從內(nèi)存復(fù)制到這一小塊臨時(shí)存儲(chǔ)區(qū)域中,運(yùn)算時(shí)就在這一小快臨時(shí)存儲(chǔ)區(qū)域內(nèi)進(jìn)行。我們稱這一小塊臨時(shí)存儲(chǔ)區(qū)域?yàn)榧拇嫫鳌?/p>
對(duì)于arm64系的CPU來說, 如果寄存器以x開頭則表明的是一個(gè)64位的寄存器,如果以w開頭則表明是一個(gè)32位的寄存器,在系統(tǒng)中沒有提供16位和8位的寄存器供訪問和使用。其中32位的寄存器是64位寄存器的低32位部分并不是獨(dú)立存在的。
高速緩存
iPhoneX上搭載的ARM處理器A11它的1級(jí)緩存的容量是64KB,2級(jí)緩存的容量8M.
CPU每執(zhí)行一條指令前都需要從內(nèi)存中將指令讀取到CPU內(nèi)并執(zhí)行。而寄存器的運(yùn)行速度相比內(nèi)存讀寫要快很多,為了性能,CPU還集成了一個(gè)高速緩存存儲(chǔ)區(qū)域.當(dāng)程序在運(yùn)行時(shí),先將要執(zhí)行的指令代碼以及數(shù)據(jù)復(fù)制到高速緩存中去(由操作系統(tǒng)完成).CPU直接從高速緩存依次讀取指令來執(zhí)行.
彌補(bǔ)寄存器的運(yùn)行速度和內(nèi)存讀寫速度之間的差距,提高速度,性能。
寄存器 --> L1 高速緩存 --> L2 高速緩存 --> L3 高速緩存 --> 內(nèi)存 --> 磁盤
寄存器的補(bǔ)充
數(shù)據(jù)地址寄存器
數(shù)據(jù)地址寄存器通常用來做數(shù)據(jù)計(jì)算的臨時(shí)存儲(chǔ)、做累加、計(jì)數(shù)、地址保存等功能。定義這些寄存器的作用主要是用于在CPU指令中保存操作數(shù),在CPU中當(dāng)做一些常規(guī)變量來使用。
ARM64中
- 64位: X0-X30, XZR(零寄存器)
- 32位: W0-W30, WZR(零寄存器)
注意:
之前講解8086匯編中有一種特殊的寄存器段寄存器:CS,DS,SS,ES四個(gè)寄存器來保存這些段的基地址,這個(gè)屬于Intel架構(gòu)CPU中.在ARM中并沒有,現(xiàn)在Intel架構(gòu)CPU中也沒有段寄存器了,只是文件中分段。
浮點(diǎn)和向量寄存器
因?yàn)楦↑c(diǎn)數(shù)的存儲(chǔ)以及其運(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)域用得非常的多)為了支持向量計(jì)算系統(tǒng)了也提供了眾多的向量寄存器.
- 向量寄存器 128位:V0-V31