| 
 | 
 
 
DEBUG是為彙編語系設計的一種高度工具,它通過單步、設定斷點等模式為彙編語系程式員提供了非常有效的除錯手段。 
一、DEBUG程式的呼叫 
在DOS的提示符下,可鍵入指令: 
C:\DEBUG [D:][PATH][FILENAME[.EXT]][PARM1][PARM2] 
其中,檔案名是被除錯檔案的名字。如使用者鍵入檔案,則DEBUG將特殊的檔案裝入存儲器中,使用者可對其進行除錯。若果未鍵入檔案名,則使用者可以用目前存儲器的內容工作,或是用DEBUG指令N和L把需要的檔案裝入存儲器後再進行除錯。指令中的D指定磁碟機PATH為路徑,PARM1和PARM2則為執行被除錯檔案時所需要的指令參數。 
在DEBUG程式調入後,將出現提示符,此時就可用DEBUG指令來除錯程式。 
二、DEBUG的主要指令 
1、顯示存儲單元的指令D(DUMP),格式為: 
_D[address]或_D[range] 
例如,按指定範圍顯示存儲單元內容的方法為: 
-d100 120 
18E4:0100 c7 06 04 02 38 01 c7 06-06 02 00 02 c7 06 08 02 G...8.G.....G... 
18E$:0110 02 02 bb 04 02 e8 02 00-CD 20 50 51 56 57 8B 37 ..;..h..M PQVW. 
7 
18E4:0120 8B 
其中0100至0120是DEBUG顯示的單元內容,左邊用十六進位表示每個位元群組,右邊用ASCII字元表示每個位元群組,·表示不可顯示的字元。這裡沒有指定段位址,D指令自動顯示DS段的內容。若果只指定首位址,則顯示從首位址開始的80個位元群組的內容。若果完全沒有指定位址,則顯示上一個D指令顯示的最後一個單元後的內容。 
2、修改存儲單元內容的指令有兩種。 
·輸入指令E(ENTER),有兩種格式如下:第一種格式可以用給定的內容表來替代指定範圍的存儲單元內容。指令格式為: 
-E address [list] 
例如,-E DS:100 F3'XYZ'8D 
其中F3,'X','Y','Z'和各佔一個位元群組,該指令可以用這五個位元群組來替代存儲單元DS:0100到0104的原先的內容。 
第二種格式則是採用逐個單元相繼修改的方法。指令格式為: 
-E address 
例如,-E DS:100 
則可能顯示為: 
18E4:0100 89.- 
若果需要把該單元的內容修改為78,則使用者可以直接鍵入78,再按"空格"鍵可接著顯示下一個單元的內容,如下: 
18E4:0100 89.78 1B.- 
這樣,使用者可以不斷修改相繼單元的內容,直到用ENTER鍵結束該指令為止。 
·填寫指令F(FILL),其格式為: 
-F range list 
例如:-F 4BA:0100 5 F3'XYZ'8D 
使04BA:0100~0104單元內含特殊的五個位元群組的內容。若果list中的位元群組數超過特殊的範圍,則忽略超過的項;若果list的位元群組數小於特殊的範圍,則重複使用list填入,直到填滿特殊的所有單元為止。 
3)檢查和修改寄存器內容的指令R(register),它有三種格式如下: 
·顯示CPU內所有寄存器內容和標誌位狀態,其格式為: 
-R 
例如,-r 
AX=0000 BX=0000 CX=010A DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000 
DS=18E4 ES=18E4 SS=18E4 CS=18E4 IP=0100 NV UP DI PL NZ NA PO NC 
18E4:0100 C70604023801 MOV WORD PTR [0204],0138 DS:0204=0000 
·顯示和修改某個寄存器內容,其格式為: 
-R register name 
例如,鍵入 
-R AX 
系統將響應如下: 
AX F1F4 
: 
即AX寄存器的目前內容為F1F4,如不修改則按ENTER鍵,否則,可鍵入欲修改的內容,如: 
 
-R bx 
BX 0369 
:059F 
則把BX寄存器的內容修改為059F。 
·顯示和修改標誌位狀態,指令格式為: 
-RF系統將響應,如: 
OV DN EI NG ZR AC PE CY- 
此時,如不修改其內容可按ENTER鍵,否則,可鍵入欲修改的內容,如: 
OV DN EI NG ZR AC PE CY-PONZDINV 
即可,可見鍵入的順序可以是任意的。 
4)執行指令G,其格式為: 
-G[=address1][address2[address3…]] 
其中,位址1指定了執行的起始位址,如不指定則從目前的CS:IP開始執行。後面的位址均為斷點位址,當指令執行到斷點時,就停止執行並顯示目前所有寄存器及標誌位的內容,和下一筆將要執行的指令。 
5)追蹤指令T(Trace),有兩種格式: 
·逐條指令追蹤 
-T [=address] 
從指定位址起執行一條指令後停下來,顯示所有寄存器內容及標誌位的值。如未指定位址則從目前的CS:IP開始執行。 
·多條指令追蹤 
-T [=address][value] 
從指定位址起執行n條指令後停下來,n由value指定。 
6)彙編指令A(Assemble),其格式為: 
-A[address] 
該指令容許鍵入彙編語系語句,並能把它們彙編成機器代碼,相繼地存放在從指定位址開始的存儲區中。必須注意:DEBUG把鍵入的數字均看成十六進位數,所以如要鍵入十進位數,則其後應加以說明,如100D。 
7)反彙編指令U(Unassemble)有兩種格式。 
·從指定位址開始,反彙編32個位元群組,其格式為: 
-U[address] 
例如: 
-u100 
18E4:0100 C70604023801 MOV WORD PTR[0204],0138 
18E4:0106 C70606020002 MOV WORD PTR[0206],0200 
18E4:010C C70606020202 MOV WORD PTR[0208],0202 
18E4:0112 BBO4O2 MOV BX,0204 
18E4:0115 E80200 CALL 011A 
18E4:0118 CD20 INT 20 
18E4:011A 50 PUSH AX 
18E4:011B 51 PUSH CX 
18E4:011C 56 PUSH SI 
18E4:011D 57 PUSH DI 
18E4:011E 8B37 MOV SI,[BX] 
若果位址被省略,則從上一個U指令的最後一條指令的下一個單元開始顯示32個位元群組。 
·對指定範圍內的存儲單元進行反彙編,格式為: 
-U[range] 
例如: 
-u100 10c 
18E4:0100 C70604023801 MOV WORD PTR[0204],0138 
18E4:0106 C70606020002 MOV WORD PTR[0206],0200 
18E4:010C C70606020202 MOV WORD PTR[0208],0202 
或 
-u100 112  
18E4:0100 C70604023801 MOV WORD PTR[0204],0138 
18E4:0106 C70606020002 MOV WORD PTR[0206],0200 
18E4:010C C70606020202 MOV WORD PTR[0208],0202 
 
