第1部分 DOS及DEBUG介紹


轉自:https://www.shiyanlou.com/courses/running/332

一、課程簡介

- 聲明:該課程基於《匯編語言(第2版)》鄭曉薇 編著,機械工業出版社。本節實驗取自教材中第二章的《實例二 進入計算機》。

- 實驗環境:

1.DOS 環境
實驗環境中安裝有dosemu可以模擬DOS環境,並提供DEBUGMASMLINK等匯編語言開發程序。

2.進入DOS和DEBUG
在桌面上雙擊dosemu圖標,直接進入DOS。再做如下操作:

C:\〉D: ——回車后進入D盤 D:\〉CD DOS ——進入DOS子目錄 D:\dos〉DIR ——列出目錄中的文件 D:\dos〉DEBUG ——進入DEBUG 

 

二、進入計算機

微型計算機的字長與微處理器的寄存器位數有關。

以Intel 80X86系列微處理器為例:
CPU是8086/8088、80286的字長是16位(二進制位bit),那么它們的寄存器的位數一定是16位的;
32位字長的微機CPU是80386/80486或者Pentium系列,它們的寄存器的位數則是32位的。

在匯編語言中,數值后面分別用字母B、H、D代表二進制(Binary)、十六進制(Hexadecimal)、十進制數(Decimal)(十進制數可以省略D)。

在計算機中還規定采用字節、字、雙字等單位來表示數據。

字節(Byte):8位二進制數。如00000101B,或表示成05H;10000101B,或表示成85H。

(Word):16位二進制數,等於2字節。如1100010111010110B,或表示成C5D6H。

雙字(Double Word):32位二進制數,又稱為雙精度數,等於4字節。如23456789H。

2.1 8086寄存器組

8086寄存器都是16位的寄存器,根據用途可分為4種類型。分別是數據寄存器、地址寄存器、段寄存器和控制寄存器。如圖所示:

 img

數據寄存器中每個寄存器又可以分為2個8位的寄存器:AH、AL,BH、BL,CH、CL,DH、DL。H表示高字節(高8位)寄存器、L表示低字節(低8位)寄存器。例如 用AX寄存器存放一個字1234H,表示為(AX)=1234H,即高字節12放在AH,低字節34放在AL中。

地址寄存器包括指針和變址寄存器SP、BP、SI、DI四個16位寄存器。顧名思義,它們可用來存放存儲器操作數的偏移地址。另外,它們也可以作為通用寄存器用。

8086CPU有4個16位的段寄存器,分別是CS代碼段寄存器、DS數據段寄存器、ES附加段寄存器、SS堆棧段寄存器。

控制寄存器包括IP和FLAGS(又稱為PSW程序狀態字)兩個16位寄存器,用於控制程序的執行。
IP 指令指針寄存器,用來存放代碼段中的偏移地址,指出當前正在執行指令的下一條指令所在單元的偏移地址。
FLAGS標志寄存器中的某位代表CPU的1個標志,表示出CPU的某種執行狀態。最低位為D0,最高位為D15。8086CPU的標志寄存器共有9個標志,分別為6個條件碼標志和3個控制標志。
如圖:

img

(1)條件碼標志 (D0~D7+D11)

CF 進位標志:當指令執行結果的最高位向前有進位時,CF=1,否則CF=0
PF 奇偶標志:當指令執行結果中1的個數為偶數個時,PF=1,否則PF=0
AF 輔助進位標志:當指令執行結果的第3位(半字節)向前有進位時,AF=1,否則AF=0
ZF 零標志:當指令執行結果為0時,ZF=1,結果不為0時,ZF=0
SF 符號標志:當指令執行結果的最高位(符號位)為負時,SF=1,否則SF=0
OF 溢出標志:當指令執行結果有溢出(超出了數的表示范圍)時,OF=1,否則OF=0

(2)控制標志 (D8~D10)

TF 陷阱標志:在DEBUG調試時,TF=1,采用單步執行方式,即進入陷阱;TF=0,正常執行程序
IF 中斷標志:設置IF=1,允許CPU響應可屏蔽中斷,IF=0則不響應
DF 方向標志:執行串處理指令時,若設置DF=0,存儲單元的地址寄存器的值自動增加,若設置DF=1,存儲單元的地址寄存器的值自動減小

