《電子技術(shù)應(yīng)用》
您所在的位置:首頁(yè) > 嵌入式技術(shù) > 解決方案 > 簡(jiǎn)明x86匯編語(yǔ)言教程(六)

簡(jiǎn)明x86匯編語(yǔ)言教程(六)

2017-06-10
關(guān)鍵詞: 匯編

4.0 利用子程序與中斷

已經(jīng)掌握了匯編語(yǔ)言,?沒(méi)錯(cuò),你現(xiàn)在已經(jīng)可以去破譯別人代碼中的秘密,。然而,,我們還有一件重要的東西沒(méi)有提到,那就是自程序和中斷,。這兩件東西是如此的重要,,以至于你的程序幾乎不可能離開(kāi)它們。

4.1 子程序

在高級(jí)語(yǔ)言中我們經(jīng)常要用到子程序,。高級(jí)語(yǔ)言中,,子程序是如此的神奇,我們能夠定義和主程序,,或其他子程序一樣的變量名,,而訪問(wèn)不同的變量,并且,,還不和程序的其他部分相沖突,。

然而遺憾的是,這種“優(yōu)勢(shì)”在匯編語(yǔ)言中是不存在的,。

匯編語(yǔ)言并不注重如何減輕程序員的負(fù)擔(dān),;相反,匯編語(yǔ)言依賴(lài)程序員的良好設(shè)計(jì),,以期發(fā)揮CPU的最佳性能,。匯編語(yǔ)言不是結(jié)構(gòu)化的語(yǔ)言,,因此,,它不提供直接的“局部變量”,。如果需要“局部變量”,,只能通過(guò)堆或棧自行實(shí)現(xiàn)。

從這個(gè)意義上講,,匯編語(yǔ)言的子程序更像GWBASIC中的GOSUB調(diào)用的那些“子程序”,。所有的“變量”(本質(zhì)上,屬于進(jìn)程的內(nèi)存和寄存器)為整個(gè)程序所共享,,高級(jí)語(yǔ)言編譯器所做的,,將局部變量放到堆或棧中的操作,只能自行實(shí)現(xiàn),。

參數(shù)的傳遞是靠寄存器和堆棧來(lái)完成的,。高級(jí)語(yǔ)言中,子程序(函數(shù),、過(guò)程,,或類(lèi)似概念的東西)依賴(lài)于堆和棧來(lái)傳遞。

讓我們來(lái)簡(jiǎn)單地分析一下一般高級(jí)語(yǔ)言的子程序的執(zhí)行過(guò)程,。無(wú)論C,、C++、BASIC,、Pascal,,這一部分基本都是一致的。

調(diào)用者將子程序執(zhí)行完成時(shí)應(yīng)返回的地址,、參數(shù)壓入堆棧 子程序使用BP指針+偏移量對(duì)棧中的參數(shù)尋址,,并取出、完成操作 子程序使用RET或RETF指令返回,。此時(shí),,CPU將IP置為堆棧中保存的地址,并繼續(xù)予以執(zhí)行

毋庸置疑,,堆棧在整個(gè)過(guò)程中發(fā)揮著非常重要的作用,。不過(guò),,本質(zhì)上對(duì)子程序最重要的還是返回地址,。如果子程序不知道這個(gè)地址,那么系統(tǒng)將會(huì)崩潰,。

調(diào)用子程序的指令是CALL,,對(duì)應(yīng)的返回指令是RET。此外,,還有一組指令,,即ENTER和LEAVE,它們可以幫助進(jìn)行堆棧的維護(hù),。

CALL指令的參數(shù)是被調(diào)用子程序的地址,。使用宏匯編的時(shí)候,,這通常是一個(gè)標(biāo)號(hào)。CALL和RET,,以及ENTER和LEAVE配對(duì),,可以實(shí)現(xiàn)對(duì)于堆棧的自動(dòng)操作,而不需要程序員進(jìn)行PUSH/POP,,以及跳轉(zhuǎn)的操作,,從而提高了效率。

作為一個(gè)編譯器的實(shí)現(xiàn)實(shí)例,,我用Visual C++編譯了一段C++程序代碼,,這段匯編代碼是使用特定的編譯選項(xiàng)得到的結(jié)果,正常的RELEASE代碼會(huì)比它精簡(jiǎn)得多,。包含源代碼的部分反匯編結(jié)果如下(取自Visual C++調(diào)試器的運(yùn)行結(jié)果,,我刪除了10條int 3指令,并加上了一些注釋?zhuān)酥?,沒(méi)有做任何修改):

1: int myTransform(int nInput){
00401000 push ebp          ; 保護(hù)現(xiàn)場(chǎng)原先的EBP指針
00401001 mov ebp,esp
2: return (nInput*2 + 3) % 7;
00401003 mov eax,dword ptr [nInput] ; 取參數(shù)
00401006 lea eax,[eax+eax+3]    ; LEA比ADD加法更快
0040100A cdq            ; DWORD->QWORD(擴(kuò)展字長(zhǎng))
0040100B mov ecx,7         ; 除數(shù)
00401010 idiv eax,ecx        ; 除
00401012 mov eax,edx        ; 商->eax(eax中保存返回值)
3: }
00401014 pop ebp          ; 恢復(fù)現(xiàn)場(chǎng)的ebp指針
00401015 ret            ; 返回
; 此處刪除10條int 3指令,,它們是方便調(diào)試用的,并不影響程序行為,。
4:
5: int main(int argc, char* argv[])
6: {
00401020 push ebp          ; 保護(hù)現(xiàn)場(chǎng)原先的EBP指針
00401021 mov ebp,esp
00401023 sub esp,10h        ; 為取argc, argv修正堆棧指針,。
7: int a[3];
8: for(register int i=0; i<3; i++){
00401026 mov dword ptr [i],0    ; 0->i
0040102D jmp main+18h (00401038)  ; 判斷循環(huán)條件
0040102F mov eax,dword ptr [i]   ; i->eax
00401032 add eax,1         ; eax ++
00401035 mov dword ptr [i],eax   ; eax->i
00401038 cmp dword ptr [i],3    ; 循環(huán)條件: i與3比較
0040103C jge main+33h (00401053)  ; 如果不符合條件,則應(yīng)結(jié)束循環(huán)
9: a[i] = myTransform(i);
0040103E mov ecx,dword ptr [i]   ; i->ecx
00401041 push ecx          ; ecx (i) -> 堆棧
00401042 call myTransform (00401000); 調(diào)用myTransform
00401047 add esp,4         ; esp+=4: 在堆中的新單元
                  ; 準(zhǔn)備存放返回結(jié)果
0040104A mov edx,dword ptr [i]   ; i->edx
0040104D mov dword ptr a[edx*4],eax ; 將eax(myTransform返回值)
                  ; 放回a[i]
10: }
00401051 jmp main+0Fh (0040102f)  ; 計(jì)算i++,,并繼續(xù)循環(huán)
11: return 0;
00401053 xor eax,eax        ; 返回值應(yīng)該是0
12: }
00401055 mov esp,ebp        ; 恢復(fù)堆棧指針
00401057 pop ebp          ; 恢復(fù)BP
00401058 ret            ; 返回調(diào)用者(C++運(yùn)行環(huán)境)

上述代碼確實(shí)做了一些無(wú)用功,,當(dāng)然,這是因?yàn)榫幾g器沒(méi)有對(duì)這段代碼進(jìn)行優(yōu)化,。讓我們來(lái)關(guān)注一下這段代碼中,,是如何調(diào)用子程序的。不考慮myTransform這個(gè)函數(shù)實(shí)際進(jìn)行的數(shù)值運(yùn)算,,最讓我感興趣的是這一行代碼:

00401003 mov eax,dword ptr [nInput] ; 取參數(shù)

