寄存器(内存访问)---汇编学习笔记
寄存器(內存訪問)
序言
第二章,我們主要從CPU如何執行指令的角度講解了8086CPU的邏輯結構、形成物理地址的方法、相關的寄存器以及一些指令。
這一章,我們從訪問內存的角度繼續學習幾個寄存器。
3.1 內存中字的存儲
CPU中,用16位寄存器來存儲一個字。字是有2個內存單元組成。高8位存放高位字節,低8位存放低位字節。
例如:問題 3.1 所描述的。
(1) 0 地址單元中存放的字節型數據是多少?
(2) 0 地址字單元中存放的字型數據是多少?
(3) 2 地址單元中存放的字節型數據是多少?
(4) 2 地址字單元中存放的字型數據是多少?
(5) 1 地址字單元中存放的字型數據是多少?
答案一目了然,分別是20H、4E20H、12H、0012H、124E。
3.2 DS和[address]
CPU要讀寫一個內存單元時,必須給出這個內存單元的地址,內存地址由段地址和偏移地址組成。 DS 存放要訪問數據的段地址, [address] 中address是偏移地址并且是一個具體的數。
這里注意,DS并不能直接給定一個數值。比如 mov ds,1000H 語句在8086CPU中是錯的。我們只能通過寄存器去改變ds的值,比如 mov ds,ax 語句。
問題 3.2
寫幾條指令,將 al 中的數據送入內存單元 10000H 中。
mov ax,1000H ;為了讓ds為1000H,先讓ax為1000H mov ds,ax ;ds只接受寄存器向它傳送的數據 mov al,[0] ;[0]是偏移地址,1000:0的內存單元是10000H3.3 字的傳送
8086CPU是 16 位結構,有16根數據線,所以,可以一次性傳送16位數據,也就是一個字。
問題 3.3
內存中的情況如下圖所示,寫出下面指令執行后寄存器ax,bx,cx中的值。
問題 3.4
內存中的情況如圖所示,寫出下面指令執行后內存中的值。
我們知道高字節放入高地址,低字節放入低地址。也就是[0]的高地址為1000:1,低地址為1000:0。
3.4 mov、add、sub指令
我們在沒什么了解的情況之前就是是要幾個了mov、add、sub等指令。
先了解mov指令的幾種形式:
mov 寄存器,數據 mov 寄存器,寄存器 mov 寄存器,內存單元 mov 內存單元,寄存器 mov 段寄存器,寄存器(1)我們猜想,既然有 mov 段寄存器,寄存器 指令,那么會有mov 寄存器,段寄存器 指令這樣的相反通路嗎?
實驗如下(再此聲明一次:借用了實驗樓的環境):
如圖所示:
- 第一個紅框的 AX 為 0000H;
- 第二個紅框是 DS 為 1000H;
- 第三個紅框發生AX的值改變。
由此可知,mov 寄存器,段寄存器指令是可用的。
(2)同樣,既然有 mov 寄存器,內存單元 ,會擁有 mov 內存單元,寄存器 指令嗎?
實驗如下:
如圖所示,內存單元 1000:0 和 1000:1 發生變化,也就是1000:[0]發生變化。
(3)那么 mov 段寄存器,內存單元 也應該可以。
實驗如下:
發現指令出錯。
同mov一樣, add 和 sub 也有以下幾種形式:
add 寄存器,數據 add 寄存器,寄存器 add 寄存器,內存單元 add 內存單元,寄存器sub 寄存器,數據 sub 寄存器,寄存器 sub 寄存器,內存單元 sub 內存單元,寄存器我們嘗試一下 add 段寄存器,ax 指令,看看可行嗎?
實驗如下:
指令出錯。
3.5 數據段
前面提到,可以根據需要,將一組內存單元定義為一個段。我們可以將一組的長度為N(N<=64KB)、地址連續、起始地址為16的倍數的內存單元當作專門存儲數據的內存空間。
例如將 123B0H~123B9H 的內存單元定義為數據段。現在要累加這個數據段中的前3個單元中的數據,如下:
mov ax,123BH mov ds,ax mov al,0 ;注意,由于題目要求是"單元",而不是"字",所以采用al add al,[0] add al,[1] add al,[2]問題 3.5
寫幾條指令,累加數據段中的前3個字型數據。代碼如下:
mov ax,123BH mov ds,ax mov ax,[0] ;因為這里采用的是"字" add ax,[2] add ax,[4]3.1~3.5 小結
(1)字在內存中存儲時,采用兩個地址連續的內存單元來存放,字的低位字節存放在低地址單元中,高位字節存放在高地址單元中。
(2)用 mov 指令訪問內存單元,可以在 mov 指令中只給出單元的偏移地址,此時,段地址默認在 DS 寄存器中。
(3)[address] 表示一個偏移地址為 address 的內存單元。
(4)在內存和寄存器之間傳送字型數據時,高地址單元和高8位寄存器、低地址單元和低8位寄存器相對應。
(5)mov、add、sub 是具有兩個操作對象的指令。jmp 是具有一個操作對象的指令。
(6)可以根據自己的推測,在 Debug 中實驗指令的新格式。
其實,最麻煩的就是第6點,每種CPU的匯編指令都會有一些不同,所以在針對不同的CPU時需要去猜測所謂的“新格式”。
檢測點 3.1
(1)在 Debug 中,用“d 0:0 1f”查看內存,結果如下。
寫出下面每條匯編指令執行后寄存器的值。
(2)內存中的情況如圖 3.6 所示。
各寄存器的初始值:CS=2000H , IP=0 , DS=1000H , AX=0 , BX=0;
①:我們知道CS=2000H,IP=0,所以從2000:0000處開始執行。因此,代碼如下。
mov ax,6622H jmp 0FF0:0100 ;0FF0:0100 == 1000:0 mov ax,2000H mov ds,ax mov ax,[0008] mov ax,[0002]②:CS:IP的值如下。
| mov ax,6622 | 2000H | 0003H | 6622H | 1000H |
| jmp 0FF0:0100 | OFFOH | 0100H | 6622H | 1000H |
| mov ax,2000H | 0FF0H | 0103H | 2000H | 1000H |
| mov ds,ax | 0FF0H | 0105H | 2000H | 2000H |
| mov ax,[0008] | 0FF0H | 0108H | C389H | 2000H |
| mov ax,[0002] | OFFOH | 010BH | EA66H | 2000H |
③:初步猜測,我認為數據和指令無區別。原因,是因為可以將mov bx,ax當做數據傳送到[0008]內存中。那我們如何確定是數據還是指令呢?當然是通過我們的CS:IP來確認咯,IP指向的第一個值是我們的指令,例如A1是為 mov ax,內存地址 的指令。執行指令后,IP根據指令來確定向后移動幾個位置。(以上是本人的猜想,不知道是否成立)
猜想:CP是時鐘脈沖,以A1為例子,我們知道讀取一個數據需要一個脈沖,A1是需要3個脈沖時間才能完成的操作?
以上是本人猜想,未經過驗證。
3.6 棧
棧是一種具有特殊訪問方式的存儲空間。特殊點在于,數據入棧出棧的次序是“先進后出”或者說“后進先出”(LIFO,Last In First Out)。擁有兩種操作:入棧(PUSH)和出棧(POP)。
3.7 CPU 提供的棧機制
CPU 提供相關的指令來以棧的方式訪問內存空間。說明了,我們可以將一段內存當做棧來使用。(其實我們編程在寫遞歸的時候,總是很經常沒有考慮遞歸基的情況就運行程序,導致內存溢出。我們通過前面所說內存被當做棧來使用,推導出:其實就是棧內存被使用了無限次,導致的內存溢出結果。)
如下所示是棧的操作:
可以看出高地址單元存放高8位,低地址單元存放低8位。
在這里,我們會疑惑!總結一下,大概是兩個問題。
這里給出答案,8086CPU 中,有兩個寄存器SS、IP分別是棧的段地址和偏移地址。在任意時刻,SS:IP 指向棧頂元素。
我們來看看PUSH操作的過程,如圖:
反之,則是POP操作過程,如圖:
我們看到,POP操作并沒有將棧頂之前的值 清 0 。
問題 3.6
如果將 10000H~1000FH 這段空間當做棧,初始狀態棧是空的,此時,SS=1000H,SP=?
答案顯然是最高地址的下一個單元,即10010H。
3.8 棧頂超界的問題
我們知道棧頂的指向有 SS:IP 控制。但并沒有控制這??臻gpop次數過多導致下溢以及push多次導致上溢的檢測。這樣會出現一個問題,我們腦海中的棧空間之外的數據會被棧的pop或者push操作給覆蓋,從而導致一系列的錯誤發生。這非常嚴重,試想一下,如果C語言編寫的一段遞歸程序沒有遞歸基就運行之后,秒級的時候就會講內存占滿,從而導致RAM死機,計算機只能重啟。這也是為什么VC++給程序只分配了4K空間的原因(我記得是4K,若有錯誤請指正)。
因此,我們在編寫匯編程序的時候,需要注意我們的PUSH和POP操作不會導致上溢以及下溢。
3.9 push、pop 指令
push和pop 指令的格式可以是如下形式:
push 寄存器 ;將一個寄存器中的數據入棧 pop 寄存器 ;出棧,用一個寄存器接受出棧的數據 push 段寄存器 pop 段寄存器 push 內存單元 pop 內存單元問題 3.7
編程,將 10000H~1000FH 這段空間當做棧,初始狀態棧是空的,將 AX、BX、DS 中的數據入棧。
問題 3.8
編程:
(1)將 10000H~1000FH 這段空間當作棧,初始狀態棧是空的;
(2)設置 AX=001AH,BX=001BH;
(3)將 AX、BX 中的數據入棧;
(4)然后將AX、BX清零;
(5)從棧中恢復AX、BX原來的內容。
問題 3.9
編程:
(1)將 10000H~1000FH 這段空間當做棧,初始狀態為空;
(2)設置 AX=001AH,BX=001BH;
(3)利用棧,交換 AX 和 BX 中的數據。
問題 3.10
如果要在 10000H 處寫入字型數據 2266H,可以用以下代碼完成:
mov ax,1000H mov ds,ax mov ax,2266H mov [0],ax補全下面的代碼,實現功能:在 10000H 處寫入字型數據 2266H 。
要求:不能使用“mov 內存單元,寄存器”這類指令。
棧的綜述
(1)8086CPU 提供了棧操作機制,方案如下。
- 在 SS、IP 中存放棧頂的段地址和偏移地址;
- 提供入棧和出棧指令,它們根據 SS:SP 指示的地址,按照棧的方式訪問內存單元。
(2)push 指令的執行步驟:
- SP=SP-2;
- 向SS:SP指向的字單元中送入數據。
(3)pop 指令的執行步驟:
- 從 SS:SP 指向的子單元中讀取數據;
- SP=SP+2。
(4)任意時刻,SS:SP 指向棧頂元素。
(5)8086CPU 只記錄棧頂,??臻g的大小我們要自己管理。
(6)用棧來暫存以后需要回復的寄存器的內容時,寄存器出棧的順序要和入棧的順序相反。
(7)push、pop 實質上是一種內存傳送指令,注意它們的靈活應用。
棧是一種非常重要的機制,一定要深入理解,靈活掌握。
3.10 棧段
在編程時,我們可以根據需要,將一組內存單元定義為一個段。我們要注意控制棧不會超界。
問題 3.11
如果將 10000H~1FFFFH 這段空間當作棧段,初始狀態棧是空的,此時,SS=1000H,SP=?
答案很顯然,SP= FFFF+1 = 10000H = 0000H。這是一個64K大小的棧段。
問題 3.12
一個棧最大可以設為多少?為什么?
最大可以設為64K,因為SP的范圍只能是 0000H~FFFFH 之間。
段的綜述
- 數據段,段地址放在DS中,偏移地址[address]。
- 代碼段,段地址放在CS中,偏移地址IP。
- 棧段,段地址放在SS中,偏移地址SP。
例如一段代碼,假設CS=1000H,IP=0000H:
mov ax,1000H mov ss,ax mov sp,0020H mov ax,cs mov ds,ax mov ax,[0] add ax,[2] mov bx,[4] add bx,[6] push ax push bx pop ax pop bx這段代碼給我們的信息是:在 10000H~1001FH這段內存中,既是代碼段,又是棧段和數據段。這樣的代碼可能會出現數據發生錯誤,盡量讓一段內存當做三者中的一種段。
檢測點 3.2
(1)補全下面的程序,使其可以將 10000H~1000FH 中的 8 個字,逆序復制到 20000H~2000FH 中。逆序復制的含義如下圖所示。
(2)補全下面的代碼,使其可以將 10000H~1000FH 中的 8 個字,逆序復制到 20000H~2000FH 中。
;題目代碼 mov ax,2000H mov ds,ax;三行代碼 mov ax,1000H mov ss,ax mov sp,0000H;題目代碼 pop [E] pop [C] pop [A] pop [8] pop [6] pop [4] pop [2] pop [0]實驗 2 用機器指令和匯編指令編程
1. 預備知識:Debug 的使用
- D命令,查看內存數據。
- E命令,修改內存數據。
- A命令,輸入匯編指令。
- U命令,查看匯編程序。
2. 實驗任務
(1)使用 Debug,將上面的程序段寫入內存,逐條執行,根據指令執行后的實際運行情況填空。
mov ax,FFFF mov ds,ax mov ax,2200 mov ss,ax mov sp,0100;填空 mov ax,[0] ;我們不考慮AX與BX的值 add ax,[2] mov bx,[4] add bx,[6]push ax ;研究SP的變化,SP = 00FEH push bx ;SP = 00FCH pop ax ;SP = 00FEH pop bx ;SP = 0100Hpush [4] ;SP = 00FEH push [6] ;SP = 00FCH(2)仔細觀察下圖的實驗過程,然后分析:為什么 2000:0~2000:f 中的內容會發生改變?
我們發現指令 mov ss,ax 被執行后,下一條指令是 mov ax,3123 也就是說 一次T指令對ss操作連同sp也執行了。這變相的說明ss和sp需要連續的改變,也就是mov ss,ax之后必須是mov sp,10。
那我們從中尋找原因:如果ss執行后,不立馬執行sp會發生什么情況?
百度了一下,回答是這樣的,我們的 T指令 是中斷指令,也就是 T指令 執行后需要把相關寄存器信息壓入棧中。那么,我們就知道了,SS之后必須跟SP,否則會出現錯誤。執行后還需要把 T指令 相關的東西壓入棧中,所以出現了一堆數據。比如:0B39 是 DS 的值等。
總結
以上是生活随笔為你收集整理的寄存器(内存访问)---汇编学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 互联网日报 | 天猫双11成交额4982
- 下一篇: 产品经理才看的懂