彙編入門-寄存器

CPU中的主要結構是運算器、控制器與寄存器,這些器件通過CPU的內部總線相連,其中運算器負責信息處理,寄存器負責信息存儲,控制器控制各種器件進行工作,內部總線連接各種器件,在它們之間進行數據的傳送。對於彙編程序員來說,主要部件是寄存器,因爲只有寄存器是我們可以編程直接操作的。不同的CPU架構不同,8086CPU共有14個寄存器,分別是AX、BX、CX、DX、SI、DI、SP、BP、IP、CS、SS、DS、ES、PSW,今天我們先來學習基礎的通用寄存器,其餘的寄存器在用到時會給予說明。

一、通用寄存器
   AX、BX、CX和DX是四個通用寄存器,通常用來存放一般性的數據,後面的分析都在8086CPU中進行。每個通用寄存器是16位,即一次可以處理一個字(2個字節)的數據,但是爲了與8086CPU之前的CPU相容,也支持一個字節的寄存器,即AH與AL,類似的還有BH和BL等,CPU操作時會降AH和AL當作獨立的寄存器,運算進位時會直接丟棄,因爲CPU認爲只有一個8位的寄存器而已:

二、物理地址
   CPU訪問內存需要知曉存儲單元的地址,由於8086CPU地址總線爲20位,但是寄存器卻只有16位,即一次處理的地址最多隻有2的16次冪,遠小於2的20次冪。爲了彌補這個問題,8086CPU採用了一種特殊的方式通過16位的寄存器來構造20位的訪問地址,簡單來說,即:段地址*16+偏移地址。從計算的位數上來說,段地址和偏移地址存儲在CPU寄存器中,都是16位的;段地址*16,即整體在右邊添加4個二進制位,成爲了20位;20位與16位相加,得到了20位的實際內存地址。這裏雖然是8086CPU中的方法,但是其實確實現在所有CPU中的實際尋址算法,即一個基地址加上一個偏移量得到一個實際地址。由此我們可以得到段的概念,內存本身不分段,但是由於CPU的特殊尋址方式,我們可以將內存看作最大64KB的一個個段(16位的最大值正好是64KB),因此我們可以在彙編中人爲的指定段的起始和結束。當然,這裏的段地址和偏移量實際上存儲在CPU的寄存器中,比如獲取指令的CS:IP,其中CS爲代碼段寄存器,其中存儲代碼段的基地址,IP寄存器則存儲着當前要執行的指令的指針,即一個偏移量,因此CS:IP指定了接下來CPU要執行的指令的位置。這裏需要說明的是,內存中的數據對於CPU來說都是二進制位,能夠區分數據和指令的唯一標準就是指令曾經或者正在被CS:IP指定;每執行完一條指令,IP會累加上條指令的長度,從而指向下調指令。

我們是否可以修改控制CS:IP的值呢?答案是肯定的,只不過我們不能使用mov等傳送指令,而應當使用jmp這類轉移指令,基本的用法是:
-1. 修改CS:IP: jmp 2AE3:3    執行後:CS=2AE3H, IP=0003H;
-2. 僅修改IP:jmp ax(ie. move ip, ax)即用寄存器中的值修改IP;

三、內存訪問
   CPU訪問內存除了獲取指令,還要獲取數據,那麼數據部分如何定位的呢?同指令的CS:IP一樣,8086CPU使用DS:[...]來獲取內存數據地址,其中段寄存器存儲內存數據段的基地址,而[...]表示一個內存偏移量指向的內存單元,如[0]表示偏移量爲0的內存單元,這裏使用時要注意,8086CPU不支持直接對DS傳送值,因此mov ds, 1000H是非法的,正確地是通過寄存器來實現,即:mov ax, 1000H; mov ds, ax;
   這部分我們要學習基本的彙編指令,如mov、sub、add等,都可以操作寄存器,操作完之後將數據放入第一個參數表示的寄存器中。CPU中的內存數據一種特殊的結果就是棧,即只能從一端讀寫數據的結構,其基本指令是push ax;將寄存器ax的值入棧;和pop ax;從棧中取出棧頂元素放入寄存器ax中;下面是mov\add\sub命令的一個簡單示例:

然後我們來看看PUSH命令的執行過程:

然後是POP命令:

  可以看出,棧的操作關鍵是棧頂位置的確定,因此CPU專門使用SS:SP來獲取當前內存中棧頂的位置。值得一提的是,CPU本身並沒有對棧的大小進行檢查,因此實際中會出現棧頂越界的問題(上限超出-PUSH;下限超出-POP),這也就要求我們必須人爲進行檢查,否則就會出現程序的漏洞。

發佈了3 篇原創文章 · 獲贊 16 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章