可見這兩種格式是等效的。 
8)命名指令N(Name),其格式為: 
-N filespecs [filespecs] 
指令把兩個檔案標識符格式化在CS:5CH和CS:6CH的兩個檔案控制塊中,以便在其後用L或W指令把檔案裝入存盤。filespecs的格式可以是: 
[d:][path] filename[.ext] 
例如, 
-N myprog 
-L 
- 
可把檔案myprog裝入存儲器。  
 
2004-5-26 09:44                  
 
IceMe 
正式會員 
 
 
 
 
 
積分 170 
發貼 305 
註冊 2004-3-15 
來自 紫色星雲 
狀態 離線  9)裝入指令(Load),有兩種功能。 
·把磁碟上指定扇區範圍的內容裝入到存儲器從指定位址開始的區域中。其格式為: 
-L[address[drive sector sector] 
·裝入指定檔案,其格式為: 
-L[address] 
此指令裝入已在CS:5CH中格式化了檔案控制塊所特殊的檔案。如未指定位址,則裝入CS:0100開始的存儲區中。 
10)寫指令W(Write),有兩種功能。 
·把資料寫入磁碟的指定扇區。其格式為: 
-W address drive sector sector 
·把資料寫入特殊的檔案中。其格式為: 
-W[address] 
此指令把特殊的存儲區中的資料寫入由CS:5CH處的檔案控制塊所特殊的檔案中。如未指定位址則資料從CS:0100開始。要寫入檔案的位元群組數應先放入BX和CX中。 
11)離開DEBUG指令Q(Quit),其格式為: 
-Q 
它離開DEBUG,返回DOS。本指令並無存盤功能,如需存盤應先使用W指令。  
 
問題:初學者問一個低級問題,執行debug-a後,若果有一行輸入錯誤,如何變更這一行? 
 
回答: 
加入進行如下輸入: 
D:\PWIN95\Desktop>debug 
-a 
2129:0100movax,200 
2129:0103movbx,200 
2129:0106movcx,200 
2129:0109 
此時,發現movbx,200一句錯誤,應為movbx,20,可以敲Enter返回"-"狀態,然後輸入: 
-a103 
2129:0103movbx,20 
若果多或是少若干行,不必重新輸入,可以用M指令移動後面的程式來去掉或是增加程式空間。 
 
如何除錯和彙編你的第一個PC x86彙編語系程式呢? 
 
以下這些簡單的解釋可以讓一個彙編語系新手使用DEBUG:  
 
0)在使用時,如何快速獲得debug的使用幫助呢。 
1)讓我們開始工作吧,例如:顯示BIOS的日期。 
2)在你的電腦的COMMANG.COM檔案裡搜尋"IBM"這幾個字元。 
3) 一位十六進位數的運算。 
4) 檢查 x86寄存器內容。 
5)我們來編寫我們的第一個用機械語系編寫的程式-列印一個字元。 
6) 我們現在用彙編語系指令來做和例5一樣的事情。 
7)現在,我們不但要編寫一個彙寫程式式,而且我們還要把它存盤。 
8) 現在,我們試一試檢視一個已經編好的程式。 
9)你可以用DEBUG的計算功能計算程式的長度。 
10)另一種顯示在螢幕上字串的方法。 
11)讓我們試一試反覆輸出。 
12)我們現在把兩個程式連線起來。 
13) 讓我們逐步執行這個剛剛修補的程式。 
14)若果一開始的指令不是跳轉指令,那麼可能就要用這種方法了。  
 
以下所有的指令都是可以執行在WIN9x的MS-DOS模式下的。 
進入MS-DOS的模式有: 
[開始][程式][MS-DOS模式] 
 
[開始][執行][開啟]COMMAND[確定] 
 
或是你可以按兩下它: 
C:\Windows\Command.com  
 
0)在使用時,如何快速獲得debug的使用幫助呢 
以下PROMPT>表示目錄提示符:一般為:C:\WINDOWS\COMMAND\ 
PROMPT> DEBUG /?<按Enterpress the enter key now> 
怎樣?出錯了吧。顯示如下 
C:\WINDOWS>DEBUG/? 
Runs Debug, a program testing and editing tool. 
 
DEBUG [[drive:][path]filename [testfile-parameters]] 
 
[drive:][path]filename Specifies the file you want to test. 
testfile-parameters Specifies command-line information required by 
the file you want to test. 
 
