關(guān)于8086CPU中的寄存器的介紹_第1頁
關(guān)于8086CPU中的寄存器的介紹_第2頁
關(guān)于8086CPU中的寄存器的介紹_第3頁
關(guān)于8086CPU中的寄存器的介紹_第4頁
關(guān)于8086CPU中的寄存器的介紹_第5頁
已閱讀5頁,還剩80頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

引子打算寫幾篇稍近底層或者說是基礎(chǔ)的博文,淺要介紹或者說是回顧一些基礎(chǔ)知識,自然,還是得從最基礎(chǔ)的開始,那就從匯編語言開刀吧,從匯編語言開刀的話,我們必須還先要了解一些其他東西,像

CPU,內(nèi)存這些知識點還是理解深刻一點的比較好,所以這一篇博文就繞著80x86

CPU中寄存器的基礎(chǔ)部分下手,至于其他的一些將會在后續(xù)的博文中介紹。同時在這里說明一下,本篇博文介紹的算是比較詳細(xì)的了,而且介紹的知識點也是比較多的,所以造成博文長度過長,如果有興趣想了解這一塊的話,還請自行斟酌好閱讀比例,建議分3次以上閱覽。讀者定位本博文主要將介紹的是

8086CPU中的寄存器,既然是8086CPU寄存器簡介的話,自然,面向的是初級一些的讀者,其中不會涉及太多難點,同時,所有的介紹,我也會盡可能的從基礎(chǔ)開始,然后循序漸進(jìn)的介紹,同時也會盡量的將知識點介紹詳細(xì),介紹的過程中也會涉及到一些匯編程序代碼,當(dāng)然,采用的是最簡單的方式介紹而已,本篇博文也就是回顧一些基礎(chǔ)知識,讀者主要定位于想對8086CPU有所了解,希望對整個程序設(shè)計的底層有所了解的朋友,而且讀者最好是擁有一定的計算機基礎(chǔ)和匯編語言基礎(chǔ)。

開頭首先淺要介紹一下

Intel

CPU的發(fā)展史吧:IntelCPU系列,最初是4位微處理器4004,然后到到8位微處理器的8008,再到8微微處理器8080,以及稍后的16位微處理器8086,由8086開始,Intel進(jìn)入現(xiàn)在所謂的

x86

時代。Intel

8086為16位

CPU,而因為在8086之前的CPU都是8位CPU,這樣也就造成了很多的外設(shè)也只支持8位,因此

Intel

緊接著就退出了8位的8088CPU,因此

Intel8088也就可以看做是8086的8位版本;如果是但從匯編語言的角度上來說,8086和8088是沒有區(qū)別的,即8086上跑的程序可以不加修改的移植到8088,8088上跑的程序也可以不加修改的移植到8086上,當(dāng)然,還是有些特殊的地方是不同的,而這些基本上在這里可以忽略掉,在8088

CPU之后,Intel

又推出了

80186,80286,這兩款CPU均是16位

CPU,而對于80186來說,其與8086的區(qū)別可以簡單的看做是80186多了幾條指令而已,而80286則不同,80286的地址總線數(shù)目有了變化,在8086,8088,80186上,CPU的地址總線都是20根,即可最大尋址220

即達(dá)到1MB的尋址能力,而對于80286CPU來說,其地址總線數(shù)目達(dá)到了24根,從而最大尋址能力為224

即16MB,由于支持更多的物理內(nèi)存尋址,因此80286便開始成為了多任務(wù),多用戶系統(tǒng)的核心。而后來,Intel

又推出了80386,80386為32位微處理器,Intel80x86家族的32位微處理器始于80386;同時80386也完全兼容先前的8086/8088,80186,80286,并且80386全面支持32位數(shù)據(jù)類型和32位操作,并且80386的數(shù)據(jù)總線根數(shù)和地址總線根數(shù)均達(dá)到了32根,從而可以最大物理尋址為232

即4GB。而之后的80486也是32位微處理器,而后又出來了Pentium和PentiumPro等等第五代微處理器,這些處理器雖然也是32位微處理器,但是他們的數(shù)據(jù)總線和地址總線都有所擴(kuò)展,比如Pentium的數(shù)據(jù)總線達(dá)到64位,而PentiumPro的地址總線位數(shù)達(dá)到了36位。

好,關(guān)于IntelCPU的介紹就到這里了,下面就要開始回歸中心,看CPU中的寄存器了,首先,從學(xué)習(xí)的角度來說,從8086/8088

CPU下手是不錯的選擇,而我這里選擇的也是8086CPU而已,說實在的,像80386CPU我也還沒有研究過,像奔騰這些,呵呵,扯更遠(yuǎn)了,說到底也就只能拿8086出來曬曬而已,當(dāng)然,從8086開始也是學(xué)習(xí)的最佳路徑。

說了這么久,到底寄存器是什么呢?其實很簡單,寄存器就是個存儲信息的單元或者說是器件又或者說是容器而已,就比如內(nèi)存也是一個存儲介質(zhì)或者說是存儲單元而已,其實寄存器從理解上來說和內(nèi)存差不多,只不過寄存器(這里討論的寄存器都是CPU中的寄存器,不包括外設(shè)上的寄存器)位于

CPU

內(nèi)部,而內(nèi)存位于CPU外部,而且,寄存器比內(nèi)存可是珍貴得多啊,就拿內(nèi)存和硬盤來比,肯定是內(nèi)存在使用上珍貴得多,是PC中的稀有資源,而寄存器是CPU中的稀有資源,內(nèi)存和寄存器相比就像硬盤和內(nèi)存相比一樣。而對于一個匯編程序員來說,CPU中主要可以使用的也就是寄存器而已,匯編程序員可以使用指令來讀寫CPU中的寄存器,從而可以實現(xiàn)對于CPU的控制,當(dāng)然,不同的CPU,寄存器的個數(shù)和結(jié)構(gòu)都是不一樣的,比如8086CPU中,寄存器的個數(shù)也就14個而已,并且8086CPU中所有的寄存器的結(jié)構(gòu)為16位,即一個寄存器中可以存放下2B即2個字節(jié),而到了80386CPU中,寄存器的個數(shù)也比8086增多了,比如在80386中添加了系統(tǒng)地址寄存器等寄存器,同時寄存器的結(jié)構(gòu)也變了,比如在80386中絕大多數(shù)的寄存器為32位,而有些寄存器則是16位。8086

CPU中寄存器總共為14個,且均為16位。即

AX,BX,CX,DX,SP,BP,SI,DI,IP,F(xiàn)LAG,CS,DS,SS,ES

共14個。而這14個寄存器按照一定方式又分為了通用寄存器,控制寄存器和段寄存器。通用寄存器:AX,BX,CX,DX稱作為數(shù)據(jù)寄存器:AX(Accumulator):累加寄存器,也稱之為累加器;BX(Base):基地址寄存器;CX(Count):計數(shù)器寄存器;DX(Data):數(shù)據(jù)寄存器;SP和BP又稱作為指針寄存器:SP(StackPointer):堆棧指針寄存器;BP(BasePointer):基指針寄存器;SI和DI又稱作為變址寄存器:SI(SourceIndex):源變址寄存器;DI(DestinationIndex):目的變址寄存器;控制寄存器:IP(InstructionPointer):指令指針寄存器;FLAG:標(biāo)志寄存器;段寄存器:CS(CodeSegment):代碼段寄存器;DS(DataSegment):數(shù)據(jù)段寄存器;SS(StackSegment):堆棧段寄存器;ES(ExtraSegment):附加段寄存器;

通用寄存器從上面可以知道,在8086CPU中,通用寄存器有8個,分別是AX,BX,CX,DX,SP,BP,SI,DI,至于為什么給它們?nèi)∶鐾ㄓ眉拇嫫鳎鞘且驗椋@些個寄存器每一個都有自己專門的用途,比如CX作為計數(shù)寄存器,則是在使用LOOP指令循環(huán)時用來指定循環(huán)次數(shù)的寄存器,如果它們每一個都只有一個專用的作用,那就它們只能稱之為專用寄存器了,正是因為這些個寄存器還可以用來傳送數(shù)據(jù)和暫存數(shù)據(jù),所以才稱它們?yōu)橥ㄓ眉拇嫫鳌O旅婢桶错樞騺硪灰唤榻B這幾個通用寄存器了:數(shù)據(jù)寄存器(AX,BX,CX,DX):數(shù)據(jù)寄存器有AX,BX,CX,DX四個組成,由于在8086之前的CPU為8位CPU,所以為了兼容以前的8位程序,在8086CPU中,每一個數(shù)據(jù)寄存器都可以當(dāng)做兩個單獨的寄存器來使用,由此,每一個16位寄存器就可以當(dāng)做2個獨立的8位寄存器來使用了。AX寄存器可以分為兩個獨立的8位的AH和AL寄存器;BX寄存器可以分為兩個獨立的8位的BH和BL寄存器;CX寄存器可以分為兩個獨立的8位的CH和CL寄存器;DX寄存器可以分為兩個獨立的8位的DH和DL寄存器;除了上面4個數(shù)據(jù)寄存器以外,其他寄存器均不可以分為兩個獨立的8位寄存器;注意在上面標(biāo)志中的“獨立”二字,這兩個字表明AH和AL作為8位寄存器使用時,可以看做它們是互不相關(guān)的,也就是看做兩個完全沒有聯(lián)系的寄存器X和Y即可,比如指令

