匯編語言Assembly(一)


花了三天的時間,學習了王爽的《匯編語言》和清華大學的公開課,還有網上的資料。筆記整理:


匯編語言實際上就是機器碼的助記符,不同類型的CPU之間沒有可移植性。直接接觸底層硬件包括內存地址和寄存器。匯編程序操作的就是數據、內存地址、寄存器和棧。書上和網上介紹的一般是16位8086CPU、X86-32和X86-64的CPU。王爽的《匯編語言》中介紹的是8086的16位CPU,而公開課中講的卻是32位和64位CPU。

CPU通過數據、地址和控制總線與外界相連並進行數據、地址和控制信號的傳送。從CPU的角度看內存地址空間是邏輯地址空間,是連續的,也就是說物理空間實際不連續:


在8086PC機中,存儲單元的地址用兩個元素來描述,即段地址和偏移地址段地址*16 + 偏移地址 = 物理地址一個段的起始地址一定是16的倍數,一個段的長度最大為64KB。這種方式可以尋址的最高地址為0xFFFF:0xFFFF,其地址空間為0x00000~0x10FFEF,因為8086的地址總線是20位,最大只能訪問到1MB的物理地址空間,即物理地址空間是0x00000~0xFFFFF。當程序訪問0x100000~0x10FFEF這一段地址時,因為其邏輯上是正常的,CPU並不會認為其訪問越界而產生異常,但這段地址確實沒有實際的物理地址與其對應。此時CPU采取的策略是,對於這部分超出1M地址空間的部分,自動將其從物理0地址處開始映射。也就是說,系統計算實際物理地址時是按照對1M求模運算的方式進行的,這種技術被稱之為wrap-around:


每個段的最小長度是16字節,而最大長度只能是64KB。但是同一物理地址可以多種表示,地址空間缺乏保護機制。對於每一個由段寄存器的內容確定的“基地址”,一個進程總是能夠訪問從此開始64KB的連續地址空間,而無法加以限制。另一方面,可以用來改變段寄存器內容的指令不是“特權指令”,通過改變段寄存器的內容,一個進程可以隨心所欲地訪問內存中的任何一個單元,而絲毫不受限制。這種模式就是實模式,得到的實在的地址。是CPU工作的一種模式。

在80286的CPU里,首次引入的地址保護的概念。也就是說80286的CPU能夠對內存及一些其他外圍設備做硬件級的保護設置(實質上就是屏蔽一些地址的訪問)。Intel決定在80386的段寄存器(CS,DS,SS,ES)的基礎上構築保護模式,並且繼續保留段寄存器為16位,同時又增添了兩個段寄存器FS和GS。為了實現保護模式,光是用段寄存器來確定一個基地址是不夠的,至少還要有一個地址段的長度,並且還需要一些諸如訪問權限之類的其他信息,此時需要“段描述符”的數據結構來抽象進而管理。

在保護模式下改變段寄存器的功能,使其從一個單純的段基址變成指向一個“段描述符”的指針。因此,當一個訪存指令發出一個內存地址時, CPU按照下面過程實現從指令中的32位邏輯地址到32位線性地址,再到物理地址的轉換:

1、首先根據指令的性質來確定該使用哪一個段寄存器,例如操作指令中的地址在代碼段CS里,而數據指令中的地址在數據段DS里。這一點與實地址模式相同。

2、根據段寄存器里的內容,找到相應的“段描述符”結構。

3、然后,從“段描述符”里得到的才是段基址。

4、將指令中的地址作為偏移量,然后和段描述符結構中規定的段長度進行比較,看齊是否越界。

5、根據指令的性質和段描述符中的訪問權限來確定當前指令操作是否越權。

6、最后才將指令中的地址作為偏移量,存儲單元的物理地址就是該段地址加上段內偏移量,與段基址相加得到線性地址,或者叫虛擬地址。

7、最后根據線性地址算出實際的物理地址。此時的由虛擬地址計算到實際物理地址即虛擬內存管理,一般以段或者頁進行管理。

段描述符保存在端描述符表中分為GDT全局端描述符表和LDT局部端描述符表。其存儲在內存中,GDT的起始地址存放在GDTR寄存器中由OS 設置。


CS、IP是8086CPU中兩個最關鍵的寄存器,它們指示了CPU當前要讀取指令的地址。CS為代碼段寄存器,IP為指令指針寄存器。從CS:IP指向的內存單元讀取指令,讀取的指令進入指令緩沖器IP = IP + 送讀取指令的長度,從而指向下一條指令。


ax、bx、cx、dx 可以用mov指令來改變,mov指令被稱為傳送指令,但是mov指令不能用於設置cs、ip的值。寄存器ax和al通常稱為累加器(Accumulator),用累加器進行的操作可能需要更少時間。累加器可用於乘、除、輸入/輸出等操作,它們的使用頻率很高;寄存器bx稱為基地址寄存器(Base Register)。它可作為存儲器指針來使用;寄存器cx稱為計數寄存器(Count Register)。在循環和字符串操作時,要用它來控制循環次數;在位操作中,當移多位時,要用cl來指明移位的位數;寄存器dx稱為數據寄存器(Data Register)。在進行乘、除運算時,它可作為默認的操作數參與運算,也可用於存放I/O的端口地址。32位指令前面加E,64位前面加R。


寄存器ESI、EDI、SI和DI稱為變址寄存器(IndexRegister),它們主要用於存放存儲單元在段內的偏移量,用它們可實現多種存儲器操作數的尋址方式。寄存器EBP、ESP、BP和SP稱為指針寄存器(PointerRegister),主要用於存放堆棧內存儲單元的偏移量,用它們可實現多種存儲器操作數的尋址方式。不可分割成8位寄存器。作為通用寄存器,也可存儲算術邏輯運算的操作數和運算結果。


段寄存器是根據內存分段的管理模式而設置的。內存單元的物理地址由段寄存器的值和一個偏移量組合而成的,這樣可用兩個較少位數的值組合成一個可訪問較大物理空間的內存地址。CS——代碼段寄存器(Code Segment Register),其值為代碼段的段值;DS——數據段寄存器(Data Segment Register),其值為數據段的段值;ES——附加段寄存器(Extra Segment Register),其值為附加數據段的段值;SS——堆棧段寄存器(Stack Segment Register),其值為堆棧段的段值;FS——附加段寄存器(Extra Segment Register),其值為附加數據段的段值;GS——附加段寄存器(Extra Segment Register),其值為附加數據段的段值。16位CPU中只有前面4個段寄存器,32位有6個。段寄存器CS指向存放程序的內存段,IP是用來存放下條待執行的指令在該段的偏移量,把它們合在一起可在該內存段內取到下次要執行的指令。段寄存器SS指向用於堆棧的內存段,SP是用來指向該堆棧的棧頂,把它們合在一起可訪問棧頂單元。另外,當偏移量用到了指針寄存器BP,則其缺省的段寄存器也是SS,並且用BP可訪問整個堆棧,不僅僅是只訪問棧頂。段寄存器DS指向數據段,ES指向附加段,在存取操作數時,二者之一和一個偏移量合並就可得到存儲單元的物理地址。該偏移量可以是具體數值、符號地址和指針寄存器的值等之一。

訪問存儲器方式 缺省的段寄存器 可選用的段寄存器 偏移量
取指令 CS   IP
堆棧操作 SS   SP
一般取操作數 DS CS、ES、SS 有效地址
串操作

源操作數

DS CS、ES、SS SI

目標操作數

ES   DI
使用指針寄存器BP SS CS、DS、ES 有效地址


指令指針EIP、IP(Instruction Pointer)是存放下次將要執行的指令在代碼段的偏移量。在具有預取指令功能的系統中,下次要執行的指令通常已被預取到指令隊列中,除非發生轉移情況。


程序狀態字寄存器PSW,共9個標識位,分為二組:運算結果標志位和狀態控制標志位。前者受算術運算和邏輯運算結果的影響,后者受一些控制指令執行的影響。有些指令的執行會改變標志位(如:算術運算指令等),不同的指令會影響不同的標志位,有些指令的執行不改變任何標志位(如:MOV指令等),有些指令的執行會受標志位的影響(如:條件轉移指令等),也有指令的執行不受其影響。各個標志位的意義:

1、進位標志CF(Carry Flag)
進位標志CF主要用來反映運算是否產生進位或借位。如果運算結果的最高位產生了一個進位或借位,那么,其值為1,否則其值為0。
使用該標志位的情況有:多字(字節)數的加減運算,無符號數的大小比較運算,移位操作,字(字節)之間移位,專門改變CF值的指令等。
2、奇偶標志PF(Parity Flag)
奇偶標志PF用於反映運算結果中“1”的個數的奇偶性。如果“1”的個數為偶數,則PF的值為1,否則其值為0。
利用PF可進行奇偶校驗檢查,或產生奇偶校驗位。在數據傳送過程中,為了提供傳送的可靠性,如果采用奇偶校驗的方法,就可使用該標志位。
3、輔助進位標志AF(Auxiliary Carry Flag)
在發生下列情況時,輔助進位標志AF的值被置為1,否則其值為0:
(1)、在字操作時,發生低字節向高字節進位或借位時;
(2)、在字節操作時,發生低4位向高4位進位或借位時。
對以上6個運算結果標志位,在一般編程情況下,標志位CF、ZF、SF和OF的使用頻率較高,而標志位PF和AF的使用頻率較低。
4、零標志ZF(Zero Flag)
零標志ZF用來反映運算結果是否為0。如果運算結果為0,則其值為1,否則其值為0。在判斷運算結果是否為0時,可使用此標志位。
5、符號標志SF(Sign Flag)
符號標志SF用來反映運算結果的符號位,它與運算結果的最高位相同。在微機系統中,有符號數采用補碼表示法,所以,SF也就反映運算結果的正負號。運算結果為正數時,SF的值為0,否則其值為1。
6、溢出標志OF(Overflow Flag)
溢出標志OF用於反映有符號數加減運算所得結果是否溢出。如果運算結果超過當前運算位數所能表示的范圍,則稱為溢出,OF的值被置為1,否則,OF的值被清為0。
“溢出”和“進位”是兩個不同含義的概念,不要混淆。如果不太清楚的話,請查閱《計算機組成原理》課程中的有關章節。
二、狀態控制標志位
狀態控制標志位是用來控制CPU操作的,它們要通過專門的指令才能使之發生改變。
1、追蹤標志TF(Trap Flag)
當追蹤標志TF被置為1時,CPU進入單步執行方式,即每執行一條指令,產生一個單步中斷請求。這種方式主要用於程序的調試。
指令系統中沒有專門的指令來改變標志位TF的值,但程序員可用其它辦法來改變其值。
2、中斷允許標志IF(Interrupt-enableFlag)
中斷允許標志IF是用來決定CPU是否響應CPU外部的可屏蔽中斷發出的中斷請求。但不管該標志為何值,CPU都必須響應CPU外部的不可屏蔽中斷所發出的中斷請求,以及CPU內部產生的中斷請求。具體規定如下:
(1)、當IF=1時,CPU可以響應CPU外部的可屏蔽中斷發出的中斷請求;
(2)、當IF=0時,CPU不響應CPU外部的可屏蔽中斷發出的中斷請求。
CPU的指令系統中也有專門的指令來改變標志位IF的值。
3、方向標志DF(DirectionFlag)
方向標志DF用來決定在串操作指令執行時有關指針寄存器發生調整的方向。具體規定在第5.2.11節——字符串操作指令——中給出。在微機的指令系統中,還提供了專門的指令來改變標志位DF的值。
三、32位標志寄存器增加的標志位
1、I/O特權標志IOPL(I/O Privilege Level)
I/O特權標志用兩位二進制位來表示,也稱為I/O特權級字段。該字段指定了要求執行I/O指令的特權級。如果當前的特權級別在數值上小於等於IOPL的值,那么,該I/O指令可執行,否則將發生一個保護異常。
2、嵌套任務標志NT(Nested Task)
嵌套任務標志NT用來控制中斷返回指令IRET的執行。具體規定如下:
(1)、當NT=0,用堆棧中保存的值恢復EFLAGS、CS和EIP,執行常規的中斷返回操作;
(2)、當NT=1,通過任務轉換實現中斷返回。
3、重啟動標志RF(Restart Flag)
重啟動標志RF用來控制是否接受調試故障。規定:RF=0時,表示“接受”調試故障,否則拒絕之。在成功執行完一條指令后,處理機把RF置為0,當接受到一個非調試故障時,處理機就把它置為1。


在指令中,指定操作數或操作數存放位置的方法稱為尋址方式。微機系統有七種基本的尋址方式:立即尋址方式、寄存器尋址方式、直接尋址方式、寄存器間接尋址方式、寄存器相對尋址方式、基址加變址尋址方式、相對基址加變址尋址方式等。

操作數作為指令的一部分而直接寫在指令中,這種操作數稱為立即數,這種尋址方式也就稱為立即數尋址方式。立即數不能作為指令中的第二操作數。MOV AX, 1234H

指令所要的操作數已存儲在某寄存器中,或把目標操作數存入寄存器。把在指令中指出所使用寄存器(即:寄存器的助憶符)的尋址方式稱為寄存器尋址方式。由於使用寄存器尋址方式可以加快速度所以提倡使用寄存器尋址方式。

指令所要的操作數存放在內存中,在指令中直接給出該操作數的有效地址,這種尋址方式為直接尋址方式。MOV BX, [1234H],此時默認基址存在DS中。MOV ES:[1000H], AX此為明顯給出基址寄存器。