After Debug starts, type ? to display a list of debugging commands. 
因為錯了所以它給你顯示一些提示。留意到最後一句了嗎? 
 
 
現在我們再來試一試: 
PROMPT> DEBUG<按Enter> (注意, DEBUG程式的指令是在一條橫線"-"後出現的。) 
-?<在出現的橫線後面輸入?再Enter> (下面的內容是按字母順序排序的) 
(注意:Note: Don't type the dash or comments -- just the ?) 
顯示如下,但是沒有中文的哦,中文是我加上去的。  
 
 
彙編assemble A [address] 
比較compare C range address 
傾倒dump D [range] 
進入enter E address [list] 
填充fill F range list 
進行go G [=address] [addresses] 
十六進位hex H value1 value2 
輸入input I port 
裝載load L [address] [drive] [firstsector] [number] 
移動move M range address 
命名name N [pathname] [arglist] 
輸出output O port byte 
進行proceed P [=address] [number] 
離開quit Q 
紀錄register R [register] 
搜尋search S range list 
描述trace T [=address] [value] 
反彙編unassemble U [range] 
寫write W [address] [drive] [firstsector] [number] 
分配延伸記憶體allocate expanded memory XA [#pages] 
釋放延伸記憶體deallocate expanded memory XD [handle] 
map expanded memory pages XM [Lpage] [Ppage] [handle] 
display expanded memory status XS 
-q<按Enter> (這是離開DEBUG回到DOS狀態)This quits out of debug, returning to the DOS prompt) 
 
Tested examples below walk the user thru the following debug examples: 
在下面的例子裡讀者必須明白以下幾條DEBUG指令。 
-D 顯示一定範圍記憶體的內容Display the contents of an area of memory 
-Q 離開DEBUG程式Quit the debug program 
-S 搜尋Search for whatever 
-H 十六進位的運算Hex arithmatic 
-R 顯示或是改變一個或是多個寄存器的內容Display or change the contents of one or more registers 
-E 輸入資料進入記憶體,在一個詳細的位址裡Enter data into memory, beginning at a specific location 
-G 執行現在在記憶體裡的程式。Go run the executable program in memory 
-U 反彙編,把我們不認識的機械代碼變為我們可以認識彙編語系符號Unassemble machine code into symbolic code 
-T 描述一條指令的用法。Trace the contents of one instruction 
-P 進行或是執行一個關聯的指令Proceed, or execute a set of related instructions 
-A 編譯,把彙編指令變為機械代碼Assemble symbolic instructions into machine code 
-N 命名一個程式Name a program 
-W 把一個已經命名的程式寫進磁碟Write the named program onto disk 
-L 把程式裝載進記憶體Load the named program back into memory 
 
返回目錄  
 
1)讓我們開始工作吧,例如:顯示BIOS的日期 
(以下PROMPT>表示目錄提示符:一般為:C:\WINDOWS\COMMAND\) 
 
PROMPT> DEBUG<按Enter>  
-D FFFF:0006 L 8<按Enter> (顯示 FFFFh, 偏移位址 6h, 長度 8 bytes) 
在作者的電腦上這裡顯示為 "1/10/96." 
譯者的電腦顯示" FFFF:0000 37 2F-30 36 2F 30 30 00 7/06/00."相信作者的電腦裡也是用這種格式顯示的。這裡顯示出來的是使用者BIOS的日期,有興趣的話可以重新開機看看,注意開機時的顯示。 
-Q<按Enter> (離開DEBUG)  
 
思考:當只按DEBUG的時候,編輯的是什麼?為什麼可以找到BIOS的日期?(譯者這裡也不是很清楚所以請大家知道的也留言給斑竹,改正。譯者認為可能是記憶體的真實物理位址。) 
 
返回目錄  
 
2)在你的電腦的COMMANG.COM檔案裡搜尋"IBM"這幾個字元 
下面的"C:\Win95\"是根據每不電腦不同的。像譯者的電腦裡就是"C:\WINDOWS" 
 
PROMPT> DEBUG C:\Win95\Command.com<按Enter> 
-S 0 L FFFF "IBM"<按Enter>(從0開始搜尋"IBM",搜尋FFFFh多個單元格) 
-Q<按Enter> (離開DEBUG)  
 
以下是譯者做的:  
 
C:\WINDOWS>DEBUG C:\WINDOWS\COMMAND.COM 
-S 0 L FFFF "IBM" 
-S 0 L FFFF "COMMAND" 
12A7:008D 
12A7:04F7 
12A7:3870 
12A7:38BE 
12A7:38DD 
-S 0 L FFFF "PATH" 
12A7:38AD 
12A7:CCB7 
12A7:CF55 
-S 0 L FFFF "COMSPEC" 
12A7:38D4 
12A7:3A4D 
12A7:CCC4 
-Q 
 
C:\WINDOWS> 
 
(注意:搜尋是要區分大小寫的) 
(你可以看到上面是沒有找到"IBM"的, 可以試一試"PATH" , "COMSPEC" , "COMMAND") 
(注意: 這種方法用在尋找加密資料和已被移除的資料等方面時是十分有用的) 
 
返回目錄  
 
3) 一位十六進位數的運算: 
 
PROMPT> DEBUG<按Enter> 
-H 9 1<按Enter> (加減兩個十六進位的數, 9h+1h=Ah & 9h-1h=8h) 
結果是顯示: 000A 0008 
-Q<按Enter> (離開DEBUG)  
 
C:\WINDOWS>debug 
-h 9 1 
000A 0008 
-q 
C:\WINDOWS> 
 
返回目錄  
 
4) 檢查x86寄存器內容 
 
PROMPT> DEBUG<按Enter> 
-R<按Enter> (顯示x86寄存器內容) 
-Q<按Enter> (離開DEBUG)  
 
C:\WINDOWS>debug 
-R 
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 
DS=127C ES=127C SS=127C CS=127C IP=0100 NV UP EI PL NZ NA PO NC 
127C:0100 043C ADD AL,3C 
-Q 
 
下面是對寄存器的簡單介紹:  
 
資料存儲器 
在本類中,一般講的AH就是AX的前八位,AL就是AX的後八位,後面的以此類推。 
AX Accumulator;作為累加器,所以它是算術運算的主要寄存器。另外所有的I/O指令都使用這一寄存器與外部裝置傳輸訊息。 
BX Base register;可以作為通用寄存器使用,此外在計算存儲器位址時,它經常用作基位址寄存器。 
CX Counting register;可以作為通用寄存器使用,此外在循環(LOOP)和串處理指令中作隱含的計數器。 
DX Data register;可以作為通用寄存器使用,一般在作雙字長運算時,把DX和AX群群組合在一起存放一個雙字長數,DX用來存放高位字。此外,對某些I/O動作,DX可用來存放I/O的連線埠位址。  
 
指標及變址寄存器 
BP Base pointers register ;機制指標寄存器 
SI Source index register ;堆棧指標寄存器 
DI Destiny index register ;目的變址寄存器 
SP Battery pointer register ;堆棧指標寄存器 
 