例: 兩個二進制數相加運算,有關標志位自動發生變化。

img

根據計算結果可知CPU會自動地把標志位設為:CF=0,SF=1,ZF=0,OF=0,PF=0,即無進位,結果為負數,結果不為0,沒有溢出,奇數個1。 對溢出的判斷也可以從簡單的角度理解,因為進行運算的二進制數是補碼,可看出本題是一個負數和一個正數相加,結果為負數,不溢出。若兩個正數相加,結果為負數,或者兩個負數相加,結果為正數,那都是溢出了,說明8位補碼已經表示不了該結果。

數的補碼表示:

在計算機中,對帶符號數可用真值和機器數兩個概念表示。真值,就是帶有“+”、“-”號的實際數值;所謂機器數,則是把“+”、“-”符號數值化(0、1)后所得到的計算機實際能表示的數。
機器數有三種碼表示,分別是原碼、反碼和補碼。匯編語言中,數都是以補碼的形式表示的,因此必須掌握數的補碼表示和補碼的運算。這三種碼的定義如下:
原碼:原碼將最高位作為符號位,正數為0,負數為1,其余7位作為數值位。
反碼:正數的反碼與正數的原碼一樣。而求負數的反碼時,符號位為1,數值位在原碼的基礎上求反。
補碼:正數的補碼與正數的原碼一樣。求負數的補碼時,符號位為1,數值位在原碼的基礎上求反加1。
例:  十進制數+5和-5分別表示成二進制數原碼、反碼和補碼:
[+5]原 = [+5]反 = [+5]補 = 00000101B
[-5]原 = 10000101B
[-5]反 = 11111010B
[-5]補 = 11111011B

2.2 內存

在匯編語言中,先要對內存地址和存儲單元的概念進行學習。對存儲單元的標識可以用物理地址或邏輯地址表示。

物理地址是內存單元的真實地址,存儲單元的物理地址是唯一的。Intel8086CPU有20根地址線,因此其存儲空間可達2的20次方=1M個字節單元(1MB)。地址都是從0開始的,在20位地址線的存儲空間中采用十六進制表示的物理地址范圍是00000H~FFFFFH。

邏輯地址是用戶編程時使用的地址,分為段地址偏移地址兩部分。在8086匯編語言中,把內存地址空間划分為若干邏輯段,每段由一些存儲單元構成,每段最大為65536個字節單元。用段地址指出是哪一段,偏移地址標明是該段中的哪個單元。段地址和偏移地址都是16位二進制數。邏輯地址的形式:
段地址:偏移地址

img 

例如:在上圖中,內存划分出了若干段。0號段,1號段,...,每一段都有0號單元、1號單元、2號單元,...。每段的長度可以不一樣,如0號段從0號單元到0FH號單元共16個字節單元,1號段從0號單元到0139H號單元共314個字節單元。用段地址表示段號,偏移地址代表每一段中的單元號,比如0000:0002H代表0號段的2號單元,0001:0002H代表1號段的2號單元,以此類推。因此,偏移地址的通俗含義是在該段內,相對於段地址偏移了多少個單元。

用戶編程時采用的邏輯地址在CPU執行程序時都要轉換成實際的物理地址,這個轉換過程是由CPU中的地址加法器自動完成的。轉換時先將16位的段地址左移4位,相當於乘以16或十六進制的10H,再和偏移地址相加。轉換公式為:
物理地址 = 段地址 × 10H + 偏移地址

例: 若某單元的邏輯地址為0001:0002H,其物理地址 = 0001H×10H + 0002H = 00012H
另一單元的邏輯地址為3020:055AH,其物理地址 = 3020H×10H + 055AH = 3075AH

存儲器邏輯分段類型如下:

代碼段——用於存放指令,段地址存放在段寄存器CS
數據段——用於存放數據,段地址存放在段寄存器DS
附加段——用於輔助存放數據,段地址存放在段寄存器ES
堆棧段——是重要的數據結構,可用來保存數據、地址和系統參數,段地址存放在段寄存器SS

