匯編語言的不同種類
-
as86匯編:能產生16位代碼的Intel 8086匯編
mov ax, cs //cs→ax,目標操作數在前
-
GNU as匯編:產生32位代碼,使用AT&T系統V語法
movl var, %eax // var→%eax,目標操作數在后
-
內嵌匯編,gcc編譯x.c文件會產生中間結果匯編文件
匯編語言的組成
匯編語言由三部分組成:
- 匯編指令。通過編譯器把指令翻譯成機器指令,也就是機器碼
- 偽指令。告訴編譯器如何翻譯
- 符號體系。
+-*/
RAM和ROM
內存最小單元:字節
RAM(Random Access Memory)(隨機存取存儲器):允許讀和寫,斷電后指令和數據就丟失了,直接與cpu交換數據
ROM(Read-Only Memory(只讀存儲器):只允許讀,斷電后指令和數據都存在
CPU中的三條總線
CPU通過地址總線,數據總線和控制總線實現對外部元器件的控制,三種總線的寬度標志了CPU不同方面的性能:
- 地址總線的寬度決定了CPU的尋址能力
- 數據總線的寬度決定了CPU與其他器件進行數據傳輸的能力(一次傳輸的數據量)
- 控制總線的寬度決定了CPU對系統中其他器件的控制能力
8086CPU給出讀取物理地址的方法

- CPU中的相關部件提供兩個16位的地址,一個是段地址,一個是偏移地址
- 段地址和偏移地址通過內部總線送入一個成為地址加法器的部件
- 地址加法器將兩個16位的地址合成為一個20位的物理地址
- 地址加法器通過內部總線將20位物理地址送入輸入輸出控制電路
- 20位物理地址被地址總線傳送到存儲器
物理地址 = 段地址 * 16 + 偏移地址(段地址*16就相當于左移4位)
上述的本質含義是:CPU在訪問內存時,用一個基礎地址和一個相對于基礎地址的偏移地址相加,給出內存單元的物理地址。

為什么非得是基礎地址+偏移地址的思想如上圖所示
段寄存器
由于CPU訪問內存時候需要相關部件提供內存單元的段地址和偏移地址,以便送入地址加法器合成物理地址,因此段寄存器主要提供段地址,8086CPU有4個段寄存器:**CS **
** 、DS、SS、ES**
CS:代碼段寄存器
IP:指令指針寄存器
加入CS中的內容為M,IP中的內容為N,則從內存M*16+N單元開始讀取一條指令并執行。即將CS:IP寄存器指向的內存單元當做指令,CS當做指令的段地址,IP當做偏移地址
總結一下寄存器和段寄存器的種類
寄存器:ax、bx、cx、dx、ah、al、bh、bl、ch、cl、dh、dl、sp、bp、si、di
段寄存器:ds、ss、cs、es
CPU中的棧
段寄存器SS和寄存器SP表示了棧頂的位置,棧頂的段地址存放在SS中,偏移地址存放在SP中。即SS:SP指向棧頂元素
push和pop指令執行時,CPU從SS和SP中得到棧頂的地址。
入棧的時候,棧頂從高地址向低地址方向增長。
8086處理器不會去管理棧頂超界的問題,需要我們自己小心是否會有越界行為。
總結:
源程序和程序
一段源程序包含匯編指令和偽指令,匯編指令是由計算機執行、處理的指令或者數據,一般叫做程序
偽指令就是不由計算機執行,而是編譯器執行的代碼
源程序就是程序+偽指令

程序執行過程的跟蹤
1.obj是目標文件
目標文件要連接外界需要的庫形成可執行文件
可執行文件被操作系統提供的shell程序加載進入內存,然后獲得cpu執行
可執行文件中程序執行完畢后,cpu返還給shell0
[BX]和loop指令
[bx]和[0]有些類似,[0]表示內存單元,其偏移量是0,例如:
-
mov ax, [0]
表示將一個內存單元的內容送入ax中,這個內存單元的長度為2字節,存1個字,偏移地址為0,段地址在ds中
-
mov al, [0]
將一個內存單元的內容送入al中,這個內存單元的長度為1字節,存1個字節,偏移地址為0,段地址在ds中
-
mov ax, [bx]
將一個內存單元的內容送入ax中,這個內存單元的長度為2字節,存1個字,偏移地址在bx中,段地址在ds中
也可以段前綴來表示:
- mov ax,ds:[bx]
表示將一個內存單元的內容送入ax,這個內存單元2個字節,存放1個字,偏移地址在bx中,段地址在ds中
可執行文件的組成
可執行文件由描述信息和程序組成,程序來自于源程序中的匯編指令和定義的數據。描述信息則主要是編譯,連接程序對源程序中相關偽指令進行處理所得到的信息。
數據、指令、棧放入不同的棧
CPU到底如何處理我們定義的段中的內容,是當做指令執行,當做數據訪問還是當做棧空間,完全是靠程序中具體的匯編指令,即:
- CS:IP -----指令
- SS:SP----- 棧
- DS-----數據
與運算和或運算
-
與(and)
這個操作可以將操作對象的相應位置設為0,因為全1才為1。
-
或(or)
該操作可以將操作對象的相應位設為1,因為有1就為1。
[bx+idata]:一種更靈活的指明內存的方式
之前前面說到過用[bx]來指明一個內存單元,我們還可以用一種更為靈活的方式指明內存單元。
[bx+idata]表明一個內存單元,它的偏移地址為bx+idata(bx中的數值加上idata)
比如mov ax, [bx + 200]指的是將一個內存單元的內容送入ax,這個內存單元長2字節,存放1個字,偏移地址為bx中的數值加上200,段地址在ds中
幾種不同的尋址方式
- **[idata]**用一個常量表示地址,可用于直接定位一個內存單元
- **[bx]**用一個變量來表示內存地址,可用于簡介定位一個內存單元
- **[bx+idata]**用一個變量和常量來表示地址,可在一個起始地址的基礎上用變量簡介定位一個內存單元
- **[bx+si]**用兩個變量表示地址
- **[bx+si+idata]**用兩個變量和一個常量表示地址
匯編語言中數據位置的表達
-
立即數(idata)
直接包含在機器指令中的數據(執行前在CPU的指令緩沖器中)
-
寄存器
指令要處理的數據在寄存器中,給出相應寄存器的名就行
-
段地址(SA)和偏移地址(EA)
如果指令要處理的數據在內存中,在匯編指令中用[X]的格式給出SA、EA在某個段寄存器中
轉移指令的原理
可以修改IP或同時修改CS和IP的指令統稱為轉移指令。轉移指令就是可以控制CPU執行內存中某處代碼的指令。
8086CPU的轉移指令分為以下幾類:
-
無條件轉移指令
主要有jmp指令,可以同時修改CS和IP。主要給出兩種信息:
-
轉移的目的地址
-
轉移的距離(段間轉移、段內轉移、段內近轉移)
-
-
條件轉移指令
jcxz指令,所有的有條件轉移指令都是短轉移,對IP的修改范圍是:-128~127
-
循環指令
loop指令,短轉移,對IP的修改范圍是:-128~127循環指令
-
過程
-
中斷
CALL和RET指令
call和ret指令都是轉移指令,他們都修改IP,或同時修改CS和IP。
-
ret和retf
ret指令用棧中的數據修改IP的內容,從而實現近轉移
retf指令用棧中的數據修改CS和IP的內容,從而實現遠轉移
-
call
CPU執行call指令時,有兩步操作:
- 將當前的IP或CS和IP壓入棧中
- 轉移
call指令不能實現短轉移
flag寄存器

-
ZF標志
零標志位,如果執行相關指令后結果為0,zf=1,若不為0,zf=0
對于運算指令如add、sub、mul、div等會影響標志寄存器
對于傳送指令mov、push、pop等不會對寄存器有什么影響
-
PF標志
奇偶標志位。如果執行指令后結果所有bit位中1的個數是偶數,pf=1,為奇數,pf=0
-
SF標志
符號標志位。執行指令后結果如果為負數,sf=1,如果非負數,sf=0。
SF標志就是CPU對有符號數運算的一種記錄,記錄數據的正負。
-
CF標志
進位標志位。在進行無符號數運算的時候,它記錄了運算結果的最高有效位向更高位的進位值,或從更高位的借位值。
當出現進位的時候,會將最高位保存起來,記錄在CF位中
-
OF標志
溢出:在進行有符號數運算時,如果超過了機器所能表示的范圍成為溢出。
溢出標志位。記錄有符號數運算的結果是否發生了溢出,如果溢出of=1,否則of=0
cf和of的區別:cf是對無符號數運算有意義的標志位,of是對有符號數運算有意義的標志位
CPU的內中斷
任何一個通用的CPU都具備一種能力,可以在執行完當前正在執行的指令后,檢測到從CPU外部發送過來的或內部產生的一種特殊信息,并且可以立即對所接收到的信息進行處理。這種特殊的信息,稱為:中斷信息。
中斷表明CPU不再接著向下執行,而是轉去處理這個特殊的信息。
中斷可以來自內部和外部,本書主要討論內中斷
內中斷有以下幾種情況產生:
- 除法錯誤
- 單步執行
- 執行into指令
- 執行int指令
中斷是不同的信息,因此必須先識別不同信息來源。所以中斷信息中必須包含識別來源的編碼,叫做中斷類型碼。這個中斷類型碼是一個字節型數據,可以表示256種中斷信息的來源。
- 中斷過程
- 從中斷信息中獲取中斷類型碼
- 標志寄存器的值入棧(因為在中斷過程中要改變標志寄存器的值,因此先將其保存在棧中)
- 設置標志寄存器的第8位TF和第9位IF的值為0
- CS的內容入棧
- IP的內容入棧
- 從內存地址為中斷類型碼*4和中斷類型碼 *4+2的兩個字單元中讀取中斷處理程序的入口地址設置IP和CS
端口的讀寫
CPU可以直接讀寫一下3個地方的數據:
- CPU內部的寄存器
- 內存單元
- 端口
端口所在的芯片和CPU通過總線相連,所以端口地址和內存地址一樣,通過地址總線來傳送。CPU總共可以定位64KB個不同的端口,因此端口的范圍是0~65535
端口的讀寫指令只有兩條:in和out
外中斷
CPU除了能夠執行指令進行運算以外,還應該能夠對外部設備進行控制,接收它們的輸入,向它們進行輸出。要及時處理外設的輸入,要解決一下兩個問題:
- 外設的輸入隨時可能發生,CPU如何得知
- CPU從何處得到外設的輸入?
答:外設接口芯片中有若干寄存器,CPU將這些寄存器當做端口來訪問。外設的輸入不直接送入內存和CPU中,而是送入相關的接口芯片的端口中;同理,CPU向外設的輸出也不是直接送入外設,而是先送入端口,再由相關芯片送到外設。因此,**CPU通過端口和外部設備進行聯系。**由于外設的輸入隨時可能到達,因此CPU提供中斷機制來滿足這種要求。這種中斷信息來自CPU外部,相關芯片向CPU發出相應的中斷信息,CPU執行完當前的指令后,可以檢測到發送過來的中斷信息,引發中斷過程進而處理外設輸入。
外中斷一共有兩類:
- 可屏蔽中斷。該中斷CPU可以不響應。是否響應要看標志寄存器中IF位的設置,當CPU檢測到可屏蔽中斷信息時,IF=1,則CPU在執行完當前指令后響應中斷,如果IF=0,則不響應可屏蔽中斷。(鍵盤輸入就屬于可屏蔽中斷)
- 不可屏蔽中斷。指CPU必須響應的外中斷,CPU執行完當前指令后,立即響應引發中斷過程。
先送入端口,再由相關芯片送到外設。因此,**CPU通過端口和外部設備進行聯系。**由于外設的輸入隨時可能到達,因此CPU提供中斷機制來滿足這種要求。這種中斷信息來自CPU外部,相關芯片向CPU發出相應的中斷信息,CPU執行完當前的指令后,可以檢測到發送過來的中斷信息,引發中斷過程進而處理外設輸入。
外中斷一共有兩類:
- 可屏蔽中斷。該中斷CPU可以不響應。是否響應要看標志寄存器中IF位的設置,當CPU檢測到可屏蔽中斷信息時,IF=1,則CPU在執行完當前指令后響應中斷,如果IF=0,則不響應可屏蔽中斷。(鍵盤輸入就屬于可屏蔽中斷)
- 不可屏蔽中斷。指CPU必須響應的外中斷,CPU執行完當前指令后,立即響應引發中斷過程。