段寄存器 
CS Code segment register ;代碼段寄存器,存放正在執行的程式指令 
DS Data segment register ;資料段寄存器,存放目前執行程式所用的資料 
SS Battery segment register ;堆棧段寄存器,定義了堆棧所在區域 
ES Extra segment register ;附加段寄存器,存放附加的資料,是一個輔助性的資料區, 
 
控制寄存器 
IP Next instruction pointer register;指令指標寄存器,它用來存放代碼段中的偏移位址,在程式執行的過程中,它始終指向下一筆指令的首位址,它與CS寄存器聯用確定下一筆指令的物理位址 
F Flag register;標誌寄存器 "NV UP EI PL NZ NA PO NC"就是了,也有人稱之為PSW Program Status Wold程式狀態寄存器  
 
(這裡有一點必須講明白的現在在,其實從奔騰開始這些寄存器(除了所有段寄存器,標誌寄存器 )都是32位的。並且加多了兩個16位段寄存器FS,GS。dos下面看到這些寄存器是16位的。要看32位寄存器可以使用soft-ice。對於FS,GS的作用我也不是很清楚,希望有高手指點,謝謝。)  
 
返回目錄  
 
2004-5-26 09:45                  
 
IceMe 
正式會員 
 
 
 
 
 
積分 170 
發貼 305 
註冊 2004-3-15 
來自 紫色星雲 
狀態 離線  5)我們來編寫我們的第一個用機械語系編寫的程式-列印一個字元 
(這裡用機械語系的主要原因是考慮到有一些使用者不懂彙編指令,現在就要讓他有一個認識電腦程式實質是一些數字)  
 
PROMPT> DEBUG<按Enter> 
-E 100<按Enter> (在偏移位址為100的地方輸入機械指令程式) 
B4<按空格>02<按空格> (在AX寄存器的前八位存入02) 
B2<按空格>41<按空格> (在DX寄存器的後八位存入41h,41h就是大寫A的ASCII碼,身邊有ASCII表的朋友可以對著表改改數字試一試) 
CD<按空格>21<按空格> (當AH=02時這是DOS顯示輸出的中斷號) 
CD<按空格>20<按Enter> (離開DOS) 
-G<按Enter> (程式執行,並在螢幕上顯示出"A") 
程式執行完以後你將看到"Program terminated normally"(程式標準結束了). 
-U 100<按Enter> (我們把它反彙編,就是把機械指令變為彙編語系指令)  
107F:0100 B402 MOV AH,02 
:0102 B2 MOV DL,41 
:0104 CD21 INT 21  
:0106 CD20 INT 20  
(下面會有一堆無用的東西) 
(對了,你的段位址可能與我的段位址CS=107F不同哦) 
-R<按Enter> (讓我們來看看寄存器的值; IP==100h, AX==0000h, DX==0000h) 
好極了,我們看到電腦又做好了準備下一次執行程式了。 
-T<按Enter> (執行第一步動作... IP=>102h, AX=>0200h,指令指標寄存器指向下一筆指令,AX的值被改變。 
-T<按Enter> (執行第二步動作... IP=>104h, , DX=>0041h,指令指標寄存器指向下一筆指令,DX的值被改變。 
-P<按Enter> (繼續執行 INT 21,IP=>106h, AX=>02h,) 
-P<按Enter> (繼續執行INT 20) 
-Q<按Enter> (離開DEBUG) 
(注意:你必須小心使用"T".因為若果你在程式完結以後繼續執行這條指令,因為我們無法預知下面的指令是什麼,所以我們也無法預知它可能帶來的後果) 
C:\WINDOWS>DEBUG 
-E 100 
127C:0100 B4.B4 02.02 B2.B2 41.41 CD.CD 21.21 CD.CD 20.20 
-G 
A 
Program terminated normally 
-U 100 
127C:0100 B402 MOV AH,02 
127C:0102 B241 MOV DL,41 
127C:0104 CD21 INT 21 
127C:0106 CD20 INT 20 
127C:0108 C706F1E30900 MOV WORD PTR [E3F1],0009 
127C:010E EB59 JMP 0169 
127C:0110 57 PUSH DI 
127C:0111 BFF1E3 MOV DI,E3F1 
127C:0114 8BDF MOV BX,DI 
127C:0116 06 PUSH ES 
127C:0117 0E PUSH CS 
127C:0118 07 POP ES 
127C:0119 32D2 XOR DL,DL 
127C:011B EB34 JMP 0151 
127C:011D 006B12 ADD [BP+DI+12],CH 
-R 
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 
DS=127C ES=127C SS=127C CS=127C IP=0100 NV UP EI PL NZ NA PO NC 
127C:0100 B402 MOV AH,02 
-T 
 
AX=0200 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 
DS=127C ES=127C SS=127C CS=127C IP=0102 NV UP EI PL NZ NA PO NC 
127C:0102 B241 MOV DL,41 
-T 
 
AX=0200 BX=0000 CX=0000 DX=0041 SP=FFEE BP=0000 SI=0000 DI=0000 
DS=127C ES=127C SS=127C CS=127C IP=0104 NV UP EI PL NZ NA PO NC 
127C:0104 CD21 INT 21 
-P 
A 
AX=0241 BX=0000 CX=0000 DX=0041 SP=FFEE BP=0000 SI=0000 DI=0000 
DS=127C ES=127C SS=127C CS=127C IP=0106 NV UP EI PL NZ NA PO NC 
127C:0106 CD20 INT 20 
-P 
 
Program terminated normally 
-Q 
 
C:\WINDOWS>  
 
返回目錄  
 
6) 我們現在用彙編語系指令來做和例5一樣的事情 
 
PROMPT> DEBUG<按Enter> 
-A 100<按Enter> (在偏移位址為100的地方輸入彙編語系程式) 
MOV AH,02<按Enter> (選用DOS的02號功能呼叫,顯示輸出) 
MOV DL,<按Enter> (在DX寄存器的後八位存入41h,41h就是大寫A的ASCII碼,身邊有ASCII表的朋友可以對著表改改數字試一試) 
INT 21<按Enter> (當AH=02時這是DOS顯示輸出的中斷號,顯示"A") 
INT 20<按Enter> (離開DOS) 
<按Enter> (結束彙編語系寫程式狀態,回到DEBUG指令狀態) 
-G =100<按Enter> (執行程式,其實可以不要"=100"因為一般預設啟始位置是100) 
-Q<按Enter> (離開DEBUG) 
 
 
C:\WINDOWS>DEBUG 
-A 100 
127C:0100 MOV AH,02 
127C:0102 MOV DL,41 
127C:0104 INT 21 
127C:0106 INT 20 
127C:0108 
-G 
A 
Program terminated normally 
-Q 
 
返回目錄 
 
7) 現在,我們不但要編寫一個彙寫程式式,而且我們還要把它存盤 
(下面這個程式就要比原來的程式複雜一點了-顯示輸出:"ABC")  
 