這里nInput是一個(gè)簡(jiǎn)簡(jiǎn)單單的變量符號(hào)嗎,?Visual C++的調(diào)試器顯然不能告訴我們答案——它的設(shè)計(jì)目標(biāo)是為了方便程序調(diào)試,而不是向你揭示編譯器生成的代碼的實(shí)際構(gòu)造,。我用另外一個(gè)反匯編器得到的結(jié)果是:

00401003 mov eax,dword ptr [ebp+8]  ; 取參數(shù)

這和我們?cè)趍ain()中看到的壓棧順序是完全吻合的(注意,,程序運(yùn)行到這個(gè)地方的時(shí)候,EBP=ESP),。main()最終將i的值通過(guò)堆棧傳遞給了myTransform(),。

剖析上面的程序只是說(shuō)明了我前面所提到的子程序的一部分用法。對(duì)于匯編語(yǔ)言來(lái)說(shuō),,完全沒(méi)有必要拘泥于結(jié)構(gòu)化程序設(shè)計(jì)的框架(在今天,,使用匯編的主要目的在于提高執(zhí)行效率,而不是方便程序的維護(hù)和調(diào)試,,因?yàn)閰R編不可能在這一點(diǎn)上做得比C++更好),??紤]下面的程序:

void myTransform1(int nCount, char* sBytes){
 for(register int i=1; i<nCount; i++)
  sBytes[i] += sBytes[i-1];
 for(i=0; i<nCount; i++)
  sBytes[i] <<= 1;
}
void myTransform2(int nCount, char* sBytes){
 for(register int i=0; i<nCount; i++)
  sBytes[i] <<= 1;
}

很容易看出,這兩個(gè)函數(shù)包含了公共部分,,即

for(i=0; i<nCount; i++)
  sBytes[i] <<= 1;

目前,,還沒(méi)有編譯器能夠做到將這兩部分合并。依然沿用剛才的編譯選項(xiàng),,得到的反匯編結(jié)果是(同樣地刪除了int 3):

1: void myTransform1(int nCount, char* sBytes){
00401000 push ebp
00401001 mov ebp,esp
00401003 push ecx
2: for(register int i=1; i<nCount; i++)
00401004 mov dword ptr [i],1
0040100B jmp myTransform1+16h (00401016)
0040100D mov eax,dword ptr [i]
00401010 add eax,1
00401013 mov dword ptr [i],eax
00401016 mov ecx,dword ptr [i]
00401019 cmp ecx,dword ptr [nCount]
0040101C jge myTransform1+3Dh (0040103d)
3: sBytes[i] += sBytes[i-1];
0040101E mov edx,dword ptr [sBytes]
00401021 add edx,dword ptr [i]
00401024 movsx eax,byte ptr [edx-1]
00401028 mov ecx,dword ptr [sBytes]
0040102B add ecx,dword ptr [i]
0040102E movsx edx,byte ptr [ecx]
00401031 add edx,eax
00401033 mov eax,dword ptr [sBytes]
00401036 add eax,dword ptr [i]
00401039 mov byte ptr [eax],dl
0040103B jmp myTransform1+0Dh (0040100d)
4: for(i=0; i<nCount; i++)
0040103D mov dword ptr [i],0
00401044 jmp myTransform1+4Fh (0040104f)
00401046 mov ecx,dword ptr [i]
00401049 add ecx,1
0040104C mov dword ptr [i],ecx
0040104F mov edx,dword ptr [i]
00401052 cmp edx,dword ptr [nCount]
00401055 jge myTransform1+6Bh (0040106b)
5: sBytes[i] <<= 1;
00401057 mov eax,dword ptr [sBytes]
0040105A add eax,dword ptr [i]
0040105D mov cl,byte ptr [eax]
0040105F shl cl,1
00401061 mov edx,dword ptr [sBytes]
00401064 add edx,dword ptr [i]
00401067 mov byte ptr [edx],cl
00401069 jmp myTransform1+46h (00401046)
6: }
0040106B mov esp,ebp
0040106D pop ebp
0040106E ret
7:
8: void myTransform2(int nCount, char* sBytes){
00401070 push ebp
00401071 mov ebp,esp
00401073 push ecx
9: for(register int i=0; i<nCount; i++)
00401074 mov dword ptr [i],0
0040107B jmp myTransform2+16h (00401086)
0040107D mov eax,dword ptr [i]
00401080 add eax,1
00401083 mov dword ptr [i],eax
00401086 mov ecx,dword ptr [i]
00401089 cmp ecx,dword ptr [nCount]
0040108C jge myTransform2+32h (004010a2)
10: sBytes[i] <<= 1;
0040108E mov edx,dword ptr [sBytes]
00401091 add edx,dword ptr [i]
00401094 mov al,byte ptr [edx]
00401096 shl al,1
00401098 mov ecx,dword ptr [sBytes]
0040109B add ecx,dword ptr [i]
0040109E mov byte ptr [ecx],al
004010A0 jmp myTransform2+0Dh (0040107d)
11: }
004010A2 mov esp,ebp
004010A4 pop ebp
004010A5 ret
12:
13: int main(int argc, char* argv[])
14: {
004010B0 push ebp
004010B1 mov ebp,esp
004010B3 sub esp,0CCh
15: char a[200];
16: for(register int i=0; i<200; i++)a[i]=i;
004010B9 mov dword ptr [i],0
004010C3 jmp main+24h (004010d4)
004010C5 mov eax,dword ptr [i]
004010CB add eax,1
004010CE mov dword ptr [i],eax
004010D4 cmp dword ptr [i],0C8h
004010DE jge main+45h (004010f5)
004010E0 mov ecx,dword ptr [i]
004010E6 mov dl,byte ptr [i]
004010EC mov byte ptr a[ecx],dl
004010F3 jmp main+15h (004010c5)
17: myTransform1(200, a);
004010F5 lea eax,[a]
004010FB push eax
004010FC push 0C8h
00401101 call myTransform1 (00401000)
00401106 add esp,8
18: myTransform2(200, a);
00401109 lea ecx,[a]
0040110F push ecx
00401110 push 0C8h
00401115 call myTransform2 (00401070)
0040111A add esp,8
19: return 0;
0040111D xor eax,eax
20: }
0040111F mov esp,ebp
00401121 pop ebp
00401122 ret

非常明顯地,,0040103d-0040106e和00401074-004010a5這兩段代碼存在少量的差別,但很顯然只是對(duì)寄存器的偏好不同(編譯器在優(yōu)化時(shí),,這可能會(huì)減少堆棧操作,,從而提高性能,但在這里只是使用了不同的寄存器而已)

對(duì)代碼進(jìn)行合并的好處是非常明顯的,。新的操作系統(tǒng)往往使用頁(yè)式內(nèi)存管理,。當(dāng)內(nèi)存不足時(shí),程序往往會(huì)頻繁引發(fā)頁(yè)面失效(Page faults),,從而引發(fā)操作系統(tǒng)從磁盤(pán)中讀取一些東西,。磁盤(pán)的速度趕不上內(nèi)存的速度,因此,,這一行為將導(dǎo)致性能的下降,。通過(guò)合并一部分代碼,可以減少程序的大小,,這意味著減少頁(yè)面失效的可能性,,從而軟件的性能會(huì)有所提高?/p>

當(dāng)然,這樣做的代價(jià)也不算低——你的程序?qū)⒆兊秒y懂,,并且難于維護(hù),。因此,再進(jìn)行這樣的優(yōu)化之前,,一定要注意:

優(yōu)化前的程序必須是正確的,。如果你不能確保這一點(diǎn),那么這種優(yōu)化必將給你的調(diào)試帶來(lái)極大的麻煩,。 優(yōu)化前的程序?qū)崿F(xiàn)最好是最優(yōu)的,。仔細(xì)檢查你的設(shè)計(jì),看看是否已經(jīng)使用了最合適(即,,對(duì)于此程序而言最優(yōu))的算法,,并且已經(jīng)在高級(jí)語(yǔ)言許可的范圍內(nèi)進(jìn)行了最好的實(shí)現(xiàn)。 優(yōu)化最好能夠非常有效地減少程序大小(例如,,如果只是減少十幾個(gè)字節(jié),恐怕就沒(méi)什么必要了),,或非常有效地提高程序的運(yùn)行速度(如果代碼只是運(yùn)行一次,,并且只是節(jié)省幾個(gè)時(shí)鐘周期,,那么在多數(shù)場(chǎng)合都沒(méi)有意義)。否則,,這種優(yōu)化將得不償失,。4.2 中斷

中斷應(yīng)該說(shuō)是一個(gè)陳舊的話(huà)題。在新的系統(tǒng)中,,它的作用正在逐漸被削弱,,而變成操作系統(tǒng)專(zhuān)用的東西。并不是所有的計(jì)算機(jī)系統(tǒng)都提供中斷,,然而在x86系統(tǒng)中,,它的作用是不可替代的。

中斷實(shí)際上是一類(lèi)特殊的子程序,。它通常由系統(tǒng)調(diào)用,,以響應(yīng)突發(fā)事件。

例如,,進(jìn)行磁盤(pán)操作時(shí),,為了提高性能,可能會(huì)使用DMA方式進(jìn)行操作,。CPU向DMA控制器發(fā)出指令,,要求外設(shè)和內(nèi)存直接交換數(shù)據(jù),而不通過(guò)CPU,。然后,,CPU轉(zhuǎn)去進(jìn)行起他的操作;當(dāng)數(shù)據(jù)交換結(jié)束時(shí),,CPU可能需要進(jìn)行一些后續(xù)操作,,但此時(shí)它如何才能知道DMA已經(jīng)完成了操作呢?

很顯然不是依靠CPU去查詢(xún)狀態(tài)——這樣DMA的優(yōu)勢(shì)就不明顯了,。為了盡可能地利用DMA的優(yōu)勢(shì),,在完成DMA操作的時(shí)候,DMA會(huì)告訴CPU“這事兒我辦完了”,,然后CPU會(huì)根據(jù)需要進(jìn)行處理,。

這種處理可能很復(fù)雜,需要若干條指令來(lái)完成,。子程序是一個(gè)不錯(cuò)的主意,,不過(guò),CALL指令需要指定地址,,讓外設(shè)強(qiáng)迫CPU執(zhí)行一條CALL指令也違背了CPU作為核心控制單元的設(shè)計(jì)初衷,。考慮到這些,,在x86系統(tǒng)中引入了中斷向量的概念,。

中斷向量表是保存在系統(tǒng)數(shù)據(jù)區(qū)(實(shí)模式下,,是0:0開(kāi)始的一段區(qū)域)的一組指針。這組指針指向每一個(gè)中斷服務(wù)程序的地址,。整個(gè)中斷向量表的結(jié)構(gòu)是一個(gè)線性表,。

每一個(gè)中斷服務(wù)有自己的唯一的編號(hào),我們通常稱(chēng)之為中斷號(hào),。每一個(gè)中斷號(hào)對(duì)應(yīng)中斷向量表中的一項(xiàng),,也就是一個(gè)中斷向量。外設(shè)向CPU發(fā)出中斷請(qǐng)求,,而CPU自己將根據(jù)當(dāng)前的程序狀態(tài)決定是否中斷當(dāng)前程序并調(diào)用相應(yīng)的中斷服務(wù),。

不難根據(jù)造成中斷的原因?qū)⒅袛喾譃閮深?lèi):硬件中斷和軟件中斷。硬件中斷有很多分類(lèi)方法,,如根據(jù)是否可以屏蔽分類(lèi),、根據(jù)優(yōu)先級(jí)高低分類(lèi),等等,??紤]到這些分類(lèi)并不一定科學(xué),并且對(duì)于我們介紹中斷的使用沒(méi)有太大的幫助,,因此我并不打算太詳細(xì)地介紹它(在本教程的高級(jí)篇中,,關(guān)于加密解密的部分會(huì)提到某些硬件中斷的利用,但那是后話(huà)),。

