匯編語言系列學習筆記:
- 匯編語言初探
- 寄存器與代碼段(本文)
在上一篇博文中主要介紹了學習匯編語言的一些必備知識。其中和這篇文章聯系比較緊密的是內存地址單元與 CPU 的概念,不熟悉的可以先行閱讀上一篇博文。
在學習寄存器這兩章內容的時候,首先要牢記一個觀點:指令和數據在內存單元中沒有任何區別,它們都是一些二進制信息。
CPU 在讀取內存中二進制信息的時候,將有的信息看作指令,有的信息看作數據。
在接下來的三篇博文中將具體介紹 CPU 到底是根據什么來做出的這種區分的。
一、寄存器的概念
寄存器是位於 CPU 內部的一種帶有存儲性質的器件。寄存器在匯編語言中有着舉足輕重的地位,因為程序員可以通過改變寄存器中的內存來實現對 CPU 的控制。
8086CPU 中總有有 14 種不同種類的寄存器,它們分別是:AX、BX、CX、DX、SI、DI、SP、BP、IP、CS、SS、DS、ES、PSW。
它們最大能存儲 16bit 的數據。
接下來的幾篇文章將逐個的介紹這些寄存器的作用。
(一)通用寄存器
8086CPU 中的通用寄存器有下面四種:
- AX(accumulator):累加寄存器,常用於運算。
- BX(base):基址寄存器,常用於地址索引。
- CX(count):計數寄存器。
- DX(data):數據寄存器,常用於數據傳遞。
從上圖可知,一個 16 位寄存器可以存儲一個 16 位數據。由於 8086CPU 上一代的寄存器都是 8 位的,為了保證兼容性,一個 16 位通用寄存器通常還能當做兩個獨立的 8 位寄存器使用。
比如,AX 可以分為 AH 和 AL,見下圖:
AX 的低 8 位(0 位 ~ 7 位)構成了 AL 寄存器,高 8 位(8 位 ~ 15 位)構成了 AH 寄存器。
8086CPU 可以一次性處理這兩種不同長度的數據,分別稱為:
- 字(word):16 位
- 字節(byte):8 位
(二)段寄存器和指針寄存器
8086CPU 中的段寄存器和指針寄存器有下面四種:
- CS(code segment):代碼段寄存器
- DS(data segment):數據段寄存器
- SS(stack segment):棧段寄存器
- ES(extra segment):附加段寄存器
- IP(instruction pointer):指令指針寄存器
- SP(stack pointer):棧指針寄存器
- BP(base pointer):基址指針寄存器
其中 CS 和 IP 是本文着重要介紹的,其余的將在后面學習到。
首先想一想 “ 段 ” 這個概念從何而來?這就要從 8086CPU 與內存之間的地址總線寬度說起了。
8086CPU 的地址總線寬度是 20 位,即一次性可以傳送 20 位的地址,理論上能達到 1MB 的尋址能力。但是我們上面介紹的寄存器最高也只有 16 位,無法直接生成 20 位的地址。
為了不白白的浪費 4 位地址總線,在 8086CPU 中采用一種將兩個 16 位地址合成一個 20 位地址的方法。
如圖所示,在 8086 中是通過一個地址加法器來完成的這種轉換:物理地址(20 bit) = 段地址(16 bit) × 16 + 偏移地址(16 bit)。其中段地址就存儲在段寄存器中。而偏移地址則保存在指針寄存器中。
這個公式隱含着兩個注意點:
- 因為 段地址 × 16 的大小必然是 16 的倍數,所以一個段內存空間的起始地址必然也是 16 的倍數。
- 因為偏移地址為 16 位,所以一個段的最大空間只有 216 B = 64 KB。
這里有一個因果關系要明確:首先是因為 CPU 與內存之間的地址總線的寬度(1MB)高於 CPU 一次性能處理、傳輸、暫存的最大寬度(64KB),為了不浪費 CPU 的尋址能力,才會有 物理地址(20 bit) = 段地址(16 bit) × 16 + 偏移地址(16bit) 這樣的一個轉換機制。
所以我在想,要是做個假設,CPU 中的寄存器都是 20 bit,或者地址總線只有 16 bit 的話,是不是也許就沒有段地址這個說法了(這是我個人的思考,如果有不對的地方,煩請指正~)。
二、代碼段
上面講了一些比較常用的寄存器,其中 CS 和 IP 寄存器是兩個最為關鍵的寄存器,它們這兩個寄存器中的值組合起來 CS:IP 表示了 CPU 當前要讀取指令的地址。
也就是說:在 8086PC 機中,任意時刻,CPU 將 CS:IP 指向的內容當做指令執行。
為了接下來的講解,先學習幾條會用到的匯編指令:
- mov ax,4E20H:將 4E20H 這個數送入寄存器 AX。
- add ax,1406H:將寄存器 AX 中的數值加上 1406H。
假設現在有下面四條匯編指令:
- mov ax,0123H
- mov bx,0003H
- mov ax,bx
- add ax,bx
對應的機器指令為:
- B8H 23H 01H
- BBH 03H 00H
- 89H D8H
- 01H D8H
現在的一個編程需要是想讓 CPU 順序執行上面四條指令,可以將這四條指令的機器碼存放在一組連續的、起始地址為 16 的倍數的一組內存單元中,如下圖:
這樣我們就定義了一個所謂的代碼段,這個代碼段從內存的第 20000H 號單元開始,存放了 10 字節的指令。
要想讓 CPU 執行這段代碼,首先需要將 CS 的內容置為 2000H,IP 的內容置為 0000H。這樣 CPU 就從內存單元的 20000H 處開始執行。
下面以一張動圖來演示 CPU 執行第一條指令時 CPU 與內存的信息交互情況:
(動圖演示)
這張動圖清晰的展示了 CPU 是如何執行處於上面內存代碼段中的第一條指令(隱藏了很多的細節)。由於指令的執行過程類似,加上制作動圖比較耗費時間,就省略了剩余的三條指令的執行過程(- -!)。
三、總結
本篇博文首先介紹了 CPU 中的寄存器種類,通過一個地址轉換公式引出了兩個重要的寄存器 CS 和 IP。有了這兩個寄存器的功能做支持,就可以定義一個存放代碼的代碼段,並讓 CPU 去執行這個代碼段。
最后還是引出文章開始的一句話:指令和數據在內存中沒有區別,它們都是一些二進制信息,把這些二進制信息看作指令還是數據,是讓編程人員通過控制 CPU 中的寄存器來完成的。
(完)