PROMPT> DEBUG<按Enter>(執行DEBUG程式;系統預設啟始IP寄存器值為100h) 
-A 100<按Enter> (用彙編語系編寫一個程式,啟始位址是100h) 
MOV AH,02<按Enter> (選取DOS的02號功能呼叫, 顯示輸出) 
MOV DL,<按Enter> (在DX寄存器的後八位存入41h,41h就是大寫A的ASCII碼) 
INT 21<按Enter> (當AH=02時這是DOS顯示輸出的中斷號,顯示"A") 
MOV DL,42<按Enter> (在DX寄存器的後八位存入41h,41h就是大寫B的ASCII碼) 
INT 21<按Enter> (當AH=02時這是DOS顯示輸出的中斷號,顯示"B") 
MOV DL,43<按Enter> (在DX寄存器的後八位存入41h,41h就是大寫C的ASCII碼) 
INT 21<按Enter> (當AH=02時這是DOS顯示輸出的中斷號,顯示"C") 
INT 20<按Enter> (程式結束,離開DEBUG) 
<按Enter> (結束彙編指令輸入,回到DEBUG指令輸入) 
-R BX<按Enter> (檢視寄存器BX的值) 
:0000<按Enter> (設定BX為0000h,這是程式的結尾位址是BX:CX) 
(注意,只要BX = 0000, 檔案的大小就小於 < 64 Kb.) 
-R CX<按Enter> (設定CX為Fh,這是程式的長度:16位) 
:0010<按Enter> (現在我們可以把這個16位元群組的程式寫入硬碟了) 
-N printabc.com<按Enter> (將要存盤的程式命名) 
-W<按Enter> (把這十六位元群組寫到檔案裡面) 
-Q<按Enter> (離開DEBUG) 
PROMPT> DIR printabc.com<按Enter> 
這裡將會報告這個檔案的大小是16位元群組 (10h 位元群組). 
PROMPT> printabc.com<按Enter> 
會馬上在螢幕上列印出"ABC" 
 
C:\WINDOWS>DEBUG 
-A 100 
127C:0100 MOV AH,02 
127C:0102 MOV DL,41 
127C:0104 INT 21 
127C:0106 MOV DL,42 
127C:0108 INT 21 
127C:010A MOV DL,43 
127C:010C INT 21 
127C:010E INT 20 
127C:0110 
-R 
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 
DS=127C ES=127C SS=127C CS=127C IP=0100 NV UP EI PL NZ NA PO NC 
127C:0100 B402 MOV AH,02 
-R BX 
BX 0000 
: 
-R CX 
CX 0000 
:0010 
-N PRINTABC.COM 
-W 
Writing 00010 bytes 
-Q 
C:\WINDOWS>DIR PRINTABC.COM 
Volume in drive C has no label 
Volume Serial Number is 28FB-70BA 
Directory of C:\WINDOWS 
PRINTABC COM 16 03-21-01 11:02 PRINTABC.COM 
1 file(s) 16 bytes 
0 dir(s) 557,711,360 bytes free 
C:\WINDOWS>PRINTABC 
ABC 
C:\WINDOWS> 
 
這裡可以有人告訴我,為什麼要存入是BX:CX代表程式長度嗎?(寫信給譯者,謝謝) 
 
返回目錄 
 
8) 現在,我們試一試檢視一個已經編好的程式: 
 
PROMPT> DEBUG<按Enter>(執行DEBUG程式在CS:IP = CS:0100h) 
-N printabc.com<按Enter> (告訴電腦你想裝載的程式名) 
-L<按Enter> (裝載那個名字的程式進入記憶體) 
-U 100 L 10<按Enter> (從偏移位址100開始反彙編16位位元群組) 
-R<按Enter> (現在看看寄存器裡面的內容) 
注意:DEBUG本身是沒有自動紀錄檔案大小的。 
-G (執行被命名的程式,列印"ABC") 
你將看到"ABC",然後是"Program terminated normally") 
 
C:\WINDOWS>DEBUG 
-N PRINTABC.COM 
-L 
-U 100 L 10 
12A4:0100 B402 MOV AH,02 
12A4:0102 B241 MOV DL,41 
12A4:0104 CD21 INT 21 
12A4:0106 B242 MOV DL,42 
12A4:0108 CD21 INT 21 
12A4:010A B243 MOV DL,43 
12A4:010C CD21 INT 21 
12A4:010E CD20 INT 20 
-R 
AX=0000 BX=0000 CX=0010 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000 
DS=12A4 ES=12A4 SS=12A4 CS=12A4 IP=0100 NV UP EI PL NZ NA PO NC 
12A4:0100 B402 MOV AH,02 
-G 
ABC 
Program terminated normally 
 
返回目錄  
 
2004-5-26 09:45                  
 
IceMe 
正式會員 
 
 
 
 
 
積分 170 
發貼 305 
註冊 2004-3-15 
來自 紫色星雲 
狀態 離線  9)你可以用DEBUG的計算功能計算程式的長度。 
 
一開始的時候你的程式起始位址是在0100h: 
107F:0100 MOV AH,02 <--這就是 100h 
你的程式的最後一行在010Eh: 
107F:010E INT 20 <--最後一行 
然後,最後一條指令的下一行的位址是0110h: 
107F:0110 <--這就是110h 
所以,從0110h裡減去100h我們得到得長度是10h 位元群組. 
 