操作數在存儲器中,操作數的有效地址用SI、DI、BX和BP等四個寄存器之一來指定,稱這種尋址方式為寄存器間接尋址方式。該尋址方式物理地址的計算方法如下:

若有效地址用SI、DI和BX等之一來指定,則其缺省的段寄存器為DS;若有效地址用BP來指定,則其缺省的段寄存器為SS(即:堆棧段)。

操作數在存儲器中,其有效地址是一個基址寄存器(BX、BP)或變址寄存器(SI、DI)的內容和指令中的8位/16位偏移量之和,成為寄存器相對尋址方式。其有效地址的計算公式如右式所示:

若有效地址用SI、DI和BX等之一來指定,則其缺省的段寄存器為DS;若有效地址用BP來指定,則其缺省的段寄存器為SS。

操作數在存儲器中,其有效地址是一個基址寄存器(BX、BP)和一個變址寄存器(SI、DI)的內容之和,成為基址加變址尋址方式。如果有效地址中含有BP,則缺省的段寄存器為SS;否則,缺省的段寄存器為DS。

操作數在存儲器中,其有效地址是一個基址寄存器(BX、BP)的值、一個變址寄存器(SI、DI)的值和指令中的8位/16位偏移量之和。其有效地址的計算公式如右式所示:

如果有效地址中含有BP,則其缺省的段寄存器為SS;否則,其缺省的段寄存器為DS。指令中給出的8位/16位偏移量用補碼表示。在計算有效地址時,如果偏移量是8位,則進行符號擴展成16位。當所得的有效地址超過0FFFFH,則取其64K的模。MOV AX, [BX+SI+1000H]。上面所算的所有EA是內存地址的偏移量而非最終地址。

源操作數

指令的變形

源操作數的尋址方式

只有偏移量

MOV AX, [100H]

直接尋址方式

只有一個寄存器

MOV AX, [BX] 或 MOV AX, [SI]

寄存器間接尋址方式

有一個寄存器和偏移量

MOV AX, [BX+100H] 或 MOV AX, [SI+100H]

寄存器相對尋址方式

有二個寄存器

MOV AX, [BX+SI]

基址加變址尋址方式

有二個寄存器和偏移量

MOV AX, [BX+SI+100H]

相對基址加變址尋址方式

32位CPU增加了新的靈活度更高的尋址方式,內存地址的偏移量可分為三部分:一個32位基址寄存器,一個可乘1、2、4或8的32位變址寄存器,一個8位/32位的偏移常量,並且這三部分還可進行任意組合,省去其中之一或之二。32位基址寄存器是:EAX、EBX、ECX、EDX、ESI、EDI、EBP和ESP;32位變址寄存器是:EAX、EBX、ECX、EDX、ESI、EDI和EBP。



在匯編語言中,標號、內存變量名、子程序名和宏名等都是標識符,它一般最多由31個字母、數字及規定的特殊字符(?、@、_、$)等組成,並且不能用數字開頭。通常情況下,匯編語言不區分標識符中字母的大小寫。匯編語言中常用的數據類型有字節、字和雙字。

定義數據變量語句是在程序中經常使用的偽指令語句,其一般格式:[變量名] 數據定義符 表達式1[, 表達式2, …,表達式n] ;注釋。數據定義符一般是DB/DD/DW。DB 1, 3, 5, 7, 9, 11,'o',每一個數字均為16位即一個字節存儲,由引號括起來的字符在內存中是存放其ASCII碼值。他們在內存中連續存儲。MSG1 DB 'I am a student.'定義了一個字符串,存放在內存仍然是一個一個ASCII碼。Word1 DW 89H,1909H, -1定義字變量,內存中存儲形式為89 00 09 19 FF FF。低對低高對高。

匯編程序中除了硬指令,還有給編譯器處理的偽指令。偶對齊偽指令even,告訴匯編程序(Assember)即將匯編源代碼程序編譯成機器指令的程序,本偽指令下面的內存變量從下一個偶地址單元開始分配。對齊偽指令ALIGN num告訴匯編程序,本偽指令下面的內存變量必須從下一個能被Num整除的地址開始分配,而且num只能是2的倍數。調整偏移量偽指令ORG告訴匯編程序,本偽指令下面的內存變量從該“數值表達式”所指定的地址開始分配。這三個偽指令用在數據定義之間。

重復說明符DUP,即duplicated,一般使用形式為count  DUP  (表達式, 表達式, …, 表達式),count是重復次數,(表達式,表達式, …, 表達式)是被重復的部分,“表達式”可以是存儲單元的初值,也可以是含義另一個DUP的式子。STRING DB 120 DUP('ABCDE'), 0。這類似於數組