MOV

AH,12H,CPU在執(zhí)行時根本就不會知道AL中是什么鬼東西,因為它只認(rèn)識

AH。下面給出一幅16位數(shù)據(jù)寄存器的結(jié)構(gòu)圖:表示16位寄存器AX可以表示成兩個8位寄存器,其中AH表示高位的8位寄存器,AL表示低位的8位寄存器。AX寄存器:如上所說,AX的另外一個名字叫做累加寄存器或者簡稱為累加器,其可以分為2個獨立的8位寄存器AH和AL;在寫匯編程序時,AX寄存器可以說是使用率最高的寄存器(不過,總共才那么14個寄存器,哪一個不經(jīng)常使用咯?),既然AX是數(shù)據(jù)寄存器的話,那么理所當(dāng)然,其可以用來存放普通的數(shù)據(jù),由于其是16位寄存器,自然也就可以存放16位數(shù)據(jù),但是因為其又可以分為2個獨立的8位寄存器AH和AL,所以,在AH和AL中又可以獨立的存放2個8位的數(shù)據(jù),可以有以下代碼(即將AX當(dāng)做普通的寄存器使用,即可以用來暫存數(shù)據(jù)):MOVAX,1234H ;向寄存器AX傳入數(shù)據(jù)1234HMOVAH,56H ;向寄存器AX的高8位寄存器AH中傳入數(shù)據(jù)56HMOVAL,78H ;向寄存器AX的低8位寄存器AL中傳入數(shù)據(jù)78H3條語句的執(zhí)行過程如下:而既然AX又被稱作為累加器,自然其還有一點點特殊的地方的:AX寄存器還具有的特殊用途是在使用DIV和MUL指令時使用,DIV在8086CPU中是除法指令,而在使用除法的時候有兩種情況,即除數(shù)可以是8位或者是16位的,而且除數(shù)可以存放在寄存器中或者是內(nèi)存單元中,而至于被除數(shù)的話,自然,應(yīng)該由AX來代替了,當(dāng)除數(shù)是8位時,被除數(shù)一定會是16位的,并且默認(rèn)是放在AX寄存器中,而當(dāng)除數(shù)是16位時,被除數(shù)一定是32位的,因為AX是16位寄存器,自然,放不下32位的被除數(shù),所以,在這里還需要使用另一個16位寄存器DX,其中DX存放32位的被除數(shù)的高16位,而AX則存放32位的被除數(shù)的低16位,同時,AX的作用還不僅僅是用來保存被除數(shù)的,當(dāng)除法指令執(zhí)行完成以后,如果除數(shù)是8位的,則在AL中會保存此次除法操作的商,而在AH中則會保存此次除法操作的余數(shù),當(dāng)然,如果除數(shù)是16位的話,則AX中會保存本次除法操作的商,而DX則保存本次除法操作的余數(shù)。上面介紹的是AX寄存器在除法操作中的應(yīng)用,下面還需要介紹一下AX在乘法操作中的應(yīng)用,當(dāng)使用MUL做乘法運算時,兩個相乘的數(shù)要么都是8位,要么都是16位,如果兩個相乘的數(shù)都是8位的話,則一個默認(rèn)是放在AL中,而另一個8位的乘數(shù)則位于其他的寄存器或者說是內(nèi)存字節(jié)單元中,而如果兩個相乘的數(shù)都是16位的話,則一個默認(rèn)存放在AX中,另一個16位的則是位于16的寄存器中或者是某個內(nèi)存字單元中。同時,當(dāng)MUL指令執(zhí)行完畢后,如果是8位的乘法運算,則默認(rèn)乘法運算的結(jié)果是保存在AX中,而如果是16位的乘法運算的話,則默認(rèn)乘法運算的結(jié)果有32位,其中,高位默認(rèn)保存在DX中,而低位則默認(rèn)保存在AX中。AX寄存器在DIV

指令中的使用:MOVDX,0H ;設(shè)置32位被除數(shù)的高16位為0HMOVAX,8H ;設(shè)置32位被除數(shù)的低16位為8HMOVBX,2H ;設(shè)置16位除數(shù)為2HDIVBX ;執(zhí)行計算4條語句的執(zhí)行過程如下:AX寄存器在MUL

指令中的使用:MOVAX,800H ;設(shè)置16位乘數(shù)為800HMOVBX,100H ;設(shè)置16位乘數(shù)為100HMOVDX,0H ;清空用來保存乘法結(jié)果的高16位MULBX ;執(zhí)行計算4條語句的執(zhí)行過程如下:

BX寄存器:首先可以明確的是,BX作為數(shù)據(jù)寄存器,表明其是可以暫存一般的數(shù)據(jù)的,即在某種程度上,它和AX可以暫存一般性數(shù)據(jù)的功能是一樣的,其同樣為了適應(yīng)以前的8位CPU,而可以將BX當(dāng)做兩個獨立的8位寄存器使用,即有BH和BL,除了暫存一般性數(shù)據(jù)的功能外,BX作為通用寄存器的一種,BX主要還是用于其專屬功能–尋址(尋址物理內(nèi)存地址)上,BX寄存器中存放的數(shù)據(jù)一般是用來作為偏移地址使用的,何為偏移地址呢?既然是偏移地址的話,當(dāng)然得有一個基地址了,而這個基地址其實就是段地址,這里就涉及到了段寄存器,當(dāng)然,在介紹BX寄存器的時候,我不會去介紹段寄存器,上面提到BX的主要功能是用在尋址上,那么,其是如何尋址的呢?對于尋址這個話題,我會在我的下一篇博文中作出詳細(xì)的介紹,而這里,我只點一下,在8086CPU中,CPU是根據(jù)<段地址:偏移地址>來進(jìn)行尋址操作的,而BX中存放的數(shù)據(jù)表示的是偏移地址的話,自然,便可以通過<段地址:[BX]>的方式來完成尋址操作了。為了介紹BX在尋址當(dāng)中的作用,下面我給出一副示意圖:上面的示意圖表示:可以令BX=2,然后通過DS:[BX]來訪問到內(nèi)存中段地址為DS,且偏移量為2的內(nèi)存單元了。上面介紹的這種尋址方式是BX在尋址中最最簡單的應(yīng)用了,而對于稍微復(fù)雜的尋址方式,還可以依賴于SI,DI,BP等寄存器來一起完成,當(dāng)然,這會是下一篇博文將要介紹的內(nèi)容了。BX

寄存器在尋址中的使用:MOVBX,5HMOVAH,11HMOVAH,[BX] ;設(shè)置AX的值為偏移地址為BX中的值時所代表的內(nèi)存單元3條語句的執(zhí)行過程如下:從上圖可以看出,在偏移地址為5時的內(nèi)存單元中的數(shù)據(jù)位BBH,而從這幅圖上面就可以看出,確實通過[BX]找到了偏移地址為5處的內(nèi)存單元,并且將內(nèi)存單元移入了AH中。

CX寄存器:CX寄存器作為數(shù)據(jù)寄存器的一種呢,其同樣具有和AX,BX一樣的特點,即可以暫存一般性的數(shù)據(jù),同時還可以將其當(dāng)做兩個獨立的8位寄存器使用,即有CH和CL兩個8位寄存器,當(dāng)然,CX也是有其專門的用途的,CX中的C被翻譯為Counting也就是計數(shù)器的功能,當(dāng)在匯編指令中使用循環(huán)LOOP指令時,可以通過CX來指定需要循環(huán)的次數(shù),而CPU在每一次執(zhí)行LOOP指令的時候,都會做兩件事:一件就是令CX=CX–1,即令CX計數(shù)器自動減去1;還有一件就是判斷CX中的值,如果CX中的值為0則會跳出循環(huán),而繼續(xù)執(zhí)行循環(huán)下面的指令,當(dāng)然如果CX中的值不為0,則會繼續(xù)執(zhí)行循環(huán)中所指定的指令。CX

寄存器在循環(huán)中的使用(輸出5個白底藍(lán)字的A):MOVAX,0B800HMOVDS,AX ;使用80x25彩色字符模式,內(nèi)存地址0xB8000-0xBFFFFFMOVBX,0 ;從0xB8000開始MOVCX,5H ;循環(huán)5次MOVDX,41H ;A的16進(jìn)制為41HMOVAX,01110001B ;顯示白底藍(lán)字s:MOV[BX],DX ;顯示ASCII字符ADDBX,1MOV[BX],AX ;設(shè)置字符顯示屬性ADDBX,1LOOPs語句的執(zhí)行過程如下:

