?? e路陽光 - 編程專區 - 匯編語言超濃縮教程 天天好心情!.htm
字號:
......k.....S.^.<BR> 1975:0170 8B C2 E8 FB FD 0B C0
75-09 8B 5E FE 8B 47 0C E8
.......u..^..G..<BR> 現在,我們來剖析另一個程序:由鍵盤輸入任意字符串,然后顯示出來。db
20指示DEBUG保留20h個未用的內存空間供緩沖區使用。<BR> 輸入A100<BR> MOV
DX,0116 ;DS:DX = 緩沖區地址,由DB偽指令確定緩沖區地址<BR> MOV AH,0A ;0Ah
號功能調用<BR> INT 21 ;鍵盤輸入緩沖區<BR> MOV DL,0A
;由于功能Ah在每個字符串最后加一個歸位碼(0Dh由 Enter<BR> MOV AH,02
;產生),使光標自動回到輸入行的最前端,為了使新輸出的<BR> INT 21
;字符串不會蓋掉原來輸入的字符串,所以利用功能2h加一<BR> ;個換行碼(OAh),使得光標移到下一行的的最前端。<BR> MOV
DX,0118 ;裝入字符串的起始位置<BR> MOV AH,09
;9h功能遇到$符號才會停止輸出,故字符串最后必須加上<BR> INT 21
;$,否則9h功能會繼續將內存中的無用數據胡亂顯示出來<BR> INT 20<BR> DB 20
;定義緩沖區
<BR> 送你一句話:學匯編切忌心浮氣燥。<BR> 客套話就不講了。工欲善其事,必先利其器。與其說DEBUG
是編譯器,倒不如說它是“直譯器”,DEBUG的A命令只可將一行匯編指令轉成機器語言,且立刻執行。真正編譯器(MASM)的運作是利用文本編輯器(EDIT等)將匯編指令建成一個獨立且附加名為.ASM的文本文件,稱源程序。它是MASM
程序的輸入部分。MASM將輸入的ASM文件,編譯成.OBJ文件,稱為目標程序。OBJ文件僅包含有關程序各部份要載入何處及如何與其他程序合并的信息,無法直接載入內存執行。鏈結程序LINK則可將OBJ文件轉換成可載入內存執行(EXEcute)的EXE文件。還可以用EXE2BIN,將符合條件的EXE文件轉成COM文件(COM
文件不但占用的內存最少,而且運行速度最快)。<BR> 下面我們用MASM寫一個與用DEBUG寫的第一個程序功能一樣的程序。<BR> 用EDIT編輯一個SMILE.ASM的源程序文件。<BR> 源程序
DEBUG 程序<BR> prognam segment<BR> assume
cs:prognam<BR> org 100h A100<BR> mov dl,1 mov
dl,1<BR> mov ah,2 mov ah,2<BR> int 21h int 21<BR> int
20h int 20<BR> prognam
ends<BR> end<BR> 比較一下:1.因為MASM會將所有的數值假設為十進制,而DEBUG則只使用十六進制,所以在源程序中,我們必須在有關數字后加上代表進制的字母,如H代表十六進制,D代表十進制。若是以字母開頭的十六進制數字,還必須在字母前加個0,以表示它是數,如0AH。2.源程序增加五行敘述:prognam
segment 與 prognam ends 是成對的,用來告訴 MASM
及LINK,此程序將放在一個稱為PROGNAM(PROGram
NAMe)的程序段內,其中段名(PROGNAM)可以任取,但其位置必須固定。assume cs:prognam
必須在程序的開頭,用來告訴編譯器此程序所在段的位置放在CS寄存器中。end用來告訴MASM,程序到此結束,
ORG 100H作用相當于DEBUG的A100,從偏移量100開始匯編。COM
文件的所有源程序都必須包含這五行,且必須依相同的次序及位置出現,這點東西記下就行,千篇一律。接著,我們用MASM編譯SMILE.ASM。<BR> 輸入
MASM SMILE ←不用打入附加名.ASM。<BR> Microsoft (R) Macro
Assembler Version 5.10<BR> Copyright (C) Microsoft Corp
1981, 1988. All rights reserved.<BR> Object filename
[SMILE.OBJ]: ←是否改動輸出OBJ文件名,如不改就ENTER<BR> Source listing
[NUL.LST]: ←
是否需要列表文件(LST),不需要就ENTER<BR> Cross-reference [NUL.CRF]:
←是否需要對照文件(CRF),不需要則ENTER<BR> 50162 + 403867 Bytes
symbol space free<BR> 0 Warning Errors
←警告錯誤,表示編譯器對某些語句不理解,通常是輸入錯誤。<BR> 0 Severe Errors
←嚴重錯誤,會造成程序無法執行,通常是語法結構錯誤。<BR> 如果沒有一個錯誤存在,即可生成OBJ文件。OBJ中包含的是編譯后的二進制結果,它還無法被
DOS載入內存中加以執行,必須加以鏈結(Linking)。以LINK將OBJ文件(SMILE.OBJ)鏈結成
EXE 文件(SMILE.EXE)時,。<BR> 1.輸入 LINK SMILE
←不用附加名OBJ<BR> Microsoft (R) Overlay Linker Version
3.64<BR> Copyright (C) Microsoft Corp 1981, 1988. All
rights reserved.<BR> Run File [SMILE.EXE]: ←
是否改動輸出EXE文件名,如不改就ENTER<BR> List File [NUL.MAP]: ←
是否需要列表文件(MAP),不需要則ENTER<BR> Libraries [.LIB]:
←是否需要庫文件,要就鍵入文件名,不要則ENTER<BR> LINK : warning L4021: no
stack segment← 由于COM文件不使用堆棧段,所以錯誤信息<BR> ←"no stack
segment"并不影響程序正常執行<BR> 至此已經生成EXE文件,我們還須使用EXE2BIN
將EXE文件(SMILE.EXE),轉換成COM文件(SMILE.COM)。輸入EXE2BIN SMILE產生
BIN 文件(SMILE.BIN)。其實 BIN 文件與 COM
文件是完全相同的,但由于DOS只認COM、EXE及BAT文件,所以BIN文件無法被正確執行,改名或直接輸入
EXE2BIN SMILE SMILE.COM即可。現在,磁盤上應該有 SMILE.COM
文件了,你只要在提示符號C:&gt;下,直接輸入文件名稱 SMILE
,就可以執行這個程序了。<BR> 你是否覺得用編譯器產生程序的方法,比 DEBUG
麻煩多了!以小程序而言,的確是如此,但對于較大的程序,你就會發現其優點了。我們再將ASCII程序以編譯器方式再做一次,看看有無差異。首先,用EDIT.COM建立
ASCII.ASM 文件。<BR> prognam segment ;定義段<BR> assume
cs:prognam ;把上面定義段的段基址放入 CS<BR> mov cx,100h ;
裝入循環次數<BR> mov dl,0 ; 裝入第一個ASCII碼,隨后每次循環裝入新碼<BR> next:
mov ah,2<BR> int 21h<BR> inc dl ;INC:遞增指令,每次將數據寄存器
DL 內的數值加 1<BR> loop next ;
循環指令,執行一次,CX減1,直到CX為0,循環停止<BR> int 20h<BR> prognam
ends ;段終止<BR> end
;匯編終止<BR> 在匯編語言的源程序中,每一個程序行都包含三項元素:<BR> start: mov
dl,1 ;裝入第一個ASCII碼,隨后每次循環裝入新碼<BR> 標識符 表達式
注解<BR> 在原始文件中加上注解可使程序更易理解,便于以后參考。每行注解以“;”與程序行分離。編譯器對注解不予理會,注解的數據不會出現在OBJ、EXE或COM文件中。由于我們在寫源程序時,并不知道每一程序行的地址,所以必須以符號名稱來代表相對地址,稱為“標識符”。我們通常在適當行的適當位置上,鍵入標識符。標識符(label)最長可達31
個字節,因此我們在程序中,盡量以簡潔的文字做為標識符。現在,你可以將此ASCII.ASM 文件編譯成
ASCII.COM 了。1.MASM ASCII,2.LINK ASCII,3.EXE2BIN ASCII
ASCII.COM。<BR> 注意:當你以編譯器匯編你設計的程序時,常會發生打字錯誤、標識符名稱拼錯、十六進制數少了h、邏輯錯誤等。匯編老手常給新人的忠告是:最好料到自己所寫的程序一定會有些錯誤(別人告訴我的);如果第一次執行程序后,就得到期望的結果,你最好還是在檢查一遍,因為它可能是錯的。原則上,只要大體的邏輯架構正確,查找程序中錯誤的過程,與寫程序本身相比甚至更有意思。寫大程序時,最好能分成許多模塊,如此可使程序本身的目的較單純,易于撰寫與查錯,另外也可讓程序中不同部份之間的界限較清楚,節省編譯的時間。如果讀程序有讀不懂的地方最好用紙筆記下有關寄存器、內存等內容,在紙上慢慢比劃,就豁然開朗了。
下面我們將寫一個能從鍵盤取得一個十進制的數值,并將其轉換成十六進制數值而顯示于屏幕上的“大程序”。前言:要讓8086執行這樣的功能,我們必須先將此問題分解成一連串的步驟,稱為程序規劃。首先,以流程圖的方式,來確保整個程序在邏輯上沒有問題(不用說了吧!什么語言都要有此步驟)。這種模塊化的規劃方式,稱之為“由上而下的程序規劃”。而在真正寫程序時,卻是從最小的單位模塊(子程序)開始,當每個模塊都完成之后,再合并成大程序;這種大處著眼,小處著手的方式稱為“由下而上的程序設計”。<BR> 我們的第一個模塊是BINIHEX,其主要用途是從8086的BX寄存器中取出二進制數,并以十六進制方式顯示在屏幕上。注意:子程序如不能獨立運行,實屬正常。<BR>
binihex segment<BR> assume cs:binihex<BR> mov ch,4
;記錄轉換后的十六進制位數(四位)<BR> rotate: mov cl,4
;利用CL當計數器,記錄寄存器數位移動次數<BR> rol bx,cl
;循環寄存器BX的內容,以便依序處理4個十六進制數<BR> mov al,bl
;把bx低八位bl內數據轉移至al<BR> and al,0fh ;把無用位清零<BR> add
al,30h ;把AL內數據加30H,并存入al<BR> cmp al,3ah ;與3ah比較<BR> jl
printit ;小于3ah則轉移<BR> add al,7h
;把AL內數據加30H,并存入al<BR> printit:mov dl,al
;把ASCII碼裝入DL<BR> mov ah,2<BR> int 21h<BR> dec ch
;ch減一,減到零時,零標志置1<BR> jnz rotate
;JNZ:當零標志未置1,則跳到指定地址。即:不等,則轉移<BR> int 20h
;從子程序退回主程序<BR> binihex ends<BR>
end<BR> 利用循環左移指令ROL循環寄存器BX(BX內容將由第二個子程序提供)的內容,以便依序處理4個十六進制數:1.
利用CL當計數器,記錄寄存器移位的次數。2.將BX的第一個十六進制值移到最右邊。利用 AND
(邏輯“與”運算:對應位都為1時,其結果為1,其余情況為零)把不要的部份清零,得到結果:先將BL值存入AL中,再利用AND以0Fh(00001111)將AL的左邊四位清零。由于0到9的ASCII碼為30h到39h,而A到F之ASCII碼為41h到46h,間斷了7h,所以得到結果:若AL之內容小于3Ah,則AL值只加30h,否則AL再加7h。ADD指令會將兩個表達式相加,其結果存于左邊表達式內。標志寄存器(Flag
Register)是一個單獨的十六位寄存器,有9個標志位,某些匯編指令(大部份是涉及比較、算術或邏輯運算的指令)執行時,會將相關標志位置1或清0,
常碰到的標志位有零標志(ZF)、符號標志(SF)、溢出標志(OF)和進位標志(CF)。
標志位保存了某個指令執行后對它的影響,可用其他相關指令,查出標志的狀態,根據狀態產生動作。CMP指令很像減法,是將兩個表達式的值相減,但寄存器或內存的內容并未改變,只是相對的標志位發生改變而已:若
AL 值小于 3Ah,則正負號標志位會置0,反之則置1。
JL指令可解釋為:小于就轉移到指定位置,大于、等于則向下執行。CMP和JG
、JL等條件轉移指令一起使用,可以形成程序的分支結構,是寫匯編程序常用技巧。<BR> 第二個模塊DECIBIN
用來接收鍵盤打入的十進制數,并將它轉換成二進制數放于BX 寄存器中,供模塊1
BINIHEX使用。<BR> decibin segment<BR> assume
cs:decibin<BR> mov bx,0 ;BX清零<BR> newchar:mov ah,1
;<BR> int 21h ;讀一個鍵盤輸入符號入al,并顯示<BR> sub al,30h
;al減去30H,結果存于al中,完成ASCII碼轉二進制碼<BR> jl exit
;小于零則轉移<BR> cmp al,9d<BR> jg exit
;左&gt;右則轉移<BR> cbw ;8位al轉換成16位ax<BR> xchg ax,bx
;互換ax和bx內數據<BR> mov cx,10d ;十進制數10入cx<BR> mul cx
;表達式的值與ax內容相乘,并將結果存于ax<BR> xchg ax,bx<BR> add
bx,ax<BR> jmp newchar ;無條件轉移<BR> exit: int 20
;回主程序<BR> decibin ends<BR> end<BR> CBW
實際結果是:若AL中的值為正,則AH填入00h;反之,則AH填入FFh。XCHG常用于需要暫時保留某個寄存器中的內容時。<BR> 當然,還得一個子程序(CRLF)使后顯示的十六進制數不會蓋掉先輸入的十進制數。<BR> crlf
segment<BR> assume cs:crlf<BR> mov dl,0dh
;回車的ASCII碼0DH入DL<BR> mov ah,2<BR> int 21h<BR> mov
dl,0ah ;換行的ASSII碼0AH入AH<BR> mov ah,2<BR> int
21h<BR> int 20 ;回主程序<BR> crlf
ends<BR> end<BR> 現在我們就可以將BINIHEX、DECIBIN及CRLF等模塊合并成一個大程序了。首先,我們要將這三個模塊子程序略加改動。然后,再寫一段程序來調用每一個子程序。<BR> crlf
proc near;<BR> mov dl,0dh<BR> mov ah,2<BR> int
21h<BR> mov dl,0ah<BR> mov ah,2<BR> int
21h<BR> ret<BR> crlf
endp<BR> 類似SEGMENT與ENDS的偽指令,PROC與ENDP也是成對出現,用來識別并定義一個程序。其實,PROC
真正的作用只是告訴編譯器:所調用的程序是屬于近程(NEAR)或遠程(FAR)。 一般的程序是由 DEBUG
直接調用的,所以用 INT 20 返回,用 CALL
指令所調用的程序則改用返回指令RET,RET會把控制權轉移到棧頂所指的地址,而該地址是由調用此程序的
CALL指令所放入的。<BR> 各模塊都搞定了,然后我們把子程序組合起來就大功告成<BR> decihex
segment ;主程序<BR> assume cs:decihex<BR> org
100h<BR> mov cx,4
;循環次數入cx;由于子程序要用到cx,故子程序要將cx入棧<BR> repeat: call
decibin;調用十進制轉二進制子程序<BR> call crlf
;調用添加回、換行符子程序<BR> call binihex
;調用二進制轉十六進制并顯示子程序<BR> call crlf<BR> loop repeat
;循環4次,可連續運算4次<BR> mov ah,4ch ;
調用DOS21號中斷4c號功能,退出程序,作用跟INT 20H<BR> int 21H ;
一樣,但適用面更廣,INT20H退不出時,試一下它<BR> decibin proc near push cx
;將cx壓入堆棧,;<BR> ┇ exit: pop cx ;將cx還原; retdecibin endp
binihex proc near push cx<BR> ┇ pop cx retbinihex endp
crlf proc near<BR> push cx<BR> ┇ pop cx retcrlf
endpdecihex ends
end<BR> CALL指令用來調用子程序,并將控制權轉移到子程序地址,同時將CALL的下行一指令地址定為返回地址,并壓入堆棧中。CALL
可分為近程(NEAR)及遠程(FAR)兩種:1.NEAR:IP的內容被壓入堆棧中,用于程序與程序在同一段中。2.FAR:CS
、IP寄存器的內容依次壓入堆棧中,用于程序與程序在不同段中。PUSH、POP又是一對指令用于將寄存器內容壓入、彈出,用來保護寄存器數據,子程序調用中運用較多。堆棧指針有個“后進先出”原則,像PUSH
AX,PUSH BX…POP BX,POP
AX這樣才能作到保護數據絲毫不差。<BR> 匯編語言超濃縮教程到這要告一段落了,希望能奠定你獨立設計的基礎。而更多更好的技巧則全依賴你平時的積累了。祝你成功![MP=480,360,true]http://www.elyg.org/jh/bbs/uploadfile/mp3/shuilian.mp3[/MP]<BR>
<P align=right><FONT color=#000066>[此貼子已經被作者于2004-10-14
18:16:48編輯過]</FONT></P><BR><BR></TD></TR>
<TR>
<TD vAlign=bottom><IMG
src="E路陽光 - 編程專區 - 匯編語言超濃縮教程 天天好心情!.files/sigline.gif"><BR>和你的年紀、差了一個音階。
<BR>對是否能吹響它、我感到非常的不安...。 <BR>在吹著熟悉的海風的夜晚、你所彈的風琴的音色反映著月光。
<BR>就這樣、分離的指尖、碎掉的四葉草、打開了弧光街道的門扉。 <BR>
<OBJECT id=RAOCX height=60 width=253
classid=clsid:CFCDAA03-8BE4-11CF-B84B-0020AFBBCCFA><PARAM NAME="_ExtentX" VALUE="6694"><PARAM NAME="_ExtentY" VALUE="1588"><PARAM NAME="AUTOSTART" VALUE="0"><PARAM NAME="SHUFFLE" VALUE="0"><PARAM NAME="PREFETCH" VALUE="0"><PARAM NAME="NOLABELS" VALUE="0"><PARAM NAME="SRC" VALUE="http://bbs.elyg.org/UploadFile/xiny.mp3"><PARAM NAME="CONTROLS" VALUE="StatusBar,ControlPanel"><PARAM NAME="LOOP" VALUE="0"><PARAM NAME="NUMLOOP" VALUE="0"><PARAM NAME="CENTER" VALUE="0"><PARAM NAME="MAINTAINASPECT" VALUE="0"><PARAM NAME="BACKGROUNDCOLOR" VALUE="#000000">
<embed src="http://bbs.elyg.org/UploadFile/xiny.mp3"
width="253" autostart="true"
height="60"></embed></OBJECT><BR><A
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -