二、寄存器
水滴石穿
一個典型的CPU由運算器、控制器、寄存器等器件構成,這些器件靠內部總線相連
內部總線實現CPU內部各個器件之間的聯系,外部總線實現CPU和主板上其他器件的聯系
簡單說,在CPU中:
- 運算器進行信息處理
- 寄存器進行信息存儲
- 控制器控制各種器件進行工作
- 內部總線連接各種器件,在它們之間進行數據的傳送
對于一個匯編程序員來說,CPU的主要部件是寄存器。寄存器是CPU中程序員可以用指令讀寫的部件。
程序員可以通過改變各種寄存器中的內容來實現對CPU的控制。
不同的CPU,寄存器個數、結構是不相同的。
8086CPU有14個寄存器,每個寄存器都有一個名稱。
分別是:AX、BX、CX、DX、SI、DI、SP、BP、IP、CS、SS、PSW
2.1 通用寄存器
-
8086CPU的所有寄存器都是16位的,可以存放兩個字節
-
AX、BX、CX、DX這四個寄存器通常用來存放一些一般性的數據,被稱為通用寄存器
-
8086CPU的上一代CPU中的寄存器都是8位的,為了保證兼容,使原來基于上代CPU編寫的程序稍加修改就可以運行在8086之上
-
8086CPU的AX、BX、CX、DX這四個寄存器都可以分為兩個獨立使用的8位寄存器來用:
- AX可分為AH和AL;
- BX可分為BH和BL;
- CX可分為CH和CL;
- DX可分為DH和DL;
-
AX的低8位(0位~7位)構成了AL寄存器
-
AX的高8位(8位~15位)構成了AH寄存器
-
AH和AL寄存器是可以獨立使用的8位寄存器
2.2 字在寄存器中的存儲
出于對兼容性的考慮,8086CPU可以一次性處理以下兩種尺寸的數據
- 字節:記為Byte,一個字節有8個bit組成,可以存在8位寄存器中
- 字:記為word,一個字由兩個字節組成,這兩個字節分別稱為這個字的高位字節和低位字節
例如:一個字型數據20000(4E20H)存放在AX寄存器中
-
高位字節AH寄存器中:78(4EH)
-
低位字節AL寄存器中:32(20H)
2.3 幾條匯編指令
匯編指令 | 控制CPU完成的操作 | 用高級語言的語法描述 |
---|---|---|
mov ax,18 | 將18送入寄存器AX中 | AX=18 |
mov ah,78 | 將78送入寄存器AH中 | AH=78 |
add ax,8 | 將寄存器AX中的數值加上8 | AX=AX+8 |
mov ax,bx | 將寄存器BX中的數據送入寄存器AX | AX=BX |
add ax,bx | 將AX和BX中的數值相加,結果存在AX中 | AX=AX+BX |
寫一條匯編指令或一個寄存器的名稱時,不區分大小寫
1、程序段中指令執行情況之一(原AX中的值:0000H,原BX中的值:0000H)
程序段中的指令 | 指令執行后AX中的數據 | 指令執行后BX中的數據 |
---|---|---|
mov ax,4E20H | 4E20H | 0000H |
add ax,1406H | 6226H | 0000H |
mov bx,2000H | 6226H | 2000H |
add ax, bx | 8226H | 2000H |
mov bx,ax | 8226H | 8226H |
add ax,bx | ? | 8226H |
問題2.1 :16位寄存器高位溢出
指令執行后AX中的數據為多少?思考后看分析
044CH,由于AX物理結構決定只能容納16位,因此高位溢出需要舍棄。
分析:程序段中的最后一條指令 add ax,bx,在執行前 ax和 bx中的數據都為 8226H,相加后所得的值為:1044CH,但是ax為16位存器,只能存放4位六進制的數據,所以最高位的1不能在ax中保存,ax中的數據為:044CH。
2、程序段中指令執行情況之二
程序段中的指令 | 指令執行后AX中的數據 | 指令執行后BX中的數據 |
---|---|---|
mov al,001AH | 001AH | 0000H |
mov bx,0026H | 001AH | 0026H |
add al,bl | 0040H | 0026H |
add ah,bl | 2640H | 0026H |
add bh,al | 2640H | 4026H |
mov ah,0 | 0040H | 4026H |
add al,85H | 00C5H | 4026H |
add al,93H | ? | 4026H |
問題2.2:8位寄存器高位溢出
指令執行后AX中的數據為多少?思考后看分析
0058H,由于al是8位寄存器,進行的是8位運算,因此進位值不能在8位寄存器中保存。
分析:程序段中的最后一條指令 add al,93H,在執行前,al中的數據為C5H,相加后所得的值為:158H,但是al為8位寄存器,只能存放兩位十六進制的數據,所以最高位的1丟失,ax中的數據為:0058H。(這里的丟失,指的是進位值不能在8位寄存器中保存,但是CPU并不真的丟棄這個進位值,關于這個問題,我們將在后面的課程中討論。
注意,此時 al是作為一個獨立的8位寄存器來使用的,和ah沒有關系,CPU在執行這條指令時認為 ah和al是兩個不相關的寄存器。不要錯誤地認為,諸如 add al,93H 的指令產生的進位會存儲在ah中,add al,93H進行的是8位運算。
如果執行 add ax,93H,低8位的進位會存儲在 ah中,CPU 在執行這條指令時認為只有一個 16 位寄存器 ax,進行的是 16位運算。指令 add ax,93H 執行后,ax 中的值為:0158H。此時,使用的寄存器是16位寄存器ax,add ax,93H相當于將ax中的16 位數據00c5H和另一個16位數據0093H相加,結果是16位的0158H。
**在進行數據傳送或運算時,要注意指令的兩個操作對象的位數應當是一致的,**例如:
mov ax bx
mov bx,cx
mov ax,18H
mov al,18H
add ax,bx
add ax20000
等都是正確的指令,而:
mov ax,bl (在8位寄存器和16位寄存器之間傳送數據)
mov bh ax (在16位寄存器和8位寄存器之間傳送數據)
mov al,20000 (8位寄存器最大可存放值為255的數據)
add al,100H (將一個高于8位的數據加到一個8位寄存器中)
等都是錯誤的指令,錯誤的原因都是指令的兩個操作對象的位數不一致。
檢測點2.1
(1)寫出每條匯編指令執行后相關寄存器中的值
匯編指令 | 匯編指令執行后寄存器的值 |
---|---|
mov ax,62627 | AX = F4A3H |
mov ah,31H | AX = 31A3H |
mov al,23H | AX = 3123H |
add ax,ax | AX = 6246H |
mov bx,826CH | BX = 826CH |
mov cx,ax | CX = 6246H |
mov ax,bx | AX = 826CH |
add ax,bx | AX = 04D8H |
mov al,bh | AX = 0482H |
mov ah,bl | AX = 6C82H |
add ah,ah | AX = D882H |
add al,6 | AX = D888H |
add al,al | AX = D810H |
mov ax,cx | AX = 6246H |
(2)只能用目前學過的匯編指令,最多使用4條指令,編程計算2的4次方
mov ax,2
add ax,ax
add ax,ax
add ax,ax
2.4 物理地址
CPU訪問內存單元時,要給出內存單元的地址。
所有內存單元構成的存儲空間是一個一維的線性空間,每一個內存單元在這個空間中都有唯一的地址。
這個唯一的地址稱為物理地址、
CPU通過地址總線送入存儲器的,必須是一個內存單元的物理地址。
在CPU向地址總線發出物理地址之前,必須要在內部先形成這個物理地址。
不同CPU可以有不同形成物理地址的方式。
下面討論8086CPU如何在內部形成內存單元的物理地址的。
2.5 16位結構的CPU
概括地講,16位結構(16位機、字長為16位等常見說法,與16位結構的含義相同)
描述了一個 CPU 具有下面幾方面的結構特性:
- 運算器一次最多可以處理16位的數據:
- 寄存器的最大寬度為16位;
- 寄存器和運算器之間的通路為16位。
8086是16位結構的CPU,這也就是說,在8086內部,能夠一次性處理、傳輸、暫時存儲的信息的最大長度是16位的。
內存單元的地址在送上地址總線之前,必須在CPU中處理、傳輸、暫時存放,對于16位 CPU,能一次性處理、傳輸、暫時存儲16位的地址。
2.6 8086CPU給出物理地址的方法
8086CPU有20位地址總線,可以傳送20位地址,達到1MB尋址能力。
8086CPU是16位結構,在內部一次性處理、傳輸、暫時存儲的地址為16位。
從8086CPU的內部結構來看,如果將地址從內部簡單地發出,那么它只能送出16位的地址,表現出的尋址能力只有 64KB。
8086CPU 采用一種在內部用兩個16位地址合成的方法來形成一個20位的物理地址。
如圖2.6所示,當8086CPU要讀寫內存時:
- CPU 中的相關部件提供兩個16位的地址,一個稱為段地址,另一個稱為偏移地址;
- 段地址和偏移地址通過內部總線送入一個稱為地址加法器的部件:
- 地址加法器將兩個16位地址合成為一個20位的物理地址;
- 地址加法器通過內部總線將20位物理地址送入輸入輸出控制電路;
- 輸入輸出控制電路將20位物理地址送上地址總線;
- 20位物理地址被地址總線傳送到存儲器
物理地址 = 段地址X16 + 偏移地址
2.7 地址加法的本質含義
“段地址x16+偏移地址=物理地址”的本質含義是:
- CPU在訪問內存時,用一個基礎地址(段地址x16)和一個相對于基礎地址的偏移地址相加,給出內存單元的物理地址。
- 更一般地說,8086CPU的這種尋址功能是“基礎地址+偏移地址=物理地址”尋址模式的一種具體實現方案。8086CPU中,段地址x16可看作是基礎地址。
2.8 段的概念
內存并沒有分段,段的劃分來自于CPU,由于8086CPU用“基礎地址(段地址x16)+偏移地址=物理地址"的方式給出內存單元的物理地址,使得我們可以用分段的方式來管理內存。例如:數據段、代碼段等由人為劃分,邏輯上劃分,有利于我們靈活編程。
以后,在編程時可以根據需要,將若干地址連續的內存單元看作一個段,用段地址x16定位段的起始地址(基礎地址),用偏移地址定位段中的內存單元。
有兩點需要注意:段地址x16必然是16的倍數,所以一個段的起始地址也一定是16的倍數:偏移地址為16位,16位地址的尋址能力為64KB,所以一個段的長度最大為64KB。
內存地址單元小結
CPU訪問內存單元時,必須向內存提供內存單元的物理地址。8086CPU在內部用段地址和偏移地址移位相加的方法形成最終的物理地址。
(1)觀察下表,思考一下有什么結論
物理地址 | 段地址 | 偏移地址 |
---|---|---|
21F6H | 2000H | 1F60H |
2100H | 0F60H | |
21F0H | 0060H | |
21F6H | 0000H | |
1F00H | 2F60H |
結論:
CPU可以用不同的段地址和偏移地址形成同一個物理地址。
比如 CPU 要訪問 21F60H 單元,則它給出的段地址 SA 和偏移地址 EA滿足 SAX16+EA=21F60H 即可。
段地址:Segment Address
偏移地址:Offset Address
有效地址:Effective Address
(2) 如果給定一個段地址,僅通過變化偏移地址來進行尋址,最多可定位多少個內存單元?
結論:
偏移地址16位,變化范圍為0-~FFFFH,僅用偏移地址來尋址最多可尋64KB個內存單元。
比如給定段地址1000H,用偏移地址尋址,CPU的尋址范圍為:10000H~1FFFFH。
在8086PC機中,存儲單元的地址用兩個元素來描述,即段地址和偏移地址。
“數據在 21F60H內存單元中。”這句話對于8086PC機一般不這樣講,取而代之的是兩種類似的說法:
- ①數據存在內存2000:1F60單元中;
- ②數據存在內存的2000H段中的1F60H單元中。
這兩種描述都表示“數據在內存21F60H單元中”
可以根據需要,將地址連續、起始地址為16的倍數的一組內存單元定義為一個段。
檢測點2.2
(1)給定段地址為 0001H,僅通過變化偏移地址尋址,CPU的尋址范圍為 到 。
段地址x16 + 偏移地址
偏移地址范圍:0~FFFFH
故CPU的尋址范圍為00010H~1000FH
(2)有一數據存放在內存 20000H單元中,現給定段地址為 SA,若想用偏移地址尋到此單元。則 SA應滿足的條件是:最小為 ,最大為 。
提示,反過來思考一下,當段地址給定為多少,CPU無論怎么變化偏移地址都無法尋到 20000H 單元?
偏移地址為最大值 FFFFH 時,段地址x16最小為20000H - FFFFH = 10001H,16進制右移1位,SA = 1001H
偏移地址為最小值 0H 時,段地址x16最大值為20000H,16進制右移1位,SA = 2000H
2.9 段寄存器
8086CPU在訪問內存時,要由相關部件提供內存單元的段地址和偏移地址,送入地址加法器合成物理地址
段地址在8086CPU的段寄存器中存放
8086CPU有4個段寄存器:CS、DS、SS、ES
CS(Code Segment):代碼段寄存器;
DS(Data Segment):數據段寄存器;
SS(Stack Segment):堆棧段寄存器;
ES(Extra Segment):附加段寄存器
2.10 CS和IP
- CS和IP是8086CPU中兩個最關鍵的寄存器,它們指示了CPU當前要讀取指令的地址
- CS為代碼寄存器,IP為指令指針寄存器
在8086PC機中,任意時刻,設CS中的內容為M,IP中的內容為N,8086CPU將從內存 Mx16+N 單元開始,讀取一條指令并執行。
也可以這樣表述:8086機中,任意時刻,CPU將CS:IP指向的內容當作指令執行。
指令執行流程:
- CPU根據CS:IP提供的基址和偏址(基址x16+偏址)在內存中讀取到要執行的指令
- CS:IP中的內容送入地址加法器
- 地址加法器將物理地址送入輸入輸出控制電路
- 輸入輸出控制電路將物理地址送上地址總線
- 找到對應物理地址上的機器指令通過數據總線送入CPU
- 輸入輸出控制電路將機器指令送入指令緩沖器
- IP中的值自動增加(讀取到一條指令后,IP中的值自動增加,以使CPU可以讀取下一條指令;讀取指令多長,IP加上多少)
- 執行控制器執行指令
總結:
- 從CS:IP指向的內存單元讀取指令,讀取的指令進入指令緩沖器
- IP=IP+所讀取指令的長度,從而指向下一條指令
- 執行指令。轉到步驟1,重復這個過程
現在我們可以回到之前的問題上,在內存中,數據和指令都表現為二進制的形式,二者沒有區別。
學習了CS:IP后,我們可以認為,CPU將CS:IP指向的內存單元中的內容看作指令。
因為任何情況下,CPU將CS、IP中的內容當做指令的段地址和偏移地址,用它們合成指令的物理地址,到內存中讀取指令碼,執行。
2.11 修改CS、IP的指令
在CPU中,程序員能夠使用指令讀寫的部件只有寄存器,程序員可以通過改變寄存器中的內容實現對CPU的控制。
CPU從何處執行指令是由CS、IP中的內容決定的,程序員可以通過改變CS、IP中的內容來控制CPU執行目標指令:轉移指令。
例如:jmp指令
- **jmp 段地址:偏移地址 :**用指令中給出的段地址修改CS,偏移地址修改IP
- **jmp (某一合法)寄存器:**用寄存器中的值修改IP,jmp ax = mov IP,ax
問題2.3
分析:
(1)先找CS:IP指向的地址:CPU的初始狀態CS=2000H,IP=0000H;指向20000H,取出指令B8 22 66(mov ax,6622H),IP=IP+3=0003H
(2)指令執行后,CS=2000H,IP=0003H;指向20003H,取出指令EA 03 00 00 10(jmp 1000:3),跳轉到1000:3,CS=1000H,IP=0003H
(3)指令執行后,CS=1000H,IP=0003H;指向10003H,取出指令B8 00 00(mov ax,0000),IP=IP+3=0006H
(4)指令執行后,CS=1000H,IP=0006H;指向10006H,取出指令8B D8(mov bx,ax),IP=IP+2=0008H
(5)指令執行后,CS=1000H,IP=0008H;指向10008H,取出指令FF E3(jmp bx),IP=IP+2=000AH
(6)指令執行后,CS=1000H,IP=0000H;CPU從內存10000H處讀取指令······
經分析后,可知指令執行序列為:
(1)mov ax,6622H
(2)jmp 1000:3
(3)mov ax,0000
(4)mov bx,ax
(5)jmp bx
(6)mov ax,0123H
(7)轉到第3步執行
2.12 代碼段
代碼段是人為在邏輯上定義的,將一段內存地址視作為一個代碼段
CPU并不能知道代碼段,CPU只是按照CS:IP執行指令
小結
(1)段地址在8086CPU的段寄存器中存放。當8086CPU要訪問內存時,由段寄存器提供內存單元的段地址。8086CPU有4個段寄存器,其中CS用來存放指令的段地址。
(2)CS存放指令的段地址,IP存放指令的偏移地址。
8086機中,任意時刻,CPU將CS:IP指向的內容當作指令執行。
(3)8086CPU的工作過程:
①從CS:IP指向的內存單元讀取指令,讀取的指令進入指令緩沖器;
②IP指向下一條指令;
③ 執行指令。(轉到步驟①,重復這個過程。)
(4)8086CPU提供轉移指令修改CS、IP的內容。
檢測點2.3
下面的3條指令執行后,CPU 幾次修改 IP?都是在什么時候?最后IP中的值是多少?
mov ax,bx
sub ax,ax
jmp ax
分析:
(1)IP為初始狀態,CS:IP指向第一條指令的位置:mov ax,bx
(2)指令執行完成后,IP=IP+3,CS:IP指向第二條指令的位置:sub ax,ax
(3)指令執行完成后,IP=IP+3,CS:IP指向第三條指令的位置:jmp ax
(4)指令執行完成后,IP=IP+2,IP=ax=0000H
實驗一 查看CPU和內存
debug的安裝
安裝教程直接百度,大致分為兩部分:dosbox和masm
自動掛載:在dosbox的dos-0.74-3.conf
配置文件的末尾,加上
Mount C E:\dosbox\DOSBox-0.74-3\masm //masm路徑下
C:
debug的命令
命令 | 對應英文單詞 | 說明 |
---|---|---|
R | Register | 查看/修改 CPU 寄存器的內容 |
D | Dump | 查看內存中的內容(十六進制轉儲) |
E | Enter | 改寫內存中的內容(逐字節輸入) |
U | Unassemble | 將機器指令反匯編成匯編指令(反編譯) |
T | Trace | 單步執行一條機器指令(跟蹤執行) |
A | Assemble | 以匯編格式在內存中寫入機器指令(匯編) |
P | Proceed | 執行子程序/循環直到返回(過程步進) |
補充說明:
- P (Proceed):用于執行 CALL、LOOP、INT 等指令時,直接運行完整個子程序/中斷/循環并停在返回后的下一條指令(與 T 的單步區分)。
- 歷史背景:這些命令縮寫源于 1980 年代的 DOS DEBUG 工具,至今仍在 x86 調試器(如 Turbo Debugger、GDB)中廣泛使用。
1、R命令
用R命令修改寄存器AX中的內容
C:>>debug //進入debug模式
-r //查看CPU寄存器內容
AX=0000 BX=0000 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=O73F ES=O73F SS=O73F CS=O73F IP=0100 NU UP EI PL NZ NA PO NC
073F:0100 0000 ADD [BX+SI],AL DS:0000=CD
-r ax //查看并修改AX寄存器內容,此時AX=0000
AX 0000
:1111
-r //查看是否修改成功,此時AX=1111
AX=1111 BX=0000 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=O73F ES=O73F SS=O73F CS=O73F IP=0100 NU UP EI PL NZ NA PO NC
073F:0100 0000 ADD [BX+SI],AL DS:0000=CD
用R命令修改寄存器CS和IP中的內容
-r ip //修改IP寄存器的值
IP 0100
:200
-r
AX=1111 BX=0000 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=O73F ES=O73F SS=O73F CS=O73F IP=0200 NU UP EI PL NZ NA PO NC
073F:0100 0000 ADD [BX+SI],AL DS:0000=CD
-r cs //修改CS寄存器的值
CS O73F
:0B39
-r
AX=1111 BX=0000 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=O73F ES=O73F SS=O73F CS=0B39 IP=0200 NU UP EI PL NZ NA PO NC
073F:0100 0000 ADD [BX+SI],AL DS:0000=CD
2、D命令
用D命令查看內存10000H處的內容,“d 段地址:偏移地址”
Debug會列出1000:0~1000:7F,從指定的內存單元開始的128個內存單元的內容
(1)中間部分是從指定地址開始的128個內存單元的內容
例如:地址1000:0的內存單元內容為72;
? 地址1000:1的內存單元內容為64;
(2)左邊部分是每行的起始地址
(3)右邊是每個內存單元中的數據對應的可顯示的ASCII碼字符
“d 段地址:起始偏移地址 結尾偏移地址”
如:查看1000:0~1000:9的內容
“d 1000:0 9”
3、E命令
用E命令改寫內存中的內容
(1)一次性改寫:e 起始地址 數據 數據 數據 …
要將1000:0~1000:9單元中的內容分別寫為0、1、2、3、4、5、6、7、8、9
用E命令修改從1000:0開始的10個單元的內容
C:>>debug //進入debug模式
-d 1000:0 f
1000:0000 72 64 73 20 63 6F 6D 6D-65 6E 74 73 20 28 72 65 rds comments (re
-
-e 1000:0 0 1 2 3 4 5 6 7 8 9
-d 1000:0 f
1000:0000 00 01 02 03 04 05 06 07-08 09 74 73 20 28 72 65 ..........ts (re
-
(2)一個個改寫:提問式填寫
用E命令修改從1000:10開始的4個單元的內容
-d 1000:10 19
1000:0010 6D 61 72 6B 73 29 20 69-6E 20 marks> in
-e 1000:10
1000:0010 6D.0 61.1 72.2 6B.1C
填0就空格,填其他,直接改寫
(3)直接寫入字符: - e 地址 字符 字符…
C:>debug
-e 1000:0 1 'a' 2 'b' 3 'c'
-
-d 1000:0 f
1000:0000 01 61 02 62 03 63 00 00-00 00 00 00 00 00 00 00 .a.b.c............
-C:>debug
-e 1000:0 1 "a+b" 2 "c++" 3 "IBM"
-
-d 1000:0 f
1000:0000 01 61 02 62 03 63 2B 2B-03 49 42 4D 00 00 00 00 .a+b.c++.IBM.......
-
4、E、U、T命令結合
(1)寫入匯編指令——E命令
練習:如何向內存中寫入機器碼呢?
我們可以用E命令將機器碼寫入內存,比如我們要從內存1000:0單位開始寫入這樣一段機器碼:
機器碼 對應的匯編指令
b80100 mov ax,0001
b90200 mov cx,0002
01c8 add ax,cxC:\>debug
-e 1000:0 b8 01 00 b9 02 00 01 c8
-
(2)查看匯編指令——U命令
C:\>debug
-e 1000:0 b8 01 00 b9 02 00 01 c8
-
-d 1000:0 1f //查看內存的內容,顯示的是機器碼
1000:0000 B8 01 00 B9 02 00 01 C8-03 49 42 4e 00 00 00 00 ..........IBM....
1000:0010 00 02 01 1C 00 00 00 00-00 00 00 00 00 00 00 00 .................-u 1000:0 //將內存中的機器碼反匯編成匯編語言
1000:0000 B80100 MOV AX,0001
1000:0003 B90200 MOV CX,0002
1000:0006 01C8 ADD AX,CX
1000:0008 ...省略
(3)執行寫入的匯編代碼——T命令
- 改CS:IP指向1000:0000
-r cs //修改CS寄存器的值
CS 0B39
:1000
-
-r ip //修改IP寄存器的值
IP 0100
:0
-r //CS:IP成功指向1000:000
AX=0000 BX=0000 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=1000 IP=0000 NU UP EI PL NZ NA PO NC
1000:0000 B80100 MOV AX,0001
- -t 一步步追蹤執行
-t //寄存器AX賦值為1,IP自動加3,上條指令的長度為3,CS:IP始終指向當前要執行的指令
AX=0001 BX=0000 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=1000 IP=0003 NU UP EI PL NZ NA PO NC
1000:0003 B90200 MOV CX,0002
-t //寄存器BX賦值為2,IP自動加3,上條指令的長度為3
AX=0001 BX=0000 CX=0002 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=1000 IP=0006 NU UP EI PL NZ NA PO NC
1000:0006 01C8 ADD AX,CX
-t //寄存器AX賦值為3,IP自動加2,上條指令的長度為2
AX=0003 BX=0000 CX=0002 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=1000 IP=0008 NU UP EI PL NZ NA PO NC
1000:0008 40 INC AX
5、A命令
在前面我們寫入匯編指令時,是以機器碼的形式寫入,這明顯不利于程序員進行編寫匯編程序。
因此,這里可以引入A命令來幫助我們。
用A命令以匯編指令的形式在內存中寫入機器指令。
C:\>debug
-a 1000:0
1000:0000 這里可以輸入匯編指令,輸入mov ax,1,按enter鍵繼續
1000:0003 再按一次enter鍵結束
-示例:
-a 1000:0
1000:0000 mov ax,1
1000:0003 mov bx,2
1000:0006 mov cx,3
1000:0009 add ax,bx
1000:000B add ax,cx
1000:000D add ax,ax
1000:000F enter鍵退出
-
-u 1000:0 //查看匯編指令
實驗任務
任務1
使用Debug,將下面的程序段寫入內存,逐條執行,觀察每條指令執行后CPU中相關寄存器中內容的變化。
機器碼 匯編指令
b8 20 4e mov ax,4E20H
05 16 14 add ax,1416H
bb 00 20 mov bx,2000H
01 d8 add ax,bx
89 c3 mov bx,ax
01 d8 add ax,bx
b8 1a 00 mov ax,001AH
bb 26 00 mov bx,0026H
00 d8 add al,bl
00 dc add ah,bl
00 c7 add bh, al
b4 00 mov ah,0
00 d8 add al,bl
04 9c add al,9CH
提示,可用E命令和A命令以兩種方式將指令寫入內存。注意用T命令執行時,CS:IP 的指向。
(1)用dosbox寫入匯編指令:從2000:0寫入,-a寫入,-u查看
-a 2000:0
2000:0000 mov ax,4E20
2000:0003 add ax,1416
2000:0006 mov bx,2000
2000:0009 add ax,bx
2000:000B mov bx,ax
2000:000D add ax,bx
2000:000F mov ax,001A
2000:0012 mov bx,0026
2000:0015 add al,bl
2000:0017 add ah,bl
2000:0019 add bh,al
2000:001B mov ah,0
2000:001D add al,bl
2000:001F add al,9C
-
-u 2000:0
2000:0000 b8 20 4e mov ax,4E20H
2000:0003 05 16 14 add ax,1416H
2000:0006 bb 00 20 mov bx,2000H
2000:0009 01 d8 add ax,bx
2000:000B 89 c3 mov bx,ax
2000:000D 01 d8 add ax,bx
2000:000F b8 1a 00 mov ax,001AH
2000:0012 bb 26 00 mov bx,0026H
2000:0015 00 d8 add al,bl
2000:0017 00 dc add ah,bl
2000:0019 00 c7 add bh, al
2000:001B b4 00 mov ah,0
2000:001D 00 d8 add al,bl
2000:001F 04 9c add al,9CH
(2)更改CS:IP指向2000:0000
-r cs //修改CS寄存器的值2000
CS 1000
:2000
-
-r ip //修改IP寄存器的值0000
IP 000F
:0
-r //CS:IP成功指向2000:0000
AX=0000 BX=0000 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=2000 IP=0000 NU UP EI PL NZ NA PO NC
2000:0000 B8204E MOV AX,4E20
(3)-t 追蹤指令執行
-t //寄存器AX賦值為4E20,IP自動加3,上條指令的長度為3,IP=0003
AX=4E20 BX=0000 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=2000 IP=0003 NU UP EI PL NZ NA PO NC
2000:0003 051614 ADD AX,1416 -t //寄存器AX+1416為6236,IP自動加3,上條指令的長度為3,IP=0006
AX=6236 BX=0000 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=2000 IP=0006 NU UP EI PL NZ NA PO NC
2000:0006 051614 MOV BX,2000 -t //寄存器BX賦值為2000,IP自動加3,上條指令的長度為3,IP=0009
AX=6236 BX=2000 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=2000 IP=0009 NU UP EI PL NZ NA PO NC
2000:0009 01D8 ADD AX,BX -t //寄存器AX+2000為8236,IP自動加2,上條指令的長度為2,IP=000B
AX=8236 BX=2000 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=2000 IP=000B NU UP EI PL NZ NA PO NC
2000:000B 89C3 MOV BX,AX -t //寄存器AX的內容復制到BX為8236,IP自動加3,上條指令的長度為3,IP=000D
AX=8236 BX=8236 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=2000 IP=000D NU UP EI PL NZ NA PO NC
2000:000D 01D8 ADD AX,BX-t //寄存器BX的內容加到AX為046C,IP自動加2,上條指令的長度為2,IP=000F
AX=046C BX=8236 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=2000 IP=000F NU UP EI PL NZ NA PO NC
2000:000F B81A00 MOV AX,001A-t //寄存器AX賦值為為001A,IP自動加3,上條指令的長度為3,IP=0012
AX=001A BX=8236 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=2000 IP=0012 NU UP EI PL NZ NA PO NC
2000:0012 B81A00 MOV BX,0026-t //寄存器BX賦值為為0026,IP自動加3,上條指令的長度為3,IP=0015
AX=001A BX=0026 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=2000 IP=0015 NU UP EI PL NZ NA PO NC
2000:0015 00D8 ADD AL,BL-t //寄存器BX的低4位加到AX的低四位為26+1A=40,IP自動加2,上條指令的長度為2,IP=0017
AX=0040 BX=0026 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=2000 IP=0017 NU UP EI PL NZ NA PO NC
2000:0017 00DC ADD AH,BL-t //寄存器BX的低4位加到AX的高四位為00+26=26,IP自動加2,上條指令的長度為2,IP=0019
AX=2640 BX=0026 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=2000 IP=0019 NU UP EI PL NZ NA PO NC
2000:0019 00C7 ADD BH,AL-t //寄存器AX的低4位加到BX的高四位為40+00=40,IP自動加2,上條指令的長度為2,IP=001B
AX=2640 BX=4026 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=2000 IP=001B NU UP EI PL NZ NA PO NC
2000:001B B400 MOVE AH,00-t //寄存器AX的高4位賦值為00,IP自動加2,上條指令的長度為2,IP=001D
AX=0040 BX=4026 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=2000 IP=001D NU UP EI PL NZ NA PO NC
2000:001D 00D8 ADD AL,BL-t //寄存器BX的低4位加到AX的低4位為26+40=66,IP自動加2,上條指令的長度為2,IP=001F
AX=0066 BX=4026 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=2000 IP=001F NU UP EI PL NZ NA PO NC
2000:001F 049C ADD AL,9C-t //寄存器AX的低4位加上9C即66+9C=102,但是這里的1是溢出的因此會被截斷,只剩下02//IP自動加2,上條指令的長度為2,IP=0021
AX=0002 BX=4026 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=2000 IP=0021 NU UP EI PL NZ NA PO NC
2000:0021
任務2
將下面3條指令寫入從2000:0開始的內存單元中,利用這3條指令計算2的8次方。
mov ax,1
add ax,ax
jmp 2000:0003
這里就不多贅述了,通過jmp跳轉指令,循環執行ax+ax實現2的8次方效果
任務3
查看內存中的內容。PC機主板上的ROM中寫有一個生產日期,在內存FFFOOH~FFFFFH的某幾個單元中,請找到這個生產日期并試圖改變它。
提示,如果讀者對實驗的結果感到疑惑,.請仔細閱讀第1章中的1.15節。
-d fff0:0 ff
這里是生產日期
因為生產日期是在ROM中,只讀不能寫,不能改變數據;
任務4
向內存從B8100H開始的單元中填寫數據,
如:-e B810:0000 01 01 02 02 03 03 04 04
請讀者先填寫不同的數據,觀察產生的現象;再改變填寫的地址,觀察產生的現象。
提示,如果讀者對實驗的結果感到疑惑,請仔細閱讀第1章中的1.15節。
這里會出現一些有顏色的形狀,但是dosbox好像看不到
這里在虛擬機中配置了一個windows xp,可以看到
這段內存區域估計是顯存地址空間,在顯存寫入數據就會有圖案出現