




版權(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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 數(shù)字化轉(zhuǎn)型下的供應(yīng)鏈創(chuàng)新模式研究考核試卷
- 人才市場供需預(yù)測模型構(gòu)建考核試卷
- 刨花板企業(yè)成本控制與質(zhì)量管理考核試卷
- 乳腺導(dǎo)管癌超聲診斷與應(yīng)用
- 基因編輯技術(shù)的前景分析
- 公司工作總結(jié)匯編14篇
- 機器人自主導(dǎo)航與定位的智能算法
- 氣球活動策劃方案
- 法律執(zhí)法活動方案
- 民生劇場活動方案
- HYT 023-2018 中國海洋站代碼(正式版)
- 人教版數(shù)學(xué)六年級下冊數(shù)第四單元《比例》集體備課教案
- 山東省濟(jì)南市2022-2023學(xué)年六年級下學(xué)期語文期末考試試卷(含答案)
- 材料、構(gòu)配件進(jìn)場檢驗記錄表C4-44
- 24春國家開放大學(xué)《農(nóng)業(yè)推廣》調(diào)查報告參考答案
- 杜邦安全管理十大理念
- 《普通話日常用語》課件2
- 糖尿病長用藥物的用法
- 《育嬰師培訓(xùn)》-課件:嬰幼兒聽說能力發(fā)展基礎(chǔ)知識
- 馬克思主義政治經(jīng)濟(jì)學(xué)課件
- 中建總承包管理支持中心方案
評論
0/150
提交評論