在設(shè)計(jì)操作系統(tǒng)時(shí),,中斷向量的概念曾經(jīng)帶來(lái)過(guò)很大的便利。操作系統(tǒng)隨時(shí)可能升級(jí),,這樣,,通過(guò)CALL來(lái)調(diào)用操作系統(tǒng)的服務(wù)(如果說(shuō)每個(gè)程序都包含對(duì)于文件系統(tǒng)、進(jìn)程表這些應(yīng)該由操作系統(tǒng)管理的數(shù)據(jù)的直接操作的話(huà),,不僅會(huì)造成程序的臃腫,,而且不利于系統(tǒng)的安全)就顯得不太合適了——沒(méi)人能知道,以后的操作系統(tǒng)的服務(wù)程序入口點(diǎn)會(huì)不會(huì)是那兒,。軟件中斷的存在為解決這個(gè)問(wèn)題提供了方便,。

對(duì)于一臺(tái)包含了BIOS的計(jì)算機(jī)來(lái)說(shuō),啟動(dòng)的時(shí)候系統(tǒng)已經(jīng)提供了一部分服務(wù),,例如顯示服務(wù),。無(wú)論你的BIOS、顯示卡有多么的“個(gè)性”,,只要他們和IBM PC兼容,,那么此時(shí)你肯定可以通過(guò)調(diào)用16(10h)號(hào)中斷來(lái)使用顯示服務(wù)。調(diào)用中斷的指令是


int 中斷號(hào)
 

這將引發(fā)CPU去調(diào)用一個(gè)中斷。CPU將保存當(dāng)前的程序狀態(tài)字,,清除Trap和Interrupt兩個(gè)標(biāo)志,,將即將執(zhí)行的指令地址壓入堆棧,,并調(diào)用中斷服務(wù)(根據(jù)中斷向量表),。

編寫(xiě)中斷服務(wù)程序不是一件容易的事情。很多時(shí)候,,中斷服務(wù)程序必須寫(xiě)成可重入代碼(或純代碼,,pure code)。所謂可重入代碼是指,,程序的運(yùn)行過(guò)程中可以被打斷,,并由開(kāi)始處再次執(zhí)行,并且在合理的范圍內(nèi)(多次重入,,而不造成堆棧溢出等其他問(wèn)題),,程序可以在被打斷處繼續(xù)執(zhí)行,并且執(zhí)行結(jié)果不受影響,。

由于在多線程環(huán)境中等其他一些地方進(jìn)行程序設(shè)計(jì)時(shí)也需要考慮這個(gè)因素,,因此這里著重講一下可重入代碼的編寫(xiě)。

可重入代碼最主要的要求就是,,程序不應(yīng)使用某個(gè)指定的內(nèi)存地址的內(nèi)存(對(duì)于高級(jí)語(yǔ)言來(lái)說(shuō),,這通常是全局變量,或?qū)ο蟮某蓡T),。如果可能的話(huà),,應(yīng)使用寄存器,或其他方式來(lái)解決,。如果不能做到這一點(diǎn),,則必須在開(kāi)始、結(jié)束的時(shí)候分別禁止和啟用中斷,,并且,,運(yùn)行時(shí)間不能太長(zhǎng)。

下面用C語(yǔ)言分別舉一個(gè)可重入函數(shù),,和兩個(gè)非可重入函數(shù)的例子(注. 這些例子應(yīng)該是在某本多線程或操作系統(tǒng)的書(shū)上看到的,,遺憾的是我想不起來(lái)是哪本書(shū)了,在這里先感謝那位作者提供的范例):

可重入函數(shù):

void strcpy(char* lpszDest, char* lpszSrc){
 while(*dest++=*src++);
 *dest=0;
}

非可重入函數(shù)

char cTemp;                  // 全局變量
void SwapChar(char* lpcX, char* lpcY){
 cTemp = *lpcX; *lpcX = *lpcY; lpcY = cTemp; // 引用了全局變量,,在分享內(nèi)存的多個(gè)線程中可能造成問(wèn)題
}