DX寄存器:DX寄存器作為數(shù)據(jù)寄存器的一種,同樣具有和AX,BX,CX一樣的特點,即可以暫存一般性的數(shù)據(jù),同時還可以將其當(dāng)做兩個獨立的8位寄存器使用,極有DH和DL,同時,DX作為一個通用寄存器的話,自然其還有其他的用途,而關(guān)于DX在其他方面的用途,其實在前面介紹AX寄存器時便已經(jīng)有所介紹了,即當(dāng)在使用DIV指令進(jìn)行除法運算時,如果除數(shù)為16位時,被除數(shù)將會是32位,而被除數(shù)的高16位就是存放在DX中,而且執(zhí)行完DIV指令后,本次除法運算所產(chǎn)生的余數(shù)將會保存在DX中,同時,在執(zhí)行MUL指令時,如果兩個相乘的數(shù)都是16位的話,那么相乘后產(chǎn)生的結(jié)果顯然需要32位來保存,而這32位的結(jié)果的高16位就是存放在DX寄存器中。DX寄存器在DIV

指令中的使用(即2293812/256=8960

余數(shù)為52):MOVDX,0023H ;32位被除數(shù)的高16位MOVAX,0034H ;32位被除數(shù)的低16位MOVBX,100H ;16的除數(shù)DIVBX語句的執(zhí)行過程如下:

可以看到在語句結(jié)束以后,AX=2300H

即十進(jìn)制的8960,而DX=34H即十進(jìn)制的52和我們的結(jié)果是一致的。DX寄存器在MUL

指令中的使用則各位可以參考在AX中MUL運算的使用,這里就不貼出來了。

指針寄存器(BP,SP):BP寄存器:8086

CPU中的指針寄存器包括兩個,即SP和BP,在這里呢,我先只對BP寄存器做介紹,因為SP寄存器實質(zhì)上必須和SS段寄存器一起使用,所以,我將會把SP寄存器留到后面和SS段寄存器一起作介紹。BP(BasePointer)也就是基指針寄存器,它和其他的幾個用來進(jìn)行尋址操作所使用的寄存器(還有BX,SI,DI)沒有太大的區(qū)別,關(guān)于SI和DI寄存器的下面請見下文。首先,BP寄存器作為通用寄存器的一種,說明其是可以暫存數(shù)據(jù)的,而后,BP又不是數(shù)據(jù)寄存器,也就意味著其不能分割成2個獨立的8位寄存器使用,而后當(dāng)以[…]的方式訪問內(nèi)存單元而且在[…]中使用了寄存器BP的話,那么如果在指令中沒有明確或者說是顯示的給出段地址時,段地址則使用默認(rèn)的SS寄存器中的值(BX,SI,DI會默認(rèn)使用DS段寄存器),比如DS:[BP]則在這里明確給出了段地址位于DS中,所以,這里代表的內(nèi)存單元即是段地址為DS,偏移量為BP寄存器中的值的內(nèi)存單元,而如果單單是使用[BP]的話,則代表的內(nèi)存單元是段地址為SS,偏移量為BP寄存器中的值的內(nèi)存單元。并且BP寄存器主要適用于給出堆棧中數(shù)據(jù)區(qū)的偏移,從而可以方便的實現(xiàn)直接存取堆棧中的數(shù)據(jù),至于堆棧的話,會在后面的博文中介紹。在8086CPU中,只有4個寄存器可以以

[…]

的方式使用,這四個寄存器分別是BX,SI,DI,BP。下面的

Demo

BX

寄存器在尋址中的使用:MOVBP,0MOVAX,[BP];將SS:[BP]代表的內(nèi)存單元移入AX中MOVAX,CS:[BP];將CS:[BP]代表的內(nèi)存單元移入AX中語句的執(zhí)行過程如下:

變址寄存器(SI,DI):首先,變址寄存器和上面介紹的指針寄存器(也就是BP和SP),它們的功能其實都是用于存放某個存儲單元地址的偏移,或者是用于某組存儲單元開始地址的偏移,即作為存儲器指針使用,當(dāng)然,由于變址寄存器和指針寄存器都是屬于通用寄存器,所以它們也可以保存算術(shù)結(jié)果或者說是具有暫存數(shù)據(jù)的功能,但是因為它們不是數(shù)據(jù)寄存器,所以無法分割成2個獨立的8位寄存器使用,關(guān)于變址寄存器和指針寄存器的詳細(xì)使用,筆者將會在下一篇博文中作出最詳細(xì)的介紹,SI(SourceIndex)是源變址寄存器,DI(DestinationIndex)即是目的變址寄存器,8086CPU中的SI寄存器和DI寄存器其實和BX寄存器的功能是差不多的,只不過SI寄存器和DI寄存器均不是數(shù)據(jù)寄存器,所以它們不能夠拆分為2個獨立的8位寄存器,而這也就是SI寄存器和DI寄存器與BX寄存器所不同的地方,既然,SI,DI兩個寄存器的功能和BX差不多,自然,SI和DI中也是可以暫存一般性數(shù)據(jù)的,同時,通過使用SI和DI寄存器也是可以用來完成尋址操作的。比如下面的代碼就是可行的:MOVSI,0 ;初始化偏移地址為0MOVAX,[SI] ;將段地址為DS偏移地址為SI的內(nèi)存單元中的值移入AX中MOVAX,DS:[SI] ;將段地址為DS偏移地址為SI的內(nèi)存單元中的值移入AX中MOVAX,SS:[SI] ;將段地址為SS偏移地址為SI的內(nèi)存單元中的值移入AX中MOVDI,0 ;初始化偏移地址為0MOVAX,[DI] ;將段地址為DS偏移地址為DI的內(nèi)存單元中的值移入AX中MOVAX,DS:[DI] ;將段地址為DS偏移地址為DI的內(nèi)存單元中的值移入AX中MOVAX,SS:[DI] ;將段地址為SS偏移地址為DI的內(nèi)存單元中的值移入AX中

其他寄存器(CS,IP,SS,SP,DS,ES)由于段寄存器總是和其他一些像指針寄存器,變址寄存器,控制寄存器一起使用,所以在這里,我并不會單獨介紹段寄存器,而是將段寄存器和一些其他的常用寄存器搭配介紹。由于下面的介紹中會涉及到很多關(guān)于段和棧的概念,而段和棧的介紹又都必須關(guān)系到物理內(nèi)存,所以在介紹段寄存器以及其他一些呈協(xié)作關(guān)系的寄存器之前,還是先來介紹一下這幾個基本的概念比較好。8086CPU訪問內(nèi)存(物理地址):當(dāng)CPU需要訪問一個內(nèi)存單元時,需要給出內(nèi)存單元的地址,而每一個內(nèi)存單元在物理內(nèi)存空間中都有一個唯一的地址,即可以通過這個地址定位到內(nèi)存單元,而這個地址即為物理地址。CPU通過地址總線將一個內(nèi)存單元的物理地址送入存儲器,而后CPU便可以通過這個物理地址來訪問這個物理地址所指向的內(nèi)存單元了。那么這個物理地址在CPU中是如何形成的呢?首先,我們知道8086CPU的地址總線是20根,即每次都可以傳輸20位的地址,從而尋址能力有220

也就是1MB的大小,但是8086CPU的寄存器只有16位,也就是在8086CPU的內(nèi)部,一次性處理,傳輸,暫存的地址都只能是16位,即8086CPU不能完整的保存下一個物理地址(物理地址為20位),如果單單以最簡單的方式(即直接用16位寄存器來保存物理地址)的話,那么,尋址能力只有216

,也就是64KB,如果真以如此簡單的方式的話,那么地址總線還需要20根干嘛呢?而且,難不成我們以后的內(nèi)存就是64KB了嗎?當(dāng)然不是的,8086CPU在這里采取了一定的措施從而使其尋址能力達(dá)到1MB。8086CPU在內(nèi)部通過兩個16位的地址進(jìn)行合成從而形成一個20位的物理地址,由此,8086CPU的尋址能力便可以達(dá)到1MB。那么8086CPU又是如何將兩個16位的地址合成為一個20位的物理地址的呢?當(dāng)CPU在訪問內(nèi)存時,其會使用一個16位的基地址,然后再使用一個16位的偏移地址,通過將基地址和偏移地址傳入8086

CPU的地址加法器中進(jìn)行合成即可以構(gòu)造出20位的物理地址。至于合成的方式如下:基地址其實是通過一個16位的段地址來形成的,將一個段地址左移4位即形成了基地址,而至于偏移地址的話,自然不必多說,為16位,通過將基地址和偏移地址相加便形成了20位的物理地址。下面給出一幅示意圖來表示物理地址的合成:段:至于段的話,其實在物理內(nèi)存中是沒有段這一概念的,事實上,段的概念來自于

CPU,因為CPU擁有段寄存器,既然在CPU中擁有了段寄存器,自然,在CPU中就肯定有段的概念了,其實段也就是在編程時,我們將若干個地址連續(xù)的內(nèi)存單元看做是一個段,然后通過將一個段地址左移4位形成基地址,再通過這個基地址來定位這個段的起始地址,然后,再通過偏移地址便可以精確定位到段中的內(nèi)存單元了,由于段的起始地址是一個段地址左移4位,所以很明顯,段的起始地址肯定是16的倍數(shù),而且由于一個段內(nèi)部,只能通過偏移地址來定位,而偏移地址為16位,所以一個段的長度也就是216

也就是64KB的大小。在編程時,可以講一段內(nèi)存定義成為一個段,而這里,我們又可以引出數(shù)據(jù)段,代碼段,棧段這三種類型的段。何為數(shù)據(jù)段呢?其實就是我們自個兒定義一段內(nèi)存(當(dāng)然段起始地址肯定是16的倍數(shù),并且段長度<=64KB),然后我們在這個段里頭存放我們所需要使用的數(shù)據(jù),這就是數(shù)據(jù)段;何為代碼段呢?其實也很簡單,也是我們自己在編程的時候定義一段內(nèi)存,然后這段內(nèi)存用來存放我們的代碼(也就是指令),既然是存放的代碼,自然就稱之為代碼段;何為棧段呢?至于棧段的話,有接觸過數(shù)據(jù)結(jié)構(gòu)的朋友應(yīng)該是很清楚棧的,而這里我們也就是在內(nèi)存中分配出一個段,然后將這個段當(dāng)做棧來使用,對于棧的介紹,詳見下文;這里呢,順便還點出幾個關(guān)于段寄存器的內(nèi)容,當(dāng)然下文還會詳細(xì)介紹的,首先,對于任何一個段來說,均有段地址,而這些段地址是存放在段寄存器中(段寄存器的作用也在于此),但是對于不同的段,它們默認(rèn)的段地址存放在不同的段寄存器中,像數(shù)據(jù)段來說,它的段地址存放在

DS(Data

Segment)寄存器中,代碼段的段地址存放在

CS(Code

Segment)寄存器中,棧段的段地址存放在

SS(Stack

Segment)寄存器中。下面給出一幅在段中尋址的示意圖:

上面的示意圖中,通過將段地址左移四位,然后與偏移地址相加便可以得到20位的物理地址了。棧:8086

CPU中提供了對棧的支持,并且其還提供了相應(yīng)的指令來以棧的方式訪問內(nèi)存空間。什么是棧?通過上面在段中的介紹,棧其實就是一個段,再說白一點,也就是一塊內(nèi)存,當(dāng)然,這塊內(nèi)存是一塊連續(xù)的內(nèi)存。既然棧是一個段的話,那么當(dāng)然就可以以使用段的方式來使用棧,當(dāng)然,除了像段一樣的使用棧以外,棧還提供了其特殊的訪問方式(如果和段一模一樣的話,那還需要棧干嗎呢?),眾所周知,棧是先進(jìn)后出類型的數(shù)據(jù)結(jié)構(gòu),在8086

CPU中也是如此,可以通過

”PUSH“

指令將數(shù)據(jù)壓入棧中,然后再通過

”POP“

指令將棧頂?shù)脑厝〕鰜怼O旅娼o出一幅示意圖來描述棧:即通過PUSH

10來將元素10放入棧中,因為,先前棧中沒有任何數(shù)據(jù),所以,10就會作為棧頂元素存在,然后再在棧中壓入元素20,此時,棧頂中的元素就是20了,然后再使用

POP指令將棧頂元素取出,此時取出的棧頂元素是20,取出20后,棧中便只剩下10了,自然10就成為了棧頂,最后再通過POP指令將棧頂10取出,此時,棧便變成了空棧了。好了,在介紹段寄存器之前的基礎(chǔ)知識介紹就到這里了,下面開始正式介紹段寄存器以及與它們協(xié)作使用的寄存器。

CS寄存器和IP寄存器:經(jīng)過前面對段的介紹,相信各位朋友對段寄存器應(yīng)該也有一定的了解了,下面將要介紹的是一組非常非常重要的寄存器,即CS:IP。CS:IP兩個寄存器指示了CPU當(dāng)前將要讀取的指令的地址,其中

CS

為代碼段寄存器,而

IP

為指令指針寄存器。什么叫做指示了CPU當(dāng)前將要讀取的指令呢?在8086

CPU中,為什么

CPU

會自動的執(zhí)行指令呢?這些指令肯定是存放在內(nèi)存中的,但是

CPU

怎么知道這些指令存放在內(nèi)存的那個位置呢?比如,我有下面的兩條指令要執(zhí)行:MOVAX,1234HMOVBX,AX而假設(shè)這兩條指令在內(nèi)存中存放為:很顯然,1000H:0000H指向的是

MOV

AX,1234H

的首地址,如果CPU要讀取到我的指令的話,很顯然,必須要知道地址

1000H:0000H,然后

CPU

就可以根據(jù)這個首地址,將匯編指令

MOV

AX,1234H

所對應(yīng)的機器碼讀入到

CPU

的指令寄存器中,最后便可以在

CPU

中進(jìn)行處理了。但關(guān)鍵是

CPU

如何知道我的

1000H:0000H

這個首地址?其實這就需要使用到

CS:IP

這個寄存器組了。當(dāng)我們運行一個可執(zhí)行文件時,很明顯,我們需要另外一個程序來將這個可執(zhí)行文件加載到內(nèi)存當(dāng)中,關(guān)于這個加載可執(zhí)行文件的程序,我們在這里不管他,點一下即可,一般是通過操作系統(tǒng)的外殼程序(也就是傳說中的

Shell

程序),Shell

將可執(zhí)行文件加載到內(nèi)存中以后,就會設(shè)置

CPU

中的兩個寄存器,即設(shè)置

CS:IP

兩個寄存器指向可執(zhí)行文件的起始地址,此后

CPU

便從這個起始地址開始讀取內(nèi)存中的指令,并且執(zhí)行,比如我們在寫匯編程序時,通常會使用

START

標(biāo)記,其實這個標(biāo)記就是用來標(biāo)記起始地址的,當(dāng)將一個匯編程序編譯,連接成可執(zhí)行文件以后,再通過操作系統(tǒng)的

Shell

程序?qū)⒖蓤?zhí)行文件加載到內(nèi)存中以后,這個

START

所標(biāo)記處的地址就是整個可執(zhí)行文件的起始地址了。也就是說,當(dāng)一個可執(zhí)行文件加載到內(nèi)存中以后,CS:IP

兩個寄存器便指向了這個可執(zhí)行文件的起始地址,然后

CPU

就可以從這個起始地址開始往下讀取指令,當(dāng)讀取完指令后,CS:IP

將會自動的改變,基本上是改變

IP,從而指向下一條要讀取的指令,這樣就可以執(zhí)行這個可執(zhí)行文件了

。最后再對

CS:IP

總結(jié)一下:你想讓

CPU

執(zhí)行哪行指令,你就讓

CS:IP

指向保存有指令的那塊內(nèi)存即可。任何時候,CS:IP

指向的地址中的內(nèi)容都是

CPU

當(dāng)前執(zhí)行的指令。下面我們來看一個

Demo,并詳細(xì)觀察其執(zhí)行的過程:ASSUMECS:CODESCODESSEGMENT START:MOVAX,1234HMOVBX,AXMOVAH,4CHINT21HCODESENDSENDSTART語句的執(zhí)行過程如下:從上面的截圖中可以看出,當(dāng)我使用

Shell(在

DOS

下也就是

Command

命令解釋器)將可執(zhí)行文件加載進(jìn)內(nèi)存后,可以看到,整個程序的起始地址為

0C54H:0000H

,并且,可以看到

CS

的地址為

0C54H,IP

的地址為

0000H,這正好吻合我們上面對

CS:IP

的分析,很明顯,CPU

將會讀取

MOV

AX,1234H

到CPU中并且執(zhí)行,然后我們繼續(xù)向下看:可以看到,我們單步執(zhí)行后,AX中的值編成了

1234H,而

IP

寄存器中的值變成了

0003H,對于

AX

中的值的改變,我們是能夠理解的,但是

IP

中的值為什么會從

0000H

變到

0003H

呢?從最上面的一幅關(guān)于指令在內(nèi)存中的存放可以看出

MOV

AX,1234H

在內(nèi)存中需要

3個內(nèi)存單元存放,也就是

CPU

為了執(zhí)行

MOV

AX,1234H

這條指令,已經(jīng)將內(nèi)存中相對應(yīng)的3

個內(nèi)存單元讀入內(nèi)存中了,執(zhí)行完這條指令后,自然,CPU

就要將偏移地址向下移動

3

個單元,從而使得

CS:IP