用STRUC和ENDS可以把一系列數據定義語句括起來作為一種新的、用戶定義的結構類型。使用形式為:

結構名 STRUC [Alignment][, NONUNIQUE]
數據定義語句序列
結構名 ENDS

其中Alignment為對齊方式。例如:

stri struc

  name dd

  aage  dw

stri ends

與結構體類型對應的還有聯合類型,很想C語言。聯合UNION使用形式:

[聯合類型名] UNION  [Alignment] [,NONUNIQUE]
數據定義語句序列
[聯合類型名] ENDS

記錄類型RECORD類型:記錄名 RECORD 字段[, 字段, ……],“字段”代表:字段名:寬度[=初值表達式]。例如COLOR RECORD BLINK:1,BACK:3=0, INTENSE:1=1, FORE:3


段屬性操作符(SEG)返回該標識符所在段的段地址。例如數據段、代碼段等。例如moc ax,meg score。偏移量屬性操作符(OFFSET)返回該標識符離它所在段的段地址有多少字節,例如mov bx,offset name。類型屬性操作符(TYPE)是返回該變量所占字節數,例如type name。長度屬性操作符(LENGTH)是針對內存變量的操作符,它返回重復操作符DUP中的重復數。如果有嵌套的DUP,則只返回最外層的重復數;如果沒有操作符DUP,則返回1。SIZE 變量 = (LENGTH 變量) × (TYPE 變量)。強制屬性操作符:數據類型 PTR 地址表達式,例如mov byte ptr [bx], 9H。


關系運算符有LT  GT  EQ  NE  LE  GE。邏輯運算符有AND  OR  XOR  NOT  SHL  SHR。各個運算符的優先級:

優先級:高

  LENGTH、SIZE、WIDTH、MASK、()、[]、.(用於結構字段)、<>(用於記錄類型)

PTR、SEG、OFFSET、TYPE、THIS、:(用於段超越前綴)
*、/、MOD、SHL、SHR
HIGH、LOW
+、-
EQ、NE、LT、LE、GT、GE
NOT
AND
OR、XOR

優先級:低

SHORT
等價語句:符號名  EQU  表達式 的作用是左邊的符號名代表右邊的表達式。可以使用符號代表字符串。等號語句類似於賦值語句:符號名=數值表達式。符號名定義語句:符號名 LABEL 類型。


雜項:

數據存儲對齊:數據在內存中存放的時候需要對齊,之所以對齊是為了配合按照塊取數據的機制,為了方便數據的訪問,提高計算機的處理速度,但是對齊會導致內存空間的浪費。例如struct結構體中的數據不會是緊挨着存放的,而是按照各種類型數據的大小,必須在其整數倍位置存放,並不連續,每種OS有自己的規定。對齊是為了提高系統的訪問速度,一般基本的對齊原則是按着最大的基本類型的長度進行對齊,較小的元素可以幾個組合起來填充一段對齊內存,實現基本的對齊。結構體中的元素也要滿足一定的分布條件,就是元素的存儲起始地址要滿足能夠整除該元素類型的長度。所以在設計struct時,應該將大數據放在前面,用小類型數據來放在后面。

高速緩存CACHE的工作原理基於局部性原理。


各CPU特性:



寄存器的分類 寄存器

主 要 用 途

數據

寄存器

AX

乘、除運算,字的輸入輸出,中間結果的緩存

AL

字節的乘、除運算,字節的輸入輸出,十進制算術運算

AH

字節的乘、除運算,存放中斷的功能號

BX

存儲器指針

CX

串操作、循環控制的計數器

CL

移位操作的計數器

DX

字的乘、除運算,間接的輸入輸出

變址
寄存器
SI

存儲器指針、串指令中的源操作數指針

DI

存儲器指針、串指令中的目的操作數指針

變址
寄存器
BP

存儲器指針、存取堆棧的指針

SP

堆棧的棧頂指針

指令指針

IP/EIP  
標志位寄存器 Flag/EFlag  
32位

CPU的

段寄存器

16位CPU的

段寄存器

ES  附加段寄存器
CS  代碼段寄存器
SS  堆棧段寄存器
DS  數據段寄存器
新增加的
段寄存器
FS  附加段寄存器
GS  附加段寄存器

借鑒文章:

http://blog.chinaunix.net/uid-20937170-id-3053573.html

http://www.cnblogs.com/luzhiyuan/p/3587470.html

http://blog.chinaunix.net/uid-23069658-id-3569341.html


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com