非可重入函數(shù)

void SwapChar2(char* lpcX, char* lpcY){
 static char cTemp;              // 靜態(tài)變量
 cTemp = *lpcX; *lpcX = *lpcY; lpcY = cTemp; // 引用了靜態(tài)變量,,在分享內(nèi)存的多個(gè)線程中可能造成問(wèn)題
}

中斷利用的是系統(tǒng)的棧。棧操作是可重入的(因?yàn)闂,?梢员WC“先進(jìn)后出”),,因此,我們并不需要考慮棧操作的重入問(wèn)題。使用宏匯編器寫(xiě)出可重入的匯編代碼需要注意一些問(wèn)題,。簡(jiǎn)單地說(shuō),,干脆不要用標(biāo)號(hào)作為變量是一個(gè)不錯(cuò)的主意。

使用高級(jí)語(yǔ)言編寫(xiě)可重入程序相對(duì)來(lái)講輕松一些,。把持住不訪問(wèn)那些全局(或當(dāng)前對(duì)象的)變量,,不使用靜態(tài)局部變量,堅(jiān)持只適用局部變量,,寫(xiě)出的程序就將是可重入的,。

書(shū)歸正傳,調(diào)用軟件中斷時(shí),,通常都是通過(guò)寄存器傳進(jìn),、傳出參數(shù)。這意味著你的int指令周?chē)苍S會(huì)存在一些“幫手”,,比如下面的代碼:

mov ax, 4c00h
int 21h

就是通過(guò)調(diào)用DOS中斷服務(wù)返回父進(jìn)程,,并帶回錯(cuò)誤反饋碼0。其中,,ax中的數(shù)據(jù)4c00h就是傳遞給DOS中斷服務(wù)的參數(shù),。

到這里,x86匯編語(yǔ)言的基礎(chǔ)部分就基本上講完了,,《簡(jiǎn)明x86匯編語(yǔ)言教程》的初級(jí)篇——匯編語(yǔ)言基礎(chǔ)也就到此告一段落,。當(dāng)然,目前為止,,我只是蜻蜓點(diǎn)水一般提到了一些學(xué)習(xí)x86匯編語(yǔ)言中我認(rèn)為需要注意的重要概念,。許多東西,包括全部匯編語(yǔ)句的時(shí)序特性(指令執(zhí)行周期數(shù),,以及指令周期中各個(gè)階段的節(jié)拍數(shù)等),、功能、參數(shù)等等,,限于個(gè)人水平和篇幅我都沒(méi)有作詳細(xì)介紹,。如果您對(duì)這些內(nèi)容感興趣,請(qǐng)參考Intel和AMD兩大CPU供應(yīng)商網(wǎng)站上提供的開(kāi)發(fā)人員參考,。

在以后的簡(jiǎn)明x86匯編語(yǔ)言教程中級(jí)篇和高級(jí)篇中,,我將著重介紹匯編語(yǔ)言的調(diào)試技術(shù)、優(yōu)化,,以及一些具體的應(yīng)用技巧,,包括反跟蹤、反反跟蹤,、加密解密,、病毒與反病毒等等,。


本站內(nèi)容除特別聲明的原創(chuàng)文章之外,轉(zhuǎn)載內(nèi)容只為傳遞更多信息,,并不代表本網(wǎng)站贊同其觀點(diǎn),。轉(zhuǎn)載的所有的文章、圖片,、音/視頻文件等資料的版權(quán)歸版權(quán)所有權(quán)人所有,。本站采用的非本站原創(chuàng)文章及圖片等內(nèi)容無(wú)法一一聯(lián)系確認(rèn)版權(quán)者。如涉及作品內(nèi)容,、版權(quán)和其它問(wèn)題,,請(qǐng)及時(shí)通過(guò)電子郵件或電話(huà)通知我們,,以便迅速采取適當(dāng)措施,,避免給雙方造成不必要的經(jīng)濟(jì)損失。聯(lián)系電話(huà):010-82306118,;郵箱:[email protected],。