存儲單元中的數據稱為存儲單元內容,一個實際的存儲單元只能存放一個字節(8位二進制)的數據。
存儲單元的地址和內容的表示形式:用括號將地址括起來即代表單元的內容。如

(3075AH)=12H   //表示3075AH號單元中的內容是12H,稱為字節單元;
(37692H)=5678H   //表示37692H單元和37693H單元一起存放5678H,該單元是字單元。

字單元在存儲的時候,高字節放在高地址單元,低字節放在低地址單元,即56H放在37693H單元,78H放在37692H單元。如圖:

  img

有關CPU和存儲單元的概念我們已經了解了,那么如何觀察實際機器內部的情況呢?能不能看到具體的寄存器、標志、存儲單元的內容呢?可不可以修改和控制它們呢?

這一系列的疑問我們可以在調試工具軟件DEBUG的支持下得到解答。通過上機實驗,可加強相關理論概念的理解;而掌握了DEBUG這個有力工具,就可以深入到機器內部進行觀察了。

 

2.3 調試工具DEBUG

在DOS操作系統和Windows操作系統中,都提供了調試工具DEBUG。DEBUG是為匯編語言設計的一種調試工具,它通過單步、設置斷點等方式為程序員提供了非常有效的調試手段。利用它可以觀察和修改CPU的寄存器、內存單元;可以跟蹤程序的運行,發現程序的錯誤。

實驗樓環境中采用dosemu來模擬DOS環境,進入DOS環境中可以直接啟動DEBUG程序。

1. DEBUG的主要命令

DEBUG命令有20多個,我們主要學習最常用的命令(具體見后面)

R ——查看和修改寄存器
D ——查看內存單元
E ——修改內存單元
U ——反匯編,將機器指令變為匯編指令
T /P——單步執行
G ——連續執行程序
A ——輸入匯編指令
Q ——退出

2. 進入DOS

DEBUG要先進入DOS環境中再使用,在實驗樓虛擬環境中進入DOS的方法:(具體操作圖解見實驗樓)

  1. 在桌面上雙擊“Xfce終端”程序進入Linux的命令行終端
  2. 在啟動的Xfce命令行界面中輸入 Dosemu 進入DOS環境,Dosemu 也有其他參數,可以在“Xfce終端”中輸入 Dosemu –help 查看
  3. 退出DOS環境,在DOS中輸入命令 exitemu
  4. 或者在桌面上雙擊dosemu圖標,直接進入DOS

進入后的DOS環境:

image

本書用到的簡單的DOS命令:

cd\ ——首先要用cd\ 退回到根目錄C>下
dir ——顯示文件列表
md hb ——建立hb子目錄
cd hb ——進入hb子目錄
copy d:\dos\masm.exe c:\hb ——將D盤dos目錄下的masm.exe拷貝到C盤hb目錄下
copy d:\dos\link.exe c:\hb ——將D盤dos目錄下的link.exe拷貝到C盤hb目錄下
cd .. ——退回到上一級目錄
e:——進入e盤
cls ——清屏
type——顯示文本文件內容(如type c:\hb\abc.asm)

DOS和DEBUG命令都支持大小寫

3. 進入DEBUG

要觀察計算機內部的情況,可直接進入DEBUG。如果要調試及觀察可執行文件,則要在DEBUG后加上文件名和擴展名.EXE。我們先觀察,因此直接鍵入 DEBUG 進入系統,如圖所示。

image

DEBUG的提示符是小短線- ,在其后輸入命令。

(1)R命令——查看和修改寄存器

R命令有兩種用法:

直接鍵入R——將顯示CPU所有的寄存器和標志位;

修改寄存器——在R后跟寫寄存器名,回車后先顯示寄存器的內容,在冒號后鍵入新的值;再用R命令就可看到修改后的內容了。如圖1所示,將AX寄存器的值改為1234H。

Alt text

圖1:用R命令查看和修改寄存器

由圖可知,由於此時DEBUG進入的是操作系統環境,R命令顯示的是系統下的寄存器的值。可看出,AX、BX、CX、DX均為0,如果將AX寄存器的值修改為1234H,執行R AX之后在冒號后輸入1234即可。注意,DEBUG下的數據都是十六進制數。