指向下一條需要執(zhí)行的指令了,為了更深刻的理解,我們再來繼續(xù)看執(zhí)行過程,從最上面的一幅關(guān)于指令在內(nèi)存中的存放可以看出

MOV

BX,AX

在內(nèi)存中只占

2

個內(nèi)存單元,這也就是為什么

IP

這一次只向下移動了

2

個單元的緣故。

關(guān)于

CS:IP

的遐想:從上面關(guān)于

CS:IP

的介紹中,我們可以大膽的猜想,我們只需要通過手動的改變

CS:IP

所指向的內(nèi)存地址,讓

CS:IP

指向我們另外的代碼,那么我們就可以讓

CPU

執(zhí)行我們自己指定的代碼了。即可以通過修改

CS:IP

來達(dá)到我們想要讓

CPU

干什么它就干什么的目的。上面的雖然是遐想,但是大家要相信,我們寫的是匯編,不是

JAVA

也不是

NET

,所以我們還真的可以達(dá)到上面的目的,也就是說我們的遐想其實是可以實現(xiàn)的,當(dāng)然這還是有一定的限制的,關(guān)于這個遐想呢,可能會在我后續(xù)的博文中有所介紹,不過感興趣的當(dāng)然可以自己去嘗試了,蠻有味的哦。

SS寄存器和SP寄存器:根據(jù)前面對棧的介紹,相信各位對棧也肯定是有一定了解了的,更何況,估計大家也是職場打滾多年的,要是棧都沒用過的話,那也確實蠻悲劇的,所以,我在這里也不會對棧做十分詳細(xì)的介紹了,但是,最基本的介紹還是要的,畢竟在底層的話,不像高級語言那么方便,可以直接一個

Stack

就OK的,在底層涉及的是棧在內(nèi)存中的具體實現(xiàn)。不知道,大伙有沒有注意筆者在本篇博文的上面介紹關(guān)于棧的知識時,我并沒有提到如何找到這個棧,我只提到了一個棧就是先進(jìn)后出操作,同時可以使用

”PUSH“

”POP“

指令,然后就是稍微帶了一下

SS這個寄存器的介紹,我們雖然在內(nèi)存中是可以方便的定義一個棧了,但是,我們?yōu)槭裁匆x這么一個棧呢?自然,是為了操作方便,同時提供給

CPU

使用的,既然

CPU

要使用的話,自然,CPU

又必須根據(jù)一定的方式找到這個棧,而這就需要使用

SS和

SP寄存器了。同時,一個棧也就是一塊內(nèi)存區(qū)域,通過上面的介紹,我們也知道了如果要在一塊內(nèi)存中精確地定位到內(nèi)存單元的話(尋址),我們必須要有基地址(也就是段地址左移

4

位)和偏移地址,自然,要在一個棧中尋址的話,也需要段地址和偏移地址,而對于一個棧來說,我們使用的最多的是什么呢?當(dāng)然是棧頂了,因為只有棧頂可以用來存取數(shù)據(jù),所以對于一個棧來說,我們只需要有棧頂?shù)亩蔚刂泛推频刂芳纯桑鴮τ跅m數(shù)亩蔚刂罚涫谴娣旁诙渭拇嫫?/p>

SS

中的,而對于棧頂?shù)钠频刂罚鋭t是存放在

SP

寄存器中的。記住,在任何時刻,SS:SP

都是指向棧頂元素。其實關(guān)于棧的使用還是比較簡單的,但是要注意的是

8086

CPU

并不會保證我們對棧的操作會不會越界。所以我們在使用棧的時候需要特別注意棧的越界問題。當(dāng)使用

PUSH

指令向棧中壓入1個字節(jié)單元時,SP=SP-1;即棧頂元素會發(fā)生變化;而當(dāng)使用

PUSH

指令向棧中壓入

2個字節(jié)的字單元時,SP=SP–2;即棧頂元素也要發(fā)生變化;當(dāng)使用

POP

指令從棧中彈出1個字節(jié)單元時,SP=SP+1;即棧頂元素會發(fā)生變化;當(dāng)使用

POP

指令從棧中彈出2個字節(jié)單元的字單元時,SP=SP+2;即棧頂元素會發(fā)生變化;下面通過一個

Demo來介紹棧的使用:ASSUMECS:CODESCODESSEGMENT START:MOVAX,1000H ;首先是定義好棧的段地址MOVSS,AXMOVAX,10H ;再定義好棧的長度(初始時刻的棧頂偏移地址即棧的長度)MOVSP,AXMOVAX,0001HPUSHAXMOVAX,0002HPUSHAXMOVAX,0003HPUSHAXMOVAX,0004HPUSHAXMOVAX,0005HPUSHAXPOPAXPOPAXPOPAXPOPAXPOPAXMOVAH,4CHINT21HCODESENDSENDSTART

然后我們來看棧在內(nèi)存中的結(jié)構(gòu)圖:語句的執(zhí)行過程如下:首先我們來看尚未執(zhí)行上述任何指令時棧中的數(shù)據(jù)情況:然后我們再來依次執(zhí)行上述指令:從上副截圖中可以看出已經(jīng)設(shè)置好了

SS:SP,也就是棧已經(jīng)設(shè)置OK了,下面開始往棧中壓入數(shù)據(jù)了,由于我們壓入棧中的數(shù)據(jù)為字?jǐn)?shù)據(jù),即占2個內(nèi)存單元,所以,每次

SP=SP–2;將5個字型數(shù)據(jù)壓入棧中后,我們可以來查看棧中的數(shù)據(jù)了,因此,在內(nèi)存中的一個好看點的結(jié)構(gòu)圖如下所示:下面開始進(jìn)行出棧操作了由于我們彈出棧時的數(shù)據(jù)為字?jǐn)?shù)據(jù),即占2個內(nèi)存單元,所以,每次

SP=SP+2;將5個字型數(shù)據(jù)全部彈出棧中后,我們可以來查看棧中的數(shù)據(jù)了,可以看到SP變成了初始狀態(tài)了,也就是說棧中所有的數(shù)據(jù)已經(jīng)全部彈出了,雖然我們查看內(nèi)存時看到的不是0,但是我們看到的這些數(shù)據(jù)都是無效的,我們這里不理會。

DS寄存器和ES寄存器:DS

寄存器和

ES

寄存器都屬于段寄存器,其實它們和

CS

寄存器以及

SS

寄存器用起來區(qū)別不大,既然是段寄存器的話,自然它們存放的就是某個段地址了。通過上面對基礎(chǔ)知識的介紹呢,我們已經(jīng)知道,如果

CPU

要訪問一個內(nèi)存單元時,我們必須要提供一個指向這個內(nèi)存單元的物理地址給

CPU,而我們也知道在

8086

CPU

中,物理地址是由段地址左移4

位,然后加上偏移地址形成的,所以,我們也就只需要提供段地址和偏移地址即OK。8086

CPU

呢,提供了一個

DS

寄存器,并且通常都是通過這個

DS

段寄存器來存放要訪問的數(shù)據(jù)的段地址。DS(Data

Segment):很顯然,DS中存放的是數(shù)據(jù)段的段地址。但是這里不得不再點一下,那就是我們對段的支持是在

CPU

上體現(xiàn)的,而不是在內(nèi)存中實現(xiàn)了段,所以事實上我們使用的段其實是一個邏輯概念,即是我們自己定義的,再說白了,我定義一個段,我說它是數(shù)據(jù)段那它就是數(shù)據(jù)段,我說它是代碼段那么它就是代碼段,它們其實都是一塊連續(xù)的內(nèi)存而已,至于為什么要區(qū)分為數(shù)據(jù)段和代碼段,很明顯,是用來給我們編程提供方便的,即我們在自己的思想上或者說是編碼習(xí)慣上規(guī)定,數(shù)據(jù)放數(shù)據(jù)段中,代碼放代碼段中。而我們在使用數(shù)據(jù)段的時候,為了方便或者說是代碼的編寫方便起見,我們一般把數(shù)據(jù)段的段地址放在

DS

寄存器中,當(dāng)然,如果你硬要覺得

DS

不順眼,那你可以換個

ES

也是一樣的,至于

ES(Extra

Segment)

段寄存器的話,自然,是一個附加段寄存器,如果再說得過分點,就當(dāng)它是個擴(kuò)展吧,當(dāng)你發(fā)現(xiàn),你幾個段寄存器不夠用的時候,你可以考慮使用

ES

段寄存器,在使用方式上,則和其他的段寄存器沒什么區(qū)別

。下面看一個介紹使用

DS

寄存器的

Demo:ASSUMECS:CODESCODESSEGMENTSTART:MOVAX,1000HMOVDS,AXMOVAL,1MOVBX,0MOVCX,5 ;設(shè)計一個循環(huán),讓其循環(huán)5次s:MOV[BX],AL ;這里[BX]并沒有指定段地址哦INCALINCBXLOOPsMOVAH,4CHINT21HCODESENDSENDSTART上面的代碼所做的事情,就是循環(huán)將

1,2,3,4,5寫入到地址

1000H:0000H,1000H:0001H,1000H:0002H,1000H:0003H,1000H:0004H

中,語句的執(zhí)行過程如下:首先我們來看尚未執(zhí)行上述任何指令時棧中的數(shù)據(jù)情況:而當(dāng)循環(huán)執(zhí)行完成以后,我們再來看內(nèi)存

1000H:0000H處的值:在這里,我們可以看到確實達(dá)到了我們預(yù)期的效果,但是大家注意看代碼:s:MOV[BX],AL ;這里[BX]并沒有指定段地址哦INCALINCBXLOOPs這里可以看到,我們在

[BX]

中并沒有給其指定段地址,而只有一個偏移地址,但是根據(jù)我們一開始的介紹,必須要有段地址和偏移地址才能夠定位內(nèi)存單元,莫非這里出問題了?其實不是的,因為我們在最前面定義了段地址

DS

1000H,當(dāng)我們定義好段地址后,每一次

CPU

執(zhí)行到

[BX]

時,便會自動或者說是默認(rèn)的從

DS

中取值,并且將取得的值作為段地址,因此,當(dāng)

[BX]

0001H

時,CPU

會從

DS

中取得一個

1000H,由這兩個一合成即可以得到正確的物理地址

1000H:0000H。最后還提醒一點,那就是

8086

CPU

不支持直接將一個數(shù)據(jù)送入段寄存器中,也就是下面的做法是錯誤的:MOVDS,1000H

標(biāo)志寄存器(FLAG):前面呢,已經(jīng)介紹了

8086

CPU

14個寄存器中的13個了,下面我們將介紹最后一個寄存器也就是

FLAG

寄存器,F(xiàn)LAG

寄存器之所以放到最后一個介紹,是因為其和其他的一些寄存器不同,像

AX,BX,CX,DX

這些寄存器來說,它們都是用來存放數(shù)據(jù)的,當(dāng)然

FLAG

中存放的也是數(shù)據(jù)啦,呵呵,不過,AX,BX這些寄存器中的數(shù)據(jù)是作為一個整體使用的,最多也就分成一個

AL

AH

使用而已,但是在

FLAG

中,數(shù)據(jù)是按位起作用的,也就是說,F(xiàn)LAG

中的每一個位都表示不同的狀態(tài),由于一個位也就能表示

0

1,自然,F(xiàn)LAG

中的每一個位就是用來描述狀態(tài)的,而且

FLAG

寄存器中存儲的信息通常又被稱作程序狀態(tài)字(PSW)。下面我給出一幅

FLAG

寄存器中各個位的示意圖:從上面這幅圖中可以看出,F(xiàn)LAG

的第

0

個位表示的是CF

,第2個位表示的是

PF

,與此類推....

首先,我們來看一個列表:上面的這個表怎么看呢?我們通過看下面一幅截圖就知道了。從上面的標(biāo)記中可以看出,從左到右依次代表

OF,DF,SF,ZF,PF,CF

標(biāo)志位的值,再通過與上面的表格相對照可以知道:OF=0;DF=0;SF=0;ZF=0;PF=0;CF=0

;至于為什么我們在

Debug

模式下,使用

R

命令時,只會列出這幾個標(biāo)志位,我菜的話是因為相對來說,列出的這幾個標(biāo)志位更為常用,其他的幾個標(biāo)志位并不經(jīng)常使用的緣故吧。下面我們就按不同的位來分別介紹這些位所描述的狀態(tài),以及它們代表的意義:CF(Carry

FLag)-進(jìn)位標(biāo)志(第0位):CF:

進(jìn)位標(biāo)志是用來反映計算時是否產(chǎn)生了由低位向高位的進(jìn)位,或者產(chǎn)生了從高位到低位的借位。if(運算過程中產(chǎn)生了進(jìn)位或者借位){CF=1;}else{CF=0;}

PF(Parity

FLag)-奇偶標(biāo)志(第2位):PF:

奇偶標(biāo)志是用來記錄相關(guān)指令執(zhí)行后,其結(jié)果的所有的

Bit

位中

1

的個數(shù)是否為偶數(shù)。if(運算結(jié)果中1的個數(shù)為偶數(shù)){PF=1;}else{PF=0;}

AF(Auxiliary

Carry

FLag)-輔助進(jìn)位標(biāo)志(第4位):AF:

用來輔助進(jìn)位標(biāo)志。if(字節(jié)操作中發(fā)生低半個字節(jié)向高半個字節(jié)借位或者進(jìn)位||字操作中發(fā)生低字節(jié)向高字節(jié)借位或者進(jìn)位){AF=1;}else{引子打算寫幾篇稍近底層或者說是基礎(chǔ)的博文,淺要介紹或者說是回顧一些基礎(chǔ)知識,自然,還是得從最基礎(chǔ)的開始,那就從匯編語言開刀吧,從匯編語言開刀的話,我們必須還先要了解一些其他東西,像

CPU,內(nèi)存這些知識點還是理解深刻一點的比較好,所以這一篇博文就繞著80x86

CPU中寄存器的基礎(chǔ)部分下手,至于其他的一些將會在后續(xù)的博文中介紹。同時在這里說明一下,本篇博文介紹的算是比較詳細(xì)的了,而且介紹的知識點也是比較多的,所以造成博文長度過長,如果有興趣想了解這一塊的話,還請自行斟酌好閱讀比例,建議分3次以上閱覽。讀者定位本博文主要將介紹的是

8086CPU中的寄存器,既然是8086CPU寄存器簡介的話,自然,面向的是初級一些的讀者,其中不會涉及太多難點,同時,所有的介紹,我也會盡可能的從基礎(chǔ)開始,然后循序漸進(jìn)的介紹,同時也會盡量的將知識點介紹詳細(xì),介紹的過程中也會涉及到一些匯編程序代碼,當(dāng)然,采用的是最簡單的方式介紹而已,本篇博文也就是回顧一些基礎(chǔ)知識,讀者主要定位于想對8086CPU有所了解,希望對整個程序設(shè)計的底層有所了解的朋友,而且讀者最好是擁有一定的計算機基礎(chǔ)和匯編語言基礎(chǔ)。

開頭首先淺要介紹一下

Intel

CPU的發(fā)展史吧:IntelCPU系列,最初是4位微處理器4004,然后到到8位微處理器的8008,再到8微微處理器8080,以及稍后的16位微處理器8086,由8086開始,Intel進(jìn)入現(xiàn)在所謂的

x86

時代。Intel

8086為16位

CPU,而因為在8086之前的CPU都是8位CPU,這樣也就造成了很多的外設(shè)也只支持8位,因此

Intel

緊接著就退出了8位的8088CPU,因此

Intel8088也就可以看做是8086的8位版本;如果是但從匯編語言的角度上來說,8086和8088是沒有區(qū)別的,即8086上跑的程序可以不加修改的移植到8088,8088上跑的程序也可以不加修改的移植到8086上,當(dāng)然,還是有些特殊的地方是不同的,而這些基本上在這里可以忽略掉,在8088

CPU之后,Intel

又推出了

80186,80286,這兩款CPU均是16位

CPU,而對于80186來說,其與8086的區(qū)別可以簡單的看做是80186多了幾條指令而已,而80286則不同,80286的地址總線數(shù)目有了變化,在8086,8088,80186上,CPU的地址總線都是20根,即可最大尋址220

即達(dá)到1MB的尋址能力,而對于80286CPU來說,其地址總線數(shù)目達(dá)到了24根,從而最大尋址能力為224

即16MB,由于支持更多的物理內(nèi)存尋址,因此80286便開始成為了多任務(wù),多用戶系統(tǒng)的核心。而后來,Intel

又推出了80386,80386為32位微處理器,Intel80x86家族的32位微處理器始于80386;同時80386也完全兼容先前的8086/8088,80186,80286,并且80386全面支持32位數(shù)據(jù)類型和32位操作,并且80386的數(shù)據(jù)總線根數(shù)和地址總線根數(shù)均達(dá)到了32根,從而可以最大物理尋址為232

即4GB。而之后的80486也是32位微處理器,而后又出來了Pentium和PentiumPro等等第五代微處理器,這些處理器雖然也是32位微處理器,但是他們的數(shù)據(jù)總線和地址總線都有所擴(kuò)展,比如Pentium的數(shù)據(jù)總線達(dá)到64位,而PentiumPro的地址總線位數(shù)達(dá)到了36位。

好,關(guān)于IntelCPU的介紹就到這里了,下面就要開始回歸中心,看CPU中的寄存器了,首先,從學(xué)習(xí)的角度來說,從8086/8088

CPU下手是不錯的選擇,而我這里選擇的也是8086CPU而已,說實在的,像80386CPU我也還沒有研究過,像奔騰這些,呵呵,扯更遠(yuǎn)了,說到底也就只能拿8086出來曬曬而已,當(dāng)然,從8086開始也是學(xué)習(xí)的最佳路徑。

說了這么久,到底寄存器是什么呢?其實很簡單,寄存器就是個存儲信息的單元或者說是器件又或者說是容器而已,就比如內(nèi)存也是一個存儲介質(zhì)或者說是存儲單元而已,其實寄存器從理解上來說和內(nèi)存差不多,只不過寄存器(這里討論的寄存器都是CPU中的寄存器,不包括外設(shè)上的寄存器)位于

CPU

內(nèi)部,而內(nèi)存位于CPU外部,而且,寄存器比內(nèi)存可是珍貴得多啊,就拿內(nèi)存和硬盤來比,肯定是內(nèi)存在使用上珍貴得多,是PC中的稀有資源,而寄存器是CPU中的稀有資源,內(nèi)存和寄存器相比就像硬盤和內(nèi)存相比一樣。而對于一個匯編程序員來說,CPU中主要可以使用的也就是寄存器而已,匯編程序員可以使用指令來讀寫CPU中的寄存器,從而可以實現(xiàn)對于CPU的控制,當(dāng)然,不同的CPU,寄存器的個數(shù)和結(jié)構(gòu)都是不一樣的,比如8086CPU中,寄存器的個數(shù)也就14個而已,并且8086CPU中所有的寄存器的結(jié)構(gòu)為16位,即一個寄存器中可以存放下2B即2個字節(jié),而到了80386CPU中,寄存器的個數(shù)也比8086增多了,比如在80386中添加了系統(tǒng)地址寄存器等寄存器,同時寄存器的結(jié)構(gòu)也變了,比如在80386中絕大多數(shù)的寄存器為32位,而有些寄存器則是16位。8086

CPU中寄存器總共為14個,且均為16位。即

AX,BX,CX,DX,SP,BP,SI,DI,IP,F(xiàn)LAG,CS,DS,SS,ES

共14個。而這14個寄存器按照一定方式又分為了通用寄存器,控制寄存器和段寄存器。通用寄存器:AX,BX,CX,DX稱作為數(shù)據(jù)寄存器:AX(Accumulator):累加寄存器,也稱之為累加器;BX(Base):基地址寄存器;CX(Count):計數(shù)器寄存器;DX(Data):數(shù)據(jù)寄存器;SP和BP又稱作為指針寄存器:SP(StackPointer):堆棧指針寄存器;BP(BasePointer):基指針寄存器;SI和DI又稱作為變址寄存器:SI(SourceIndex):源變址寄存器;DI(DestinationIndex):目的變址寄存器;控制寄存器:IP(InstructionPointer):指令指針寄存器;FLAG:標(biāo)志寄存器;段寄存器:CS(CodeSegment):代碼段寄存器;DS(DataSegment):數(shù)據(jù)段寄存器;SS(StackSegment):堆棧段寄存器;ES(ExtraSegment):附加段寄存器;

通用寄存器從上面可以知道,在8086CPU中,通用寄存器有8個,分別是AX,BX,CX,DX,SP,BP,SI,DI,至于為什么給它們?nèi)∶鐾ㄓ眉拇嫫鳎鞘且驗椋@些個寄存器每一個都有自己專門的用途,比如CX作為計數(shù)寄存器,則是在使用LOOP指令循環(huán)時用來指定循環(huán)次數(shù)的寄存器,如果它們每一個都只有一個專用的作用,那就它們只能稱之為專用寄存器了,正是因為這些個寄存器還可以用來傳送數(shù)據(jù)和暫存數(shù)據(jù),所以才稱它們?yōu)橥ㄓ眉拇嫫鳌O旅婢桶错樞騺硪灰唤榻B這幾個通用寄存器了:數(shù)據(jù)寄存器(AX,BX,CX,DX):數(shù)據(jù)寄存器有AX,BX,CX,DX四個組成,由于在8086之前的CPU為8位CPU,所以為了兼容以前的8位程序,在8086CPU中,每一個數(shù)據(jù)寄存器都可以當(dāng)做兩個單獨的寄存器來使用,由此,每一個16位寄存器就可以當(dāng)做2個獨立的8位寄存器來使用了。AX寄存器可以分為兩個獨立的8位的AH和AL寄存器;BX寄存器可以分為兩個獨立的8位的BH和BL寄存器;CX寄存器可以分為兩個獨立的8位的CH和CL寄存器;DX寄存器可以分為兩個獨立的8位的DH和DL寄存器;除了上面4個數(shù)據(jù)寄存器以外,其他寄存器均不可以分為兩個獨立的8位寄存器;注意在上面標(biāo)志中的“獨立”二字,這兩個字表明AH和AL作為8位寄存器使用時,可以看做它們是互不相關(guān)的,也就是看做兩個完全沒有聯(lián)系的寄存器X和Y即可,比如指令

MOV

AH,12H,CPU在執(zhí)行時根本就不會知道AL中是什么鬼東西,因為它只認(rèn)識

AH。下面給出一幅16位數(shù)據(jù)寄存器的結(jié)構(gòu)圖:表示16位寄存器AX可以表示成兩個8位寄存器,其中AH表示高位的8位寄存器,AL表示低位的8位寄存器。AX寄存器:如上所說,AX的另外一個名字叫做累加寄存器或者簡稱為累加器,其可以分為2個獨立的8位寄存器AH和AL;在寫匯編程序時,AX寄存器可以說是使用率最高的寄存器(不過,總共才那么14個寄存器,哪一個不經(jīng)常使用咯?),既然AX是數(shù)據(jù)寄存器的話,那么理所當(dāng)然,其可以用來存放普通的數(shù)據(jù),由于其是16位寄存器,自然也就可以存放16位數(shù)據(jù),但是因為其又可以分為2個獨立的8位寄存器AH和AL,所以,在AH和AL中又可以獨立的存放2個8位的數(shù)據(jù),可以有以下代碼(即將AX當(dāng)做普通的寄存器使用,即可以用來暫存數(shù)據(jù)):MOVAX,1234H ;向寄存器AX傳入數(shù)據(jù)1234HMOVAH,56H ;向寄存器AX的高8位寄存器AH中傳入數(shù)據(jù)56HMOVAL,78H ;向寄存器AX的低8位寄存器AL中傳入數(shù)據(jù)78H3條語句的執(zhí)行過程如下:而既然AX又被稱作為累加器,自然其還有一點點特殊的地方的:AX寄存器還具有的特殊用途是在使用DIV和MUL指令時使用,DIV在8086CPU中是除法指令,而在使用除法的時候有兩種情況,即除數(shù)可以是8位或者是16位的,而且除數(shù)可以存放在寄存器中或者是內(nèi)存單元中,而至于被除數(shù)的話,自然,應(yīng)該由AX來代替了,當(dāng)除數(shù)是8位時,被除數(shù)一定會是16位的,并且默認(rèn)是放在AX寄存器中,而當(dāng)除數(shù)是16位時,被除數(shù)一定是32位的,因為AX是16位寄存器,自然,放不下32位的被除數(shù),所以,在這里還需要使用另一個16位寄存器DX,其中DX存放32位的被除數(shù)的高16位,而AX則存放32位的被除數(shù)的低16位,同時,AX的作用還不僅僅是用來保存被除數(shù)的,當(dāng)除法指令執(zhí)行完成以后,如果除數(shù)是8位的,則在AL中會保存此次除法操作的商,而在AH中則會保存此次除法操作的余數(shù),當(dāng)然,如果除數(shù)是16位的話,則AX中會保存本次除法操作的商,而DX則保存本次除法操作的余數(shù)。上面介紹的是AX寄存器在除法操作中的應(yīng)用,下面還需要介紹一下AX在乘法操作中的應(yīng)用,當(dāng)使用MUL做乘法運算時,兩個相乘的數(shù)要么都是8位,要么都是16位,如果兩個相乘的數(shù)都是8位的話,則一個默認(rèn)是放在AL中,而另一個8位的乘數(shù)則位于其他的寄存器或者說是內(nèi)存字節(jié)單元中,而如果兩個相乘的數(shù)都是16位的話,則一個默認(rèn)存放在AX中,另一個16位的則是位于16的寄存器中或者是某個內(nèi)存字單元中。同時,當(dāng)MUL指令執(zhí)行完畢后,如果是8位的乘法運算,則默認(rèn)乘法運算的結(jié)果是保存在AX中,而如果是16位的乘法運算的話,則默認(rèn)乘法運算的結(jié)果有32位,其中,高位默認(rèn)保存在DX中,而低位則默認(rèn)保存在AX中。AX寄存器在DIV

指令中的使用:MOVDX,0H ;設(shè)置32位被除數(shù)的高16位為0HMOVAX,8H ;設(shè)置32位被除數(shù)的低16位為8HMOVBX,2H ;設(shè)置16位除數(shù)為2HDIVBX ;執(zhí)行計算4條語句的執(zhí)行過程如下:AX寄存器在MUL

指令中的使用:MOVAX,800H ;設(shè)置16位乘數(shù)為800HMOVBX,100H ;設(shè)置16位乘數(shù)為100HMOVDX,0H ;清空用來保存乘法結(jié)果的高16位MULBX ;執(zhí)行計算4條語句的執(zhí)行過程如下:

BX寄存器:首先可以明確的是,BX作為數(shù)據(jù)寄存器,表明其是可以暫存一般的數(shù)據(jù)的,即在某種程度上,它和AX可以暫存一般性數(shù)據(jù)的功能是一樣的,其同樣為了適應(yīng)以前的8位CPU,而可以將BX當(dāng)做兩個獨立的8位寄存器使用,即有BH和BL,除了暫存一般性數(shù)據(jù)的功能外,BX作為通用寄存器的一種,BX主要還是用于其專屬功能–尋址(尋址物理內(nèi)存地址)上,BX寄存器中存放的數(shù)據(jù)一般是用來作為偏移地址使用的,何為偏移地址呢?既然是偏移地址的話,當(dāng)然得有一個基地址了,而這個基地址其實就是段地址,這里就涉及到了段寄存器,當(dāng)然,在介紹BX寄存器的時候,我不會去介紹段寄存器,上面提到BX的主要功能是用在尋址上,那么,其是如何尋址的呢?對于尋址這個話題,我會在我的下一篇博文中作出詳細(xì)的介紹,而這里,我只點一下,在8086CPU中,CPU是根據(jù)<段地址:偏移地址>來進(jìn)行尋址操作的,而BX中存放的數(shù)據(jù)表示的是偏移地址的話,自然,便可以通過<段地址:[BX]>的方式來完成尋址操作了。為了介紹BX在尋址當(dāng)中的作用,下面我給出一副示意圖:上面的示意圖表示:可以令BX=2,然后通過DS:[BX]來訪問到內(nèi)存中段地址為DS,且偏移量為2的內(nèi)存單元了。上面介紹的這種尋址方式是BX在尋址中最最簡單的應(yīng)用了,而對于稍微復(fù)雜的尋址方式,還可以依賴于SI,DI,BP等寄存器來一起完成,當(dāng)然,這會是下一篇博文將要介紹的內(nèi)容了。BX

寄存器在尋址中的使用:MOVBX,5HMOVAH,11HMOVAH,[BX] ;設(shè)置AX的值為偏移地址為BX中的值時所代表的內(nèi)存單元3條語句的執(zhí)行過程如下:從上圖可以看出,在偏移地址為5時的內(nèi)存單元中的數(shù)據(jù)位BBH,而從這幅圖上面就可以看出,確實通過[BX]找到了偏移地址為5處的內(nèi)存單元,并且將內(nèi)存單元移入了AH中。

CX寄存器:CX寄存器作為數(shù)據(jù)寄存器的一種呢,其同樣具有和AX,BX一樣的特點,即可以暫存一般性的數(shù)據(jù),同時還可以將其當(dāng)做兩個獨立的8位寄存器使用,即有CH和CL兩個8位寄存器,當(dāng)然,CX也是有其專門的用途的,CX中的C被翻譯為Counting也就是計數(shù)器的功能,當(dāng)在匯編指令中使用循環(huán)LOOP指令時,可以通過CX來指定需要循環(huán)的次數(shù),而CPU在每一次執(zhí)行LOOP指令的時候,都會做兩件事:一件就是令CX=CX–1,即令CX計數(shù)器自動減去1;還有一件就是判斷CX中的值,如果CX中的值為0則會跳出循環(huán),而繼續(xù)執(zhí)行循環(huán)下面的指令,當(dāng)然如果CX中的值不為0,則會繼續(xù)執(zhí)行循環(huán)中所指定的指令。CX

寄存器在循環(huán)中的使用(輸出5個白底藍(lán)字的A):MOVAX,0B800HMOVDS,AX ;使用80x25彩色字符模式,內(nèi)存地址0xB8000-0xBFFFFFMOVBX,0 ;從0xB8000開始MOVCX,5H ;循環(huán)5次MOVDX,41H ;A的16進(jìn)制為41HMOVAX,01110001B ;顯示白底藍(lán)字s:MOV[BX],DX ;顯示ASCII字符ADDBX,1MOV[BX],AX ;設(shè)置字符顯示屬性ADDBX,1LOOPs語句的執(zhí)行過程如下:

DX寄存器:DX寄存器作為數(shù)據(jù)寄存器的一種,同樣具有和AX,BX,CX一樣的特點,即可以暫存一般性的數(shù)據(jù),同時還可以將其當(dāng)做兩個獨立的8位寄存器使用,極有DH和DL,同時,DX作為一個通用寄存器的話,自然其還有其他的用途,而關(guān)于DX在其他方面的用途,其實在前面介紹AX寄存器時便已經(jīng)有所介紹了,即當(dāng)在使用DIV指令進(jìn)行除法運算時,如果除數(shù)為16位時,被除數(shù)將會是32位,而被除數(shù)的高16位就是存放在DX中,而且執(zhí)行完DIV指令后,本次除法運算所產(chǎn)生的余數(shù)將會保存在DX中,同時,在執(zhí)行MUL指令時,如果兩個相乘的數(shù)都是16位的話,那么相乘后產(chǎn)生的結(jié)果顯然需要32位來保存,而這32位的結(jié)果的高16位就是存放在DX寄存器中。DX寄存器在DIV

指令中的使用(即2293812/256=8960

余數(shù)為52):MOVDX,0023H ;32位被除數(shù)的高16位MOVAX,0034H ;32位被除數(shù)的低16位MOVBX,100H ;16的除數(shù)DIVBX語句的執(zhí)行過程如下:

可以看到在語句結(jié)束以后,AX=2300H

即十進(jìn)制的8960,而DX=34H即十進(jìn)制的52和我們的結(jié)果是一致的。DX寄存器在MUL

指令中的使用則各位可以參考在AX中MUL運算的使用,這里就不貼出來了。

指針寄存器(BP,SP):BP寄存器:8086

CPU中的指針寄存器包括兩個,即SP和BP,在這里呢,我先只對BP寄存器做介紹,因為SP寄存器實質(zhì)上必須和SS段寄存器一起使用,所以,我將會把SP寄存器留到后面和SS段寄存器一起作介紹。BP(BasePointer)也就是基指針寄存器,它和其他的幾個用來進(jìn)行尋址操作所使用的寄存器(還有BX,SI,DI)沒有太大的區(qū)別,關(guān)于SI和DI寄存器的下面請見下文。首先,BP寄存器作為通用寄存器的一種,說明其是可以暫存數(shù)據(jù)的,而后,BP又不是數(shù)據(jù)寄存器,也就意味著其不能分割成2個獨立的8位寄存器使用,而后當(dāng)以[…]的方式訪問內(nèi)存單元而且在[…]中使用了寄存器BP的話,那么如果在指令中沒有明確或者說是顯示的給出段地址時,段地址則使用默認(rèn)的SS寄存器中的值(BX,SI,DI會默認(rèn)使用DS段寄存器),比如DS:[BP]則在這里明確給出了段地址位于DS中,所以,這里代表的內(nèi)存單元即是段地址為DS,偏移量為BP寄存器中的值的內(nèi)存單元,而如果單單是使用[BP]的話,則代表的內(nèi)存單元是段地址為SS,偏移量為BP寄存器中的值的內(nèi)存單元。并且BP寄存器主要適用于給出堆棧中數(shù)據(jù)區(qū)的偏移,從而可以方便的實現(xiàn)直接存取堆棧中的數(shù)據(jù),至于堆棧的話,會在后面的博文中介紹。在8086CPU中,只有4個寄存器可以以

[…]

的方式使用,這四個寄存器分別是BX,SI,DI,BP。下面的

Demo

BX

寄存器在尋址中的使用:MOVBP,0MOVAX,[BP];將SS:[BP]代表的內(nèi)存單元移入AX中MOVAX,CS:[BP];將CS:[BP]代表的內(nèi)存單元移入AX中語句的執(zhí)行過程如下:

變址寄存器(SI,DI):首先,變址寄存器和上面介紹的指針寄存器(也就是BP和SP),它們的功能其實都是用于存放某個存儲單元地址的偏移,或者是用于某組存儲單元開始地址的偏移,即作為存儲器指針使用,當(dāng)然,由于變址寄存器和指針寄存器都是屬于通用寄存器,所以它們也可以保存算術(shù)結(jié)果或者說是具有暫存數(shù)據(jù)的功能,但是因為它們不是數(shù)據(jù)寄存器,所以無法分割成2個獨立的8位寄存器使用,關(guān)于變址寄存器和指針寄存器的詳細(xì)使用,筆者將會在下一篇博文中作出最詳細(xì)的介紹,SI(SourceIndex)是源變址寄存器,DI(DestinationIndex)即是目的變址寄存器,8086CPU中的SI寄存器和DI寄存器其實和

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論