PROMPT> DEBUG<按Enter> 
-H 110 100<按Enter> (這條指令將運算110h+100h和110h-100h) 
0210 0010<按Enter> (匯報 110h-100h=0010h; 16-byte 程式長度16位) 
-Q<按Enter> (離開DEBUG) 
 
 
C:\WINDOWS>debug 
-H 110 100 
0210 0010 
-Q 
 
返回目錄 
 
10)另一種顯示在螢幕上字串的方法 
 
注意:在你輸入資料的時候,按"-"鍵將會可以讓你回退一格。  
 
PROMPT> DEBUG<按Enter> 
-E 200<按Enter> (從偏移位址200開始。輸入"Hello,World") 
48<按空格>65<按空格> (輸入48h (H)和65h (e)) 
6C<按空格>6C<按空格> (輸入6Ch (l)和6Ch (l)) 
6F<按空格>2C<按空格> (輸入6Fh (o)和2Ch (,)) 
57<按空格>6F<按空格> (輸入57h (W)和6Fh (o)) 
72<按空格>6C<按空格> (輸入72h (r)和6Ch (l)) 
64<按空格>24<按空格> (輸入64h (d)和24h ($)) 
<按Enter> ("Hello,World" 已經輸入完畢) 
-D 200<按Enter> (顯示你剛剛輸入的內容: 
48 65 6C 6C 6F 2C 57 6F-72 6C 64 24 ... HELLO,WORLD$...) 
-A 100<按Enter> (用彙編語系寫一個新程式在IP-100h處開始) 
MOV AH,09<按Enter> (選取DOS的09號功能呼叫,顯示字串) 
MOV DX,0200<按Enter> (把輸出位址(200h),放進寄存器) 
INT 21<按Enter> (執行DOS功能呼叫,顯示"Hello,World") 
INT 20<按Enter> (離開程式回到DOS狀態) 
<按Enter> (結束彙編語系輸入,回到DEBUG輸入狀態) 
-G<按Enter> (從 CS:IP開始執行程式, 就是從107F:0100h開始執行程式)  
 
現在,我們可以把這個程式儲存進一硬碟 
 
-D 100<按Enter> (紀錄:程式的起始點在100h) 
-D 200<按Enter> (紀錄:程式資料單元的結束點是在020Bh) 
-H 20B 100<按Enter> (運算 20Bh-100h=10Bh;程式長度267位元群組) 
-R BX<按Enter> (檢查BX寄存器的值) 
:0000<按Enter> (設定BX為0000h,程式的長度是BX:CX,實際上你可以把和CX寫到一起,即實際長度為:0000010Bh,這樣些的目的是使你可以計算更大的程式的長度) 
-R CX<按Enter> (設定CX 為010Bh, 這就是這個程式的長度了) 
:010B<按Enter> (現在你可以把這個108位元群組的程式寫入硬碟了) 
-N printhw.com<按Enter> (將要寫入硬碟的程式命名) 
-W<按Enter> (把這10Bh 即267個位元群組寫入檔案) 
-Q<按Enter> (離開DEBUG) 
PROMPT> DIR printhw.com<按Enter> 
將會匯報程式的長度是267位元群組(10Bh位元群組). 
PROMPT> printhw.com<按Enter>  
執行這個程式,這將會在螢幕上顯示出"Hello,World" : 
 
C:\WINDOWS>DEBUG 
-E 200 
127C:0200 2C.48 D5.65 BA.6C FF.6C FF.6F B8.2C 00.57 AE.6F 
127C:0208 CD.72 2F.6C 3C.64 00.24 C3. 
-D 200 
127C:0200 48 65 6C 6C 6F 2C 57 6F-72 6C 64 24 C3 A0 ED E3 Hello,World$ 
127C:0210 0A C0 74 09 56 57 E8 84-21 5F 5E 73 0A B9 04 01 ..t.VW..!_^s 
127C:0220 FC 56 57 F3 A4 5F 5E C3-50 56 33 C9 33 DB AC E8 .VW.._^.PV3. 
127C:0230 C3 23 74 19 3C 0D 74 15-F6 C7 20 75 06 3A 06 1E .#t.<.t... u 
127C:0240 D4 74 0A 41 3C 22 75 E6-80 F7 20 EB E1 5E 58 C3 .t.A<"u... . 
127C:0250 A1 F3 D8 8B 36 F5 D8 C6-06 37 DA 00 C6 06 33 DA ....6....7.. 
127C:0260 00 8B 36 F5 D8 8B 0E F3-D8 8B D6 E3 42 51 56 5B ..6......... 
127C:0270 2B DE 59 03 CB 8B D6 C6-06 D7 DC 00 E3 31 49 AC +.Y......... 
-A 100 
127C:0100 MOV AH,09 
127C:0102 MOV DX,0200 
127C:0105 INT 21 
127C:0107 INT 20 
127C:0109 
-G 
Hello,World 
Program terminated normally 
-D200 
127C:0200 48 65 6C 6C 6F 2C 57 6F-72 6C 64 24 C3 A0 ED E3 Hello,World$ 
127C:0210 0A C0 74 09 56 57 E8 84-21 5F 5E 73 0A B9 04 01 ..t.VW..!_^s 
127C:0220 FC 56 57 F3 A4 5F 5E C3-50 56 33 C9 33 DB AC E8 .VW.._^.PV3. 
127C:0230 C3 23 74 19 3C 0D 74 15-F6 C7 20 75 06 3A 06 1E .#t.<.t... u 
127C:0240 D4 74 0A 41 3C 22 75 E6-80 F7 20 EB E1 5E 58 C3 .t.A<"u... . 
127C:0250 A1 F3 D8 8B 36 F5 D8 C6-06 37 DA 00 C6 06 33 DA ....6....7.. 
27C:0260 00 8B 36 F5 D8 8B 0E F3-D8 8B D6 E3 42 51 56 5B ..6......... 
127C:0270 2B DE 59 03 CB 8B D6 C6-06 D7 DC 00 E3 31 49 AC +.Y......... 
-H 20B 100 
030B 010B 
-R BX 
BX 0000 
: 
-R CX 
CX 0000 
:010B 
-N PRINTHW.COM 
-W 
Writing 0010B bytes 
-Q 
C:\WINDOWS>DIR PRINTHW.COM 
Volume in drive C has no label 
Volume Serial Number is 28FB-70BA 
Directory of C:\WINDOWS 
PRINTHW COM 267 03-22-01 11:53 PRINTHW.COM 
1 file(s) 267 bytes 
0 dir(s) 555,089,920 bytes free 
 
返回目錄 
 
11)讓我們試一試反覆輸出: 
 
PROMPT> DEBUG<按Enter> 
-A 100<按Enter> (用彙編語系寫一個新的程式,起始位址是100h) 
JMP 125<按Enter> (從102h接前往125h) 
<按Enter> (結束輸入彙編指令。譯者註:這裡是為了例12做準備) 
-E 102 'Hello World' 0d 0a '$'<按Enter> (把字串輸入記憶體) 
-A 125<按Enter> (從125h開始繼續編寫我們的彙編語系程式) 
MOV DX,0102<按Enter> (把字串的首位址(102h)放入DX寄存器) 
MOV CX,0005<按Enter> (指定這條指令將被顯示5次) 
MOV AH,09<按Enter> (選取DOS的09號功能呼叫, 顯示字串) 
INT 21<按Enter> (執行DOS的功能呼叫, 顯示"Hello, World") 
DEC CX<按Enter> (每次執行到這裡CX都減去1) 
JCXZ 0134<按Enter> (若果計數器CX=0,那麼前往位址0134h) 
JMP 012D<按Enter> (其他情況下,即CX≠O時前往012Dh) 
INT 20<按Enter> (程式離開DOS狀態) 
<按Enter> (結束彙編語系程式輸入,回到DEBUG) 
-U 100<按Enter> (從位址100h 開始反彙編) 
-U<按Enter> (繼續執行反彙編指令,直至你看到INT 20) 
-H 0136 100<按Enter> (運算程式長度為36h) 
-U 100 L 36<按Enter> ( 從100h反彙編到136h ,來確認你的計算) 
-R BX<按Enter> (檢視寄存器BX的值) 
:0000<按Enter> (設定BX為0000h) 
-R CX<按Enter> (把CX 設定為36h, 這就是程式長度36位元群組) 
:0036<按Enter> (現在你可以把這36位元群組寫入檔案了) 
-N printhw5.com<按Enter>(命名我,我們要寫入的檔案名) 
-W<按Enter> (把這36位元群組的內容寫進新檔案) 
-G<按Enter> (執行程式,在螢幕上顯示"Hello-World ") 
-Q<按Enter> (離開DEBUG) 
PROMPT> DIR printhw5.com<按Enter> 
將會匯報檔案大小為54位元群組,換算為十六進位就是36h位元群組 
PROMPT> printhw5.com<按Enter>  
將在螢幕上顯示五次"Hello World" 
 
返回目錄 
 
12)我們現在把兩個程式連線起來。  
 
我們現在把printhw.com做為修補程式 寫進printhw5.com, 新版本的printhw5 將先執行原來的printhw.com再執行原來的printhw5.com 
 
PROMPT> COPY printhw5.com printhw5.bak<按Enter> 
首先,備份printhw5.com,以後可以用於比較 
PROMPT> DIR printhw5.com<按Enter> 
現在,檢視到得仍然是以前的54位元群組(36h 位元群組) 
PROMPT> DEBUG printhw5.com<按Enter> 
-R<按Enter> (現在檢視仍然是BX:CX=0000 0036h bytes) 
-U 100<按Enter> (檢視到最後的是 EB 23 (JMP 0125)) 
-H 100 36<按Enter> (最後的指令是在 100h+36h=136h) 
-H 136 1<按Enter> (下一個可用的存儲器位置是136h+1h=137h) 
現在你擁有足夠的資料,去修補那個程式 
-E 110<按Enter> (把"Hello,World"輸入記憶體) 
48<按空格>65<按空格> (輸入48h (H)和65h (e)) 
6C<按空格>6C<按空格> (輸入6Ch (l)和6Ch (l)) 
6F<按空格>2C<按空格> (輸入6Fh (o)和2Ch (,)) 
57<按空格>6F<按空格> (輸入57h (W)和6Fh (o)) 
72<按空格>6C<按空格> (輸入72h (r)和6Ch (l)) 
64<按空格>24<按空格> (輸入64h (d)和24h ($)) 
<按Enter> (停止輸入"Hello,World") 
-D 110<按Enter> (顯示更才輸入記憶體的資料: 
48 65 6C 6C 6F 2C 57 6F-72 6C 64 24 ...HELLO,WORLD$...) 
-A 100<按Enter> (在IP位址的(100h)開始奪取原來的程式的控制權,原來這裡是"JMP 125") 
JMP 137<按Enter> (代替原來執行的程式首先執行我們現在的修補程式) 
<按Enter> (結束彙編指令輸入,回到DEBUG指令輸入) 
-A 137<按Enter> (在下面的可用通姦編譯這個修補程式) 
MOV AH,09<按Enter> (選取DOS的09號功能呼叫,顯示輸出) 
MOV DX,110<按Enter> (把我們要輸出的字段的首位址(110h)給DX寄存器) 
INT 21<按Enter> (執行DOS 的功能呼叫,顯示"Hello,World") 
JMP 0125<按Enter> (這裡用跳轉到原程式來代替離開到DOS指令(INT 20)) 
<按Enter> (結束彙編指令輸入,回到DEBUG指令輸入) 
 
-U 125<按Enter> (確認一下源程式沒有被我們誤改了,若果無改了就馬上離開DEBUG重新來過) 
-U 100 L 1<按Enter> (確認已經使程式跳轉到我們的修補程式位址137h) 
-D 110 L C<按Enter> (確認資料區已經有了我們想要的資料) 
-U 137<按Enter> (確認我們的新程式已經輸入了) 
 
現在我們可以把這個小程式存入硬碟了: 
(注意:在現在整個程式的最後一條指令"JMP 0125" 的後面一條的位址是0140h) 
-H 0140h 100<按Enter> (計算140h-100h=40h; 答案是我們現在有一個長度為64位元群組的小程式) 
-RBX<按Enter> (檢查BX寄存器的值是否為"0") 
:<按Enter> (若果BX是0000h那麼就不需要改動啦) 
-RCX<按Enter> (要把CX改為40h。這是我們的程式的長度) 
:40<按Enter> (現在你可以把這0000:0040h個位元群組的小程式放入硬碟啦) 
-W<按Enter> (覆蓋我們的原程式) 
-G<按Enter> (嘗試執行我們的新程式) 
-Q<按Enter> (離開DEBUG回到DOS) 
 
PROMPT> DIR printhw5.com<按Enter> 
現在你再看就發現文章大小不再是54位元群組, 變成了64位元群組. 
PROMPT> printhw5.com<按Enter> 
現在是首先在螢幕上列印 "Hello,World"一次,然後再列印"Hello,World" 5 次(譯者註:這裡其實可以在寫程式的時候換一換內容試一試. 
 
返回目錄 
 
13) 讓我們逐步執行這個剛剛修補的程式: 
 
PROMPT> DEBUG printhw5.com<按Enter> 
-R<按Enter> (第1步:位址0100h內容是 EB35 "JMP 0137") 
-T<按Enter> (第2步:位址0137h內容是B409 "MOV AH,09") 
-T<按Enter> (第3步:位址0139h內容是BA1001 "MOV DX,0110") 
-T<按Enter> (第4步:位址0139h內容是CD21 "INT 21") 
-P<按Enter> (執行第5:"Hello,World"位址013Eh內容是EBE5 "JMP 0125") 
-T<按Enter> (到這裡控制權已經回到了原程式) 
若果你想的話,你可以一步一步的執行完全部程式;方法就是一直按"T",直至到達下一個功能呼叫執行完成後。到那時按一個"P"就可以繼續按"T". 
 
返回目錄 
 
14)若果一開始的指令不是跳轉指令,那麼可能就要用這種方法了: 
 
例如:若果我們想叫程式printhw 先列印"ABC",就要取得控制權了。然後列印"ABC"的程式把控制權給回原來的printhw.  
 
在這個事例裡 ,printhw在100h的位址有兩位元群組的程式; 
不能像上面那樣簡單的替代(一個JMP代替另一個JMP)就完事。 
解決辦法就是使用NOP指令。 
 
 
PROMPT> DIR printhw.com<按Enter> 
將匯報程式的長度為267位元群組(10Bh 位元群組). 
 
PROMPT> DEBUG printhw.com<按Enter> 
-R<按Enter> (IP=100h 並且printhw's 的檔案大小=BX:CX=0000:010Bh) 
-U 100<按Enter> (第一條指令B4 09 (MOV AH,09)是兩個位元群組的) 
(第二條指令是三個位元群組的 BA 00 02 (MOV DX,0200)) 
-H 100 10B<按Enter> (最後一條printhw的指令是在100h+10Bh=20Bh) 
(DOS的INT 21功能呼叫是在105h開始的) 
現在你有足夠的資料輸入你的程式了! 
-A 100<按Enter> (要在printhw 的IP開始位置就奪取程式的控制權) 
JMP 20B<按Enter> (前往20Bh增加一個程式) 
NOP<按Enter> (用空指令填充直至你去到下一筆完整的指令) 
NOP<按Enter> (你可以用它來覆蓋你不想只執行的原程式指令 ,而不改變原來的位址。但是在這裡我們只需要兩個NOP) 
譯者註:為了使大家更加明白所以我將各條指令對應的機械指令的長度寫在下面 
B409 MOV AH,09 
BA0002 MOV DX,0200 
E90301 JMP 020B 
90 NOP 
這樣我們就很清楚的看到JMP 020B的長度比MOV AH,09多了1個位元群組,但是MOV DX,0200有是3個位元群組,而NOP是空指令,是不執行任何動作的,它只是占1個位元群組。所以我們現在把前兩條指令用一個JMP 020B和兩個NOP代替。後面再加上去。 
<按Enter> (結束彙編指令回到DEBUG指令輸入) 
-U 100<按Enter> (看一看前面我們做了些什麼) 
(注意DOS INT 21中斷任然是在 IP=105h的地方開始) 
-A 20B<按Enter> (現在把我們的原程式寫在後面) 
MOV AH,02<按Enter> (選取DOS 的 2號功能呼叫, 字元顯示輸出) 
MOV DL,41<按Enter> (在DL寄存器存入"A"的ASCII碼41h) 
INT 21<按Enter> (執行DOS 的功能呼叫,顯示字元"A") 
MOV DL,42<按Enter> (在DL寄存器存入"B"的ASCII碼42h) 
INT 21<按Enter> (執行DOS 的功能呼叫,顯示字元"B") 
MOV DL,43<按Enter> (在DL寄存器存入"C"的ASCII碼43h) 
INT 21<按Enter> (執行DOS 的功能呼叫,顯示字元"C") 
MOV AH,09<按Enter> (現在重新輸入原來在100h的程式指令) 
MOV DX,0200<按Enter> (現在要打掃寄存器了,復原原來的200h的值) 
JMP 105<按Enter> (前往INT 21指令的位置105h) 
<按Enter> (請注意一下你這裡最後的位址是0221h) 
-H 221 100<按Enter> (計算221h-100h=121h 就是289位元群組的程式) 
-R CX<按Enter> (把CX的值設為121h, 這就設定了程式的新長度) 
:0121<按Enter> (現在用121h (也就是289位元群組)覆蓋原值) 
-W<按Enter> (把這289個位元群組寫回原程式) 
-Q<按Enter> (離開DEBUG) 
 
PROMPT> DIR printhw.com<按Enter> 
現在在看就會是新程式的長度289位元群組而不是,267位元群組) 
現在在螢幕上先出現"ABC"再出現"Hello,World"  
 
 |   
 
 
 
 |