再來看四個段寄存器DS、ES、SS、CS的值都是0AFAH,說明現在系統處在同一個邏輯段中(不同的系統環境下,段寄存器的值可能不一樣,dosemu虛擬機中為07BEH)。操作系統根據內存的情況為各段分配段地址,因此每台機器或每次運行時段地址值可能會不一樣。IP指令指針寄存器的值是0100H,表示將要執行的指令在代碼段的0100H單元中。該指令單元的邏輯地址應該由CS:IP構成,即0AFA:0100H。

我們來看在寄存器的下面那一行的表示。該行顯示的是代碼段的一條指令的反匯編。所謂反匯編指的是將二進制的機器指令顯示成匯編指令。由三部分構成:最左邊0AFA:0100表示該指令所在單元的邏輯地址,中間1E表示該指令的機器碼,第3列顯示為匯編指令PUSH DS,該指令的作用是將DS入棧。(dosemu虛擬機中為TEST測試指令)。 通過DEBUG,我們就可知道一條匯編指令翻譯成機器代碼是什么值了;反之也一樣,對一條機器指令也可得知它代表什么匯編指令。

在圖的右邊顯示的是CPU標志寄存器各標志位的狀態,可對照表2-1觀察一下現在系統的狀態。

Alt text

(2)D命令——查看內存單元

內存每16個字節單元為一小段,邏輯段必須從小段的首址開始。用D命令可以查看存儲單元的地址和內容。

D命令格式為:

D 段地址:起始偏移地址 [結尾偏移地址] 

例如:

D DS:0      //查看數據段,從0號單元開始
D ES:0      //查看附加段,從0號單元開始
D DS:100    //查看數據段,從100H號單元開始
D 0200:5 15   //查看0200H段的5號單元到15H號單元(在虛擬機上該命令不能執行)

D命令的執行情況如圖2所示

Alt text

圖2:用D命令查看存儲單元

其中左邊一列為邏輯地址,中間部分為存儲單元的內容。每行為16個字節單元,中間的小橫線用於區分前8個單元和后8個單元。在邏輯地址中只給出每行第一個單元的偏移地址,其余15個單元的偏移地址沒有標出。可以推斷出圖中第一行單元的偏移地址從0000H到000FH,第二行單元的偏移地址為0010H~001FH,以此類推。右邊部分顯示出內存單元中的ASCII碼表示的字符,無法顯示時用小點代替。

圖2中:

第一條D命令顯示的是數據段存儲單元的內容,可以看到數據段的段地址為DS,其值0B05H。0號單元的內容為CDH,1號單元為20H ,…,第15號單元的內容為03H;第二行0010H號(16號)單元的內容為69H,它是小寫字母i的ASCII碼,因此右邊區域中顯示了i ,表示該單元的值69H可以看成ASCII碼。

第二條D命令顯示0200H段中的內容,也是從0號單元開始。

第三條D命令從0200H段的5號單元開始顯示直到15H號單元。

如果在D后面直接寫出偏移地址,則顯示當前數據段下偏移地址開始的內存單元,如:

D 10    //從數據段10H號單元開始顯示
D100    //從數據段100H號單元開始顯示

注意:多次鍵入D,可連續顯示后面的單元內容。

(3)E命令——修改內存單元

用E命令可以改寫多個存儲單元的內容。格式為:E 起始地址 修改值 修改值 …

例如:將數據段中的DS:3~DS:5 三個單元的內容修改為14、15、16。命令為

E DS:3 14 15 16

如圖3所示

Alt text 

圖3:用E命令修改存儲單元

用D DS:0命令顯示后,可以看到,這三個單元的值由原來的9F 00 9A修改為14 15 16。

如果E后面直接跟偏移地址,則修改當前數據段下偏移地址所指單元值;還可以用E命令修改其它段的存儲單元內容。

E 10        //修改當前數據段10H號單元內容
E ES:100    //修改附加段100H號單元內容
D ES:100    //查看一下100H單元的內容是否修改了
(4)U命令 ——反匯編

程序員編寫的匯編語言源程序經過匯編(編譯)后生成了二進制的機器指令代碼,而U命令可將二進制的機器指令變為助記符形式的匯編指令,因此稱之為“反匯編”。通過U命令,我們可以得到機器指令與匯編指令的對照,了解機器指令的存儲情況,如圖4所示

Alt text

圖4:用U命令顯示匯編程序段(可見機器指令與匯編指令的對照)

左邊為代碼段中存儲單元的邏輯地址,段地址CS的值為0AFEH,偏移地址從0100H開始。緊靠偏移地址的一列為機器指令代碼,右邊部分是機器指令對應的匯編指令。例如第一行中,機器指令為7419H,它對應的匯編指令為JZ 011B,該指令是條件轉移指令,表示當結果為0時跳轉到偏移地址011BH單元中的指令繼續執行。而0AFE:011BH單元的指令為MOV BX,0034,是一條傳送指令。(dosemu虛擬機中是另一組不同的指令)。

注意:多次鍵入U,可連續顯示后面的程序部分。

U后跟偏移地址,則從該地址開始反匯編。如:

U 0      //從代碼段0號單元開始反匯編
U100     //從代碼段100H號單元開始反匯編

需要注意的是,圖4中顯示的程序代碼並不是用戶編寫的程序,因為在輸入DEBUG命令時沒有寫用戶程序名.EXE。
這段程序代碼是系統代碼段中保存的內容,有可能是系統程序,也有可能是無效的代碼。

(5)A 命令——輸入匯編指令

在DEBUG中,使用A命令可以輸入匯編指令,系統自動地將鍵入的匯編指令翻譯成機器代碼,並相繼地存放在從指定地址開始的存儲區中。由於DEBUG下的數值默認為十六進制數,因此先要將十進制數轉換成十六進制數。

例如,計算Z=35+27的匯編指令為:

MOV  AX,23H
ADD  AX,1BH
MOV  [0000],AX

加法的結果Z=62=3EH。變量Z用存儲單元[0000]表示。這三條指令可在DEBUG下用A命令直接輸入。

輸入A命令后,系統自動地給出邏輯地址為0AEE:0100(CS:偏移地址),在其后輸入匯編指令,回車后可輸入下一條指令,直接回車則退出輸入。操作過程如圖5所示:

Alt text

圖5:用A命令輸入匯編指令

也可以在A命令后給出指令的存放地址,如A CS:0000,表示從代碼段的0號單元開始存放輸入的指令。

(6)T/P命令——單步執行

輸入完指令后,應該執行它。T命令可以一條一條地執行指令。P命令的作用與T命令相同,當遇到中斷指令INT n和調用指令CALL時,應該使用P命令,以確保程序正常執行。這是因為INT n指令和CALL指令都要轉移到子程序去執行,T命令進入子程序后可能無法返回;而P命令則直接執行該指令,並將結果帶回。遇到循環指令LOOP時也應該使用P命令,可以使循環快速結束。

本次執行前,先用R命令查看指令指針寄存器IP的值是否為0100,如果不是,用R IP命令修改為0100。表示現在要從CS:0100單元開始執行指令。T命令每執行一次,都要顯示當前寄存器的狀況,我們可以隨時了解指令的執行情況。計算Z=35+27的匯編指令的執行過程,如圖6所示

Alt text

圖6:用T命令單步執行三條指令

查看執行結果:第一次執行T命令后,AX寄存器的值改為0023,第二次執行后,AX的值變成003E了,說明已經執行完加法ADD指令了,第三次執行T后,寄存器的值並未發生變化,說明第三條指令沒有對寄存器操作。第三條指令MOV [0000],AX是把結果保存到數據段的存儲單元0號字單元中,用D DS:0命令查看該單元的值已經為003EH了(兩個字節單元為一個字單元)。

T命令還可以連續執行多條指令。如上例中連續執行3條指令,可用如下T命令:

-T 3

T命令也可以設置開始地址和執行條數。如上例中從0100H開始連續執行3條指令,可用如下T命令:

-T =0100  3
(7)G命令——連續執行程序

有關連續執行命令G的用法我們放到后面章節中學習。

(8)Q命令 ——退出DEBUG

鍵入Q,回車后退出DEBUG,返回到DOS下。

提示:DEBUG的更多命令及用法參見本書附錄C。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM