一.認(rèn)識(shí)匯編語言
要認(rèn)識(shí)匯編語言唆铐,還得從編程語言的發(fā)展說起蹲嚣,語言有以下幾種分類采郎,其發(fā)展都是為了讓我們更容易去操縱計(jì)算機(jī):
- 機(jī)器語言:由0和1組成苔悦。
- 匯編語言:用符號(hào)代替了0和1净嘀,比機(jī)器語言更便于閱讀和記憶报咳。
- 高級(jí)語言:Objective-C/Java/C++等,更接近人類語言挖藏,方便程序員的使用暑刃。
舉個(gè)例子??:
以賦值a=b為例(計(jì)算上的操作就是將寄存器BX的內(nèi)容送入寄存器AX):
可以看到我們寫的代碼經(jīng)過編譯轉(zhuǎn)換成計(jì)算機(jī)能夠知道的指令,從而讓計(jì)算機(jī)進(jìn)行相應(yīng)的操作膜眠。匯編語言與機(jī)器語言一一對(duì)應(yīng)岩臣,每一條機(jī)器指令都有與之對(duì)應(yīng)的匯編指令。匯編語言可以通過編譯得到機(jī)器語言宵膨,機(jī)器語言可以通過反匯編得到匯編語言架谎。高級(jí)語言可以通過編譯得到匯編語言\機(jī)器語言,但匯編語言\機(jī)器語言幾乎不可能還原成高級(jí)語言辟躏。
匯編語言有如下特點(diǎn):
① 可以直接訪問谷扣、控制各種硬件設(shè)備,比如存儲(chǔ)器捎琐、CPU等会涎,能最大限度地發(fā)揮硬件的功能涯曲。但是知識(shí)點(diǎn)過多,開發(fā)者需要對(duì)CPU等硬件結(jié)構(gòu)有所了解在塔,所以不易于編寫幻件、調(diào)試、維護(hù)蛔溃。
② 能夠不受編譯器的限制绰沥,對(duì)生成的二進(jìn)制代碼進(jìn)行完全的控制。
③ 目標(biāo)代碼簡(jiǎn)短贺待,占用內(nèi)存少徽曲,執(zhí)行速度快◆锶可能寫的源文件比較大(相對(duì)高級(jí)語言比較啰嗦)秃臣,但是編譯后的目標(biāo)文件、可執(zhí)行文件都小得多哪工。
以c = a + b為例:(對(duì)比匯編語言和C++語言)
④ 匯編指令是機(jī)器指令的助記符,同機(jī)器指令一一對(duì)應(yīng)奥此。每一種CPU都有自己的機(jī)器指令集\匯編指令集,所以匯編語言不具備可移植性雁比。
也是因?yàn)閰R編語言的這些特點(diǎn)稚虎,讓學(xué)習(xí)它有了重要的用途:
- 理解代碼的本質(zhì),為編寫高效代碼打下基礎(chǔ)偎捎。
- 理解整個(gè)計(jì)算機(jī)系統(tǒng)的最佳起點(diǎn)和最有效途徑蠢终。
- 編寫驅(qū)動(dòng)程序、操作系統(tǒng)茴她,對(duì)性能要求極高的程序或者代碼片段寻拂,可與高級(jí)語言混合使用(內(nèi)聯(lián)匯編)
- 軟件安全、病毒分析與防治
iPhone里面用到的是ARM匯編:
- armv6:iPhone, iPhone2, iPhone3G, 第一代丈牢、第二代 iPod Touch
- armv7:3GS,4, 4S,iPad, iPad2, iPad3, iPad mini, iPod Touch 3G, iPod Touch4
- armv7s:5, 5C, iPad4
- arm64:5S 及以后 iPhoneX , iPad Air, iPad mini2以后
二. 計(jì)算機(jī)硬件結(jié)構(gòu)基礎(chǔ)與匯編
要想學(xué)好匯編語言祭钉,首先要對(duì)CPU等硬件結(jié)構(gòu)有一定的了解。最為關(guān)鍵的是需要了解CPU和內(nèi)存赡麦,我們遇到的絕大部分指令都是跟內(nèi)存朴皆、CPU有關(guān)的帕识。
App的啟動(dòng)過程如下:
接下來我們具體講講數(shù)據(jù)(指定)的交互泛粹,其中有這么幾個(gè)重要的部件需要了解:
① 總線
② 內(nèi)存
③ 寄存器
① 總線
每一個(gè)CPU芯片都有許多管腳,這些管腳和總線相連肮疗,CPU通過總線跟外部器件進(jìn)行交互晶姊。
總線有三種類型:地址總線、數(shù)據(jù)總線和控制總線伪货。
以CPU從內(nèi)存的3號(hào)單元讀取數(shù)據(jù)為例:
地址總線負(fù)責(zé)傳地址(尋址)们衙,它的寬度決定了CPU的尋址能力钾怔。比如8086的地址總線是20(20根線),尋址能力是1M(2的20次方)(2的10次方就進(jìn)1個(gè)單位蒙挑,B → KB → M)宗侦。
數(shù)據(jù)總線負(fù)責(zé)傳數(shù)據(jù),它的寬度決定了CPU的單次數(shù)據(jù)傳輸量忆蚀,也就是數(shù)據(jù)傳輸速度矾利。比如從內(nèi)存中讀取1024字節(jié)的數(shù)據(jù)(1024B),8086(16位馋袜,即每次傳2字節(jié))至少要讀(傳輸)512次男旗,80386(32位,即每次傳4字節(jié))至少要讀256次欣鳖。 → 我們常說的32位和64位CPU指的就是這個(gè)
控制總線負(fù)責(zé)傳控制命令察皇,它的寬度決定了CPU對(duì)其他器件的控制類型的多少。
例子??:8088的數(shù)據(jù)總線寬度是8(8條線泽台,一條只能傳0和1兩種訊號(hào)什荣,),8086的數(shù)據(jù)總線寬度是16怀酷,分別向內(nèi)存中寫入89D8H(這邊4個(gè)16進(jìn)制溃睹,需要16位,所以8080只能先傳一半)
常見的數(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é)竞滓。
進(jìn)制占字節(jié)數(shù)
2進(jìn)制:一個(gè)2進(jìn)制占1位,1/8個(gè)字節(jié)吹缔。
8進(jìn)制:一個(gè)8進(jìn)制占3位商佑,3/8個(gè)字節(jié)。
16進(jìn)制:一個(gè)16進(jìn)制占4位厢塘,1/2個(gè)字節(jié)茶没。
② 內(nèi)存
內(nèi)存(Memory)也被稱為內(nèi)存儲(chǔ)器,其作用是用于暫時(shí)存放CPU中的運(yùn)算數(shù)據(jù)晚碾,以及與硬盤等外部存儲(chǔ)器交換的數(shù)據(jù)抓半。只要計(jì)算機(jī)在運(yùn)行中,CPU就會(huì)把需要運(yùn)算的數(shù)據(jù)調(diào)到內(nèi)存中進(jìn)行運(yùn)算格嘁,當(dāng)運(yùn)算完成后CPU再將結(jié)果傳送出來笛求,內(nèi)存的運(yùn)行也決定了計(jì)算機(jī)的穩(wěn)定運(yùn)行。
計(jì)算機(jī)中有各類存儲(chǔ)器,它們的邏輯連接情況如下:
內(nèi)存地址范圍(空間大刑饺搿)受CPU地址總線寬度的限制狡孔。比如8086地址總線寬度是20,可以定位2的20次方不同的內(nèi)存單元蜂嗽,所以內(nèi)存地址范圍為0x00000~0xFFFFF(1個(gè)16位占4),內(nèi)存空間大小為1M苗膝。
各類存儲(chǔ)器地址肯定是不一樣的,他們又不一定是在一塊植旧,所以我們把它想象成一塊虛擬的邏輯存儲(chǔ)器荚醒。如下圖:
每段內(nèi)存地址都有特定的用途:
CPU訪問內(nèi)存單元時(shí),要給出內(nèi)存單元的地址隆嗅。8086有20位地址總線界阁,可以傳送20位的地址,1M的尋址能力(從首地址到尾地址為1M)胖喳。但它又是16位結(jié)構(gòu)的CPU泡躯,它內(nèi)部能夠一次性處理、傳輸丽焊、暫時(shí)存儲(chǔ)的地址為16位较剃。如果將地址從內(nèi)部簡(jiǎn)單地發(fā)出,那么它只能送出16位的地址技健,表現(xiàn)出來的尋址能力只有64KB写穴。
所以,8086采用一種在內(nèi)部用2個(gè)16位地址(段地址和偏移地址)合成的方法來生成1個(gè)20位的物理地址雌贱。8086是用“起始地址(段地址×16(16位就是進(jìn)一格啊送,后面補(bǔ)0)) + 偏移地址 = 物理地址”的方式給出物理地址。
為了開發(fā)方便欣孤,我們可以采取分段的方法來管理內(nèi)存馋没,比如:
地址10000H - 100FFH的內(nèi)存單元組成一個(gè)段,該段的起始地址為10000H降传,段地址為1000H篷朵,大小為100H。地址10000H - 1007FH婆排、10080H - 100FFH的內(nèi)存單元組成2個(gè)段声旺,它們的起始地址為:10000H和10080H,段地址為1000H和1008H段只,大小都為80H腮猖。
偏移地址為16位,變化范圍0-FFFFH翼悴,僅用偏移地址來尋址最多可尋64KB個(gè)內(nèi)存單元(尋址能力為64KB缚够,所以一個(gè)段的長(zhǎng)度最大為64KB)。比如給定段地址1000H鹦赎,用偏移地址尋址谍椅,CPU的尋址范圍為:10000H - 1FFFFH。
③ 寄存器
總線和內(nèi)存算是CPU外面的東西古话,接下來我們要說最重要的部分——CPU雏吭。
CPU主要是解釋計(jì)算機(jī)指令以及處理計(jì)算機(jī)軟件中的數(shù)據(jù)。它主要由三大部件構(gòu)成(其內(nèi)部部件之間由總線相連):
對(duì)程序員來說陪踩,CPU中最主要部件是寄存器杖们,可以通過改變寄存器的內(nèi)容來實(shí)現(xiàn)對(duì)CPU的控制。
不同的CPU肩狂,寄存器的個(gè)數(shù)摘完、結(jié)構(gòu)是不相同的。比如:8086是16位結(jié)構(gòu)的CPU傻谁,有14個(gè)16位的寄存器(每個(gè)寄存器可以存放2個(gè)字節(jié))孝治。
以通用寄存器為例:
AX、BX审磁、CX谈飒、DX這4個(gè)寄存器通常用來存放一般性的數(shù)據(jù),稱為通用寄存器(有時(shí)也有特定用途)态蒂。通常杭措,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)存空間瘩蚪。會(huì)有三個(gè)步驟:
① CPU首先會(huì)將紅色內(nèi)存空間的值放到AX寄存器中:mov ax,紅色內(nèi)存空間
② 然后讓AX寄存器與1相加:add ax,1
③ 最后將值賦值給內(nèi)存空間:mov 藍(lán)色內(nèi)存空間,ax
像AX刑桑、BX、CX募舟、DX這4個(gè)寄存器都是16位的祠斧,意味著它們能存16個(gè)0或1,可以存兩個(gè)字節(jié)(byte)拱礁,一個(gè)字(word)琢锋。上一代8086的寄存器都是8位的,為了保證兼容呢灶, AX吴超、BX、CX鸯乃、DX都可分為2個(gè)獨(dú)立的8位寄存器來使用鲸阻。
在匯編的數(shù)據(jù)存儲(chǔ)中跋涣,有2個(gè)比較常用的單位:
字節(jié)(byte):1個(gè)字節(jié)由8bit組成,可以存儲(chǔ)在8位寄存器中鸟悴。
字(word):1個(gè)字由2個(gè)字節(jié)組成陈辱,這2個(gè)字節(jié)分別稱為字的高字節(jié)和低字節(jié)。
比如上圖中细诸,數(shù)據(jù)20000(4E20H沛贪,0100111000100000B),高字節(jié)的值是78震贵,低字節(jié)的值是32利赋。1個(gè)字可以存在1個(gè)16位寄存器中,這個(gè)字的高字節(jié)猩系、低字節(jié)分別存儲(chǔ)在這個(gè)寄存器的高8位寄存器(AH)媚送、低8位寄存器(AL)中。
已知寇甸,8086在訪問內(nèi)存時(shí)要由相關(guān)部件提供內(nèi)存單元的段地址和偏移地址季希,送入地址加法器合成物理地址。那是什么部件提供段地址幽纷?
段地址在8086的段寄存器中存放式塌,8086有4個(gè)段寄存器:CS、DS友浸、SS峰尝、ES,當(dāng)CPU需要訪問內(nèi)存時(shí)由這4個(gè)段寄存器提供內(nèi)存單元的段地址收恢。
CS (Code Segment):代碼段寄存器
DS (Data Segment):數(shù)據(jù)段寄存器
SS (Stack Segment):堆棧段寄存器
ES (Extra Segment):附加段寄存器
CS(代碼段寄存器)
CS為代碼段寄存器武学,IP為指令指針寄存器,它們指示了CPU當(dāng)前要讀取指令的地址伦意。任意時(shí)刻火窒,8086CPU都會(huì)將CS:IP指向的指令作為下一條需要取出執(zhí)行的指令。
步驟如下:
① CS驮肉、IP中的內(nèi)容送入地址加法器熏矿,生成物理地址20000H。
② 地址加法器將物理地址送入輸入輸出控制電路离钝。
③ 輸入輸出控制電路將物理地址20000H送上地址總線票编。
④ 從內(nèi)存20000H單元開始存放的機(jī)器指令(B8 23 01)通過數(shù)據(jù)總線被送入CPU。(為什么是3個(gè)呢卵渴?應(yīng)該是這三個(gè)組成一個(gè)完整的機(jī)器指令慧域,有的是兩個(gè)組成的)
⑤ 輸入輸出控制電路將指令(B8 23 01)送入指令緩沖器。
讀取一條指令后浪读,IP中的值自動(dòng)增加昔榴,以使CPU可以讀取下一條指令辛藻。因當(dāng)前讀入的指令(B8 23 01)為三個(gè)字節(jié),所以IP中的值加3互订。此時(shí)吱肌,CS:IP 指向內(nèi)存單元2000:0003。
⑥ 執(zhí)行控制器執(zhí)行指令(B8 23 01)屁奏,即mov ax 0123H岩榆。
⑦ 指令被執(zhí)行后AX中的內(nèi)容為0123H错负。
此時(shí)坟瓢,CPU將從內(nèi)存單元2000:0003處讀取指令。
⑧ CPU從內(nèi)存20003H處讀取指令(BB 03 30)入指令緩存器犹撒,IP中的值加3折联。
后面指令以此類推。识颊。诚镰。
在8086CPU啟動(dòng)或復(fù)位后,CS:IP 被設(shè)置為FFFFH:0000H祥款,所以FFFF0H單元中的指令是開機(jī)后的第一條指令清笨。
CPU從何處執(zhí)行指令是由CS骏掀、IP中的內(nèi)容決定的队伟,我們可以通過改變CS、IP的內(nèi)容來控制CPU執(zhí)行目標(biāo)指令诊县。
jmp指令(跳轉(zhuǎn))
8086提供了一個(gè)mov指令(傳送指令)桨昙,可以用來修改大部分寄存器的值检号,比如mov ax,10、mov bx,20蛙酪、mov cx,30齐苛、mov dx,40。但是桂塞,mov指令不能用于設(shè)置CS凹蜂、IP的值,8086沒有提供這樣的功能阁危。
8086提供了另外的指令來修改CS炊甲、IP的值,這些指令統(tǒng)稱為轉(zhuǎn)移指令欲芹,最簡(jiǎn)單的是jmp指令卿啡。
jmp 段地址:偏移地址 ?? 用指令中給出的段地址修改CS,偏移地址修改IP
jmp 直接值??用直接值修改IP
jmp 某一合法寄存器??用寄存器中的值修改IP
例子??:
jmp 2AE3:3菱父,執(zhí)行后CS = 2AE3H颈娜,IP = 0003H剑逃,CPU將從2AE33H處讀取指令。
DS(地址段寄存器)
CPU要讀寫一個(gè)內(nèi)存單元時(shí)官辽,必須要先給出這個(gè)內(nèi)存單元的地址蛹磺,在8086中,內(nèi)存地址由段地址和偏移地址組成同仆,8086中有一個(gè)DS段寄存器萤捆,通常用來存放要訪問數(shù)據(jù)的段地址。
舉個(gè)例子??:
mov bx俗批,1000H
mov dx俗或,bx
mov al,[0]
上面3條指令的作用將10000H(1000:0)中的內(nèi)存數(shù)據(jù)賦值到al寄存器中岁忘。mov al,[address]的意思將DS:address中的內(nèi)存數(shù)據(jù)賦值到al寄存器中辛慰,由于al是8位寄存器,所以是將一個(gè)字節(jié)的數(shù)據(jù)賦值給al寄存器(由于8086不支持將數(shù)據(jù)直接送入段寄存器中干像,mov ds,1000H是錯(cuò)誤的)帅腌。
上面的例子中是賦值給al(8位),如果是賦值給ax呢(16位)麻汰?那就是字型數(shù)據(jù)的傳遞(2個(gè)字節(jié)速客,16位)。
在內(nèi)存中五鲫,一個(gè)地址放一個(gè)字節(jié)的數(shù)據(jù)(8位溺职,兩個(gè)16進(jìn)制,如34)臣镣,傳遞字型意味著要2個(gè)內(nèi)存單元辅愿。那是從低內(nèi)存開始或者從高內(nèi)存開始,這就涉及到大小端的概念忆某。
- 大端模式点待,是指數(shù)據(jù)的高字節(jié)保存在內(nèi)存的低地址中,而數(shù)據(jù)的低字節(jié)保存在內(nèi)存的高地址中(高低\低高)
- 小端模式弃舒,是指數(shù)據(jù)的高字節(jié)保存在內(nèi)存的高地址中癞埠,而數(shù)據(jù)的低字節(jié)保存在內(nèi)存的低地址中(高高\(yùn)低低)
比如我們常見的x86就是小端模式,ARM小端大端都可以聋呢。
舉個(gè)例子??:
mov指令(賦值)
mov 寄存器苗踪,數(shù)據(jù) // 比如mov ax,8
mov 寄存器削锰,寄存器 // 比如mov ax通铲,bx
mov 寄存器,內(nèi)存單元 // 比如mov ax器贩,[0]
mov 內(nèi)存單元颅夺,寄存器 // 比如mov [0]朋截,ax
mov 段寄存器,寄存器 // 比如mov ds吧黄,ax
mov 寄存器部服,段寄存器 // 比如mov ax,ds
mov 內(nèi)存單元拗慨,內(nèi)存單元 //這個(gè)是錯(cuò)誤的
add和sub指令
add 寄存器廓八,數(shù)據(jù) // 比如add ax,8
add 寄存器赵抢,寄存器 // 比如add ax剧蹂,bx
add 寄存器,內(nèi)存單元 // 比如add ax昌讲,[0]
add 內(nèi)存單元国夜,寄存器 // 比如add [0]减噪,ax
sub 寄存器短绸,數(shù)據(jù) // 比如sub ax,8
sub 寄存器筹裕,寄存器 // 比如sub ax醋闭,bx
sub 寄存器,內(nèi)存單元 // 比如sub ax朝卒,[0]
sub 內(nèi)存單元证逻,寄存器 // 比如sub [0],ax
棧(棧段)
棧:是一種具有特殊的訪問方式的存儲(chǔ)空間(后進(jìn)先出)
8086會(huì)將CS作為代碼段的段地址抗斤,將CS:IP指向的指令作為下一條需要取出執(zhí)行的指令囚企。
8086會(huì)將DS作為數(shù)據(jù)段的段地址,mov ax,[address]就是取出DS:address的內(nèi)存數(shù)據(jù)放到ax寄存器中瑞眼。
8086會(huì)將SS作為棧段的段地址龙宏,任意時(shí)刻,SS:SP指向棧頂元素伤疙。
8086提供了PUSH(入棧)和POP (出棧)指令來操作棧段的數(shù)據(jù)
比如push ax是將ax的數(shù)據(jù)入棧银酗,pop ax是將棧頂?shù)臄?shù)據(jù)送入ax。
椡较瘢空時(shí)黍特,SS:SP指向棧空間最高地址單元的下一個(gè)單元(就是棧的下面锯蛀,棧外了)灭衷。
push和pop指令
在8086中,push旁涤、pop操作的數(shù)據(jù)都是2個(gè)字節(jié)的翔曲,也就是以字為單位的经备。
push 寄存器 // 將一個(gè)寄存器中的數(shù)據(jù)入棧
pop 寄存器 //用一個(gè)寄存器接收出棧的數(shù)據(jù)
push 段寄存器 // 將一個(gè)段寄存器中的數(shù)據(jù)入棧
pop 段寄存器 //用一個(gè)段寄存器接收出棧的數(shù)據(jù)
push 內(nèi)存單元 // 將一個(gè)內(nèi)存單元處的字(也就是開始的兩個(gè)內(nèi)存單元)入棧
pop 內(nèi)存單元 //用一個(gè)內(nèi)存單元接收出棧的數(shù)據(jù)
舉個(gè)例子??:
mov ax,1000H
mov dx部默,ax //dx = 1000H
push [0] //將1000:0處的字壓入棧中
pop [2] //出棧的數(shù)據(jù)送入1000:2處
段的總結(jié)
我們可以用一個(gè)段存放數(shù)據(jù)侵蒙,將它定義為“數(shù)據(jù)段”;
我們可以用一個(gè)段存放代碼傅蹂,將它定義為“代碼段”纷闺;
我們可以用一個(gè)段當(dāng)作棧,將它定義為“棧段”份蝴。
對(duì)于數(shù)據(jù)段犁功,將它的段地址放在DS中,用mov婚夫、add浸卦、sub等訪問內(nèi)存單元的指令時(shí),CPU就將我們定義的數(shù)據(jù)段中的內(nèi)容當(dāng)做數(shù)據(jù)來訪問案糙;
對(duì)于代碼端限嫌,將它的段地址放在CS中,將段中第一條指令的偏移地址放在IP中时捌,這樣CPU就將執(zhí)行我們定義的代碼段中的指令怒医;
對(duì)于棧段,將它的段地址放在SS中奢讨,將棧頂單元的偏移地址放在SP中稚叹,這樣CPU在需要進(jìn)行棧操作的時(shí)候,比如執(zhí)行push拿诸、pop指令等扒袖,就將我們定義的棧段當(dāng)成棧空間來用亩码。
三.完整的匯編程序
完整的匯編程序包含匯編指令和偽指令季率。
匯編指令如mov、add蟀伸、sub等蚀同,有對(duì)應(yīng)的機(jī)器指令,可以被編譯為機(jī)器指令啊掏,最終被CPU執(zhí)行蠢络。偽指令如assume、 segment迟蜜、ends刹孔、end等,沒有對(duì)應(yīng)的機(jī)器指令,由編譯器解析髓霞,最終不被CPU執(zhí)行卦睹。
// 聲明一下code段是cs段、代碼段
assume cs:code
// segment和ends的作用是定義一個(gè)段,code是我們?nèi)〉亩蚊?code segment
mov ax, 1122h
mov bx, 3344h
add ax, bx
// 正常退出程序
mov ax, 4c00h
int 21h
code ends
// 編譯器遇到end時(shí)方库,就結(jié)束對(duì)源程序的編譯
end
使用匯編語言編寫一個(gè)完整的程序结序,步驟大致如下:
編寫源代碼 → 編譯、鏈接 → 調(diào)試纵潦、運(yùn)行
在完整的匯編程序中徐鹤,我們會(huì)看到常見的幾種語法。
- 中斷int
- 循環(huán)loop
- call和ret指令
中斷int
可以通過指令int n產(chǎn)生中斷邀层,n是中斷碼返敬,內(nèi)存中有一張中斷向量表,用來存放中斷碼對(duì)應(yīng)中斷處理程序的入口地址寥院。
CPU在接收到中斷信號(hào)后劲赠,暫停當(dāng)前正在執(zhí)行的程序,跳轉(zhuǎn)到中斷碼對(duì)應(yīng)的中斷向量表地址處秸谢,去執(zhí)行中斷處理程序凛澎。
常見中斷:
- int 10h用于執(zhí)行BIOS中斷
- int 3是“斷點(diǎn)中斷”,用于調(diào)試程序
- int 21h用于執(zhí)行DOS系統(tǒng)功能調(diào)用钮追,AH寄存器存儲(chǔ)功能號(hào)
循環(huán)loop
loop指令和cx配合使用预厌,用于循環(huán)執(zhí)行重復(fù)的操作阿迈,類似于高級(jí)語言中的for元媚、while循環(huán)。
loop指令的執(zhí)行流程苗沧,讓cx的值減一刊棕,判斷cx的值。
mov ax, 2h
mov cx, 5 // 5為循環(huán)次數(shù)
s: add ax, ax // s為標(biāo)號(hào)
loop s // 循環(huán)執(zhí)行標(biāo)號(hào)的程序待逞,即 add ax, ax
call和ret指令
call是將下一條指令的偏移地址入棧后甥角,轉(zhuǎn)到標(biāo)號(hào)處執(zhí)行指令。
call 標(biāo)號(hào)
ret是將棧頂?shù)闹党鰲J队#x值給ip嗤无。
四.棧幀
棧幀就是一個(gè)函數(shù)執(zhí)行的環(huán)境,包括:參數(shù)怜庸、局部變量当犯、返回地址等。
每個(gè)函數(shù)都有自己對(duì)應(yīng)的棧幀割疾,用來保存(或者說保護(hù))自己的數(shù)據(jù)嚎卫。
以下是關(guān)于函數(shù)執(zhí)行過程,棧幀的變化(對(duì)應(yīng)的圖片如下):
- push 參數(shù)
- push 函數(shù)的返回地址
- push bp (保留bp之前的值宏榕,方便以后恢復(fù))
- mov bp, sp (保留sp之前的值拓诸,方便以后恢復(fù))
- sub sp,空間大小 (分配空間給局部變量)
- 保護(hù)可能要用到的寄存器
- 使用CC(int 3)填充局部變量的空間
- --------執(zhí)行業(yè)務(wù)邏輯--------
- 恢復(fù)寄存器之前的值
- mov sp, bp (恢復(fù)sp之前的值)
- pop bp (恢復(fù)bp之前的值)
- ret (將函數(shù)的返回地址出棧侵佃,執(zhí)行下一條指令)
- 恢復(fù)棧平衡 (add sp,參數(shù)所占的空間)