1. 程式人生 > >寄存器與代碼段

寄存器與代碼段

bsp ins bubuko 編程 組合 二進制 .com 分享圖片 spa

匯編語言系列學習筆記:

  • 匯編語言初探
  • 寄存器與代碼段(本文)
  • 寄存器與數據段(待完成)
  • 寄存器與棧段(待完成)

在上一篇博文中主要介紹了學習匯編語言的一些必備知識。其中和這篇文章聯系比較緊密的是內存地址單元與 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 中的寄存器來完成的

(完)

寄存器與代碼段