史萊姆論壇

返回   史萊姆論壇 > 教學文件資料庫 > 應用軟體使用技術文件
忘記密碼?
論壇說明

歡迎您來到『史萊姆論壇』 ^___^

您目前正以訪客的身份瀏覽本論壇,訪客所擁有的權限將受到限制,您可以瀏覽本論壇大部份的版區與文章,但您將無法參與任何討論或是使用私人訊息與其他會員交流。若您希望擁有完整的使用權限,請註冊成為我們的一份子,註冊的程序十分簡單、快速,而且最重要的是--註冊是完全免費的!

請點擊這裡:『註冊成為我們的一份子!』

Google 提供的廣告


 
 
主題工具 顯示模式
舊 2006-04-20, 10:02 AM   #1
psac
榮譽會員
 
psac 的頭像
榮譽勳章
UID - 3662
在線等級: 級別:30 | 在線時長:1048小時 | 升級還需:37小時級別:30 | 在線時長:1048小時 | 升級還需:37小時級別:30 | 在線時長:1048小時 | 升級還需:37小時級別:30 | 在線時長:1048小時 | 升級還需:37小時級別:30 | 在線時長:1048小時 | 升級還需:37小時
註冊日期: 2002-12-07
住址: 木柵市立動物園
文章: 17381
現金: 5253 金幣
資產: 33853 金幣
預設 彙編譯語言超濃縮教學

彙編語言超濃縮教學

「 哎喲,哥們兒,還搗鼓彙編呢?那東西沒用,兄弟用VB"釣"一個API就夠你忙活個十天半月的,還不一定搞出來。」此君之言倒也不虛,那吾等還有無必要研他一究呢?(廢話,當然有啦!要不然你寫這篇文章幹嘛。)別急,別急,讓我把這個中原委慢慢道來:一、所有電腦語言寫出的程序執行時在記憶體中都以機器碼方式儲存於,機器碼可以被比較準確的翻譯成彙編語言,這是因為彙編語言相容性最好,故幾乎所有跟蹤、偵錯工具(包括WIN95/98下)都是以彙編示人的,如果閣下對CRACK頗感興趣……;二、彙編直接與硬體打交道,如果你想搞通程序在執行時在電腦中的來龍去脈,也就是搞清電腦每個組成部分究竟在幹什麼、究竟怎麼幹?一個真正的硬體發燒友,不懂這些可不行。三、如今玩DOS的多是「高手」,如能像吾一樣混入(我不是高手)「高手」內部,不僅可以從「高手」朋友那兒套些黑客級「機密」,還可以自詡「高手」盡情享受強烈的虛榮感--#$%& 「醒醒!」

對初學者而言,彙編的許多指令太複雜,往往教學很長時間也寫不出一個漂漂亮亮的程序,以致妨礙了我們教學彙編的興趣,不少人就此放棄。所以我個人看法學彙編,不一定要寫程序,寫程序確實不是彙編的強項,大家不妨玩玩DEBUG,有時CRACK出一個小軟體比完成一個程序更有成就感(就像學電腦先玩遊戲一樣)。某些高深的指令事實上只對有經驗的彙編程序員有用,對我們而言,太過高深了。為了使教學彙編語言有個好的開始,你必須要先排除那些華麗複雜的指令,將注意力集中在最重要的幾個指令上(CMP LOOP MOV JNZ……)。但是想在囉哩吧嗦的教科書中完成上述目標,談何容易,所以本人整理了這篇超濃縮(用WINZIP、WINRAR…依次壓迫,嘿嘿!)教學。大言不慚的說,看通本文,你完全可以「不經意」間在前輩或是後生賣弄一下DEBUG,很有成就感的,試試看!那麼--這個接下來呢?-- Here we go!(閱讀時看不懂不要緊,下文必有分解)

因為彙編是通過CPU和記憶體跟硬體對話的,所以我們不得不先瞭解一下CPU和記憶體:(關於數的進制問題在此不提)

CPU是可以執行電腦所有算術╱邏輯運算與基本 I/O 控制功能的一塊晶片。一種彙編語言只能用於特定的CPU。也就是說,不同的CPU其彙編語言的指令語法亦不相同。個人電腦由1981年推出至今,其CPU發展程序為:8086→80286→80386→80486→PENTIUM →……,還有AMD、CYRIX等旁支。後面相容前面CPU的功能,只不過多了些指令(如多能奔騰的MMX指令集)、增大了暫存器(如386的32位EAX)、增多了暫存器(如486的FS)。為確保彙編程序可以適用於各種機型,所以推薦使用8086彙編語言,其相容性最佳。本文所提均為8086彙編語言。暫存器(Register)是CPU內部的元件,所以在暫存器之間的資料傳送非常快。用途:1.可將暫存器內的資料執行算術及邏輯運算。2.存於暫存器內的位址可用來指向記憶體的某個位置,即尋址。3.可以用來讀寫資料到電腦的周邊設備。8086 有8個8位資料暫存器,這些8位暫存器可分別組成16位暫存器:AH&AL=AX:累加暫存器,常用於運算;BH&BL=BX:基址暫存器,常用於位址索引;CH&CL=CX:計數暫存器,常用於計數;DH&DL=DX:資料暫存器,常用於資料傳送。為了運用所有的記憶體空間,8086設定了四個段暫存器,專門用來儲存段位址:CS(Code Segment):程式碼段暫存器;DS(Data Segment):資料段暫存器;SS(Stack Segment):堆疊段暫存器;ES(Extra Segment):附加段暫存器。當一個程序要執行時,就要決定程序程式碼、資料和堆疊各要用到記憶體的哪些位置,通過設定段暫存器 CS,DS,SS 來指向這些起始位置。通常是將DS固定,而根據需要修改CS。所以,程序可以在可尋址空間小於64K的情況下被寫成任意大小。 所以,程序和其資料組合起來的大小,限制在DS 所指的64K內,這就是COM文件不得大於64K的原因。8086以記憶體做為戰場,用暫存器做為軍事基地,以加速工作。除了前面所提的暫存器外,還有一些特殊功能的暫存器:IP(Intruction Pointer):指令游標暫存器,與CS配合使用,可跟蹤程序的執行程序;SP(Stack Pointer):堆疊游標,與SS配合使用,可指向目前的堆疊位置。BP(Base Pointer):基址游標暫存器,可用作SS的一個相對基址位置;SI(Source Index):源變址暫存器可用來存放相對於DS段之源變址游標;DI(Destination Index):目的變址暫存器,可用來存放相對於 ES 段之目的變址游標。還有一個標誌暫存器FR(Flag Register),有九個有意義的標誌,將在下文用到時詳細說明。

記憶體是電腦運作中的關鍵部分,也是電腦在工作中儲存訊息的地方。記憶體組織有許多可存放數值的儲存位置,叫「位址」。8086位址總線有20位,所以CPU擁有達1M的尋址空間,這也是DOS的有效控制範圍,而8086能做的運算僅限於處理16位資料,即只有0到64K,所以,必須用分段尋址才能控制整個記憶體位址。完整的20位位址可分成兩部份:1.段基址(Segment):16位二進制數後面加上四個二進制0,即一個16進制0,變成20位二進制數,可設定1M中任何一個64K段,通常記做16位二進制數;2.偏移量(Offset):直接使用16位二進制數,指向段基址中的任何一個位址。如:2222(段基址):3333(偏移量),其實際的20位位址值為:25553。除了上述營養要充分吸收外,你還要知道什麼是DOS、BIOS功能使用,簡單的說,功能使用類似於WIN95 API,相當於子程序。彙編寫程序已經夠要命了,如果不用MS、IBM的子程序,這日子真是沒法過了(關於功能使用詳見《電腦愛好者》98年11期)。

編寫彙編語言有兩種主要的方法:1.使用MASM或TASM等編譯器;2.使用除錯程序DEBUG.COM。DEBUG其實並不能算是一個編譯器,它的主要用途在於除錯,即修正彙編程序中的錯誤。不過,也可以用來寫短的彙編程序,尤其對初學者而言,DEBUG 更是最佳的入門工具。因為DEBUG操作容易:只要按鍵輸入DEBUGEnter鍵,AEnter鍵即可進行彙編,程序簡單,而使用編譯器時,必須用到文本編輯器、編譯器本身、LINK以及EXE2BIN等程序,其中每一個程序都必須用到一系列相當複雜的指令才能工作,而且用編譯器處理源程序,必須加入許多與指令語句無關的指示性語句,以供編譯器識別,使用 DEBUG 可以避免一開始就碰到許多難以理解的程序行。DEBUG 除了能夠彙編程序之外,還可用來檢查和修改記憶體位置、載入儲存和執行程序、以及檢查和修改暫存器,換句話說,DEBUG是為了讓我們接觸硬體而設計的。(8086常用指令用法將在每個彙編程序中講解,限於篇幅,不可能將所有指令列出)。

DEBUG的的A指令可以彙編出簡單的COM文件,所以DEBUG編寫的程序一定要由位址 100h(COM文件要求)開始才合法。FOLLOW ME,SETP BY SETP(步步Enter鍵):

輸入 A100 ; 從DS:100開始彙編
2.輸入 MOV DL,1 ; 將數值 01h 裝入 DL 暫存器

3.輸入 MOV AH,2 ; 將數值 02h 裝入 DL 暫存器

4.輸入 INT 21 ; 使用DOS 21號中斷2號功能,用來逐個顯示裝入DL的字元

5.輸入 INT 20 ; 使用DOS 20號中斷,終止程序,將控制權交回給 DEBUG

6.請按 Enter 鍵

7.現在已將彙編語言程序放入記憶體中了,輸入 G(執行)

8.出現結果:輸出一個符號。

ㄖ ←輸出結果其實不是它,因WORD97無法顯示原結果,故找一贗品將就著。

Program terminated normally

我們可以用U指令將十六進制的機器碼反彙編(Unassemble)成彙編指令。你將發現每一行右邊的彙編指令就是被彙編成相應的機器碼,而8086實際上就是以機器碼來執行程序。

1.輸入 U100,106

1FED:0100 B201 MOV DL,01

1FED:0102 B402 MOV AH,02

1FED:0104 CD21 INT 21

1FED:0106 CD20 INT 20

DEBUG可以用R指令來檢視、改變暫存器內容。CS:IP暫存器,儲存了將執行指令位址。

1.輸入R

AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000

DS=1FED ES=1FED SS=1FED CS=1FED IP=0100 NV UP EI PL NZ NA PO NC

1FED:0100 B201 MOV DL,01

當程序由DS:100開始執行,那麼終止程序時,DEBUG會自動將IP內容重新設定為100。當你要將此程序做成一個獨立的可執行文件,則可以用N指令對該程序命名。但一定要為COM文件,否則無法以DEBUG載入。

輸入N SMILE.COM ;我們得告訴DEBUG程序長度:程序從100開始到106,故佔用7
;字元。我們利用BX存放長度值高位部分,而以CX存放低位元部分。

2.輸入RBX ;檢視 BX 暫存器的內容,本程序只有7個字元,故本步可省略

3.輸入 RCX  ;檢視 CX 暫存器的內容

4.輸入 7  ;程序的字元數

5.輸入 W ;用W指令將該程序寫入(Write)磁牒中

修行至此,我們便可以真正接觸8086彙編指令了。 當我們寫彙編語言程序的時候,通常不會直接將機器碼放入記憶體中,而是打入一串助記符號(Mnemonic Symbols),這些符號比十六進制機器碼更容易記住,此之謂彙編指令。助記符號,告訴CPU應執行何種運算。 也就是說,助憶符號所構成的彙編語言是為人設計的,而機器語言是對PC設計的。

現在,我們再來分析一個可以將所有ASCII碼顯示出來的程序。

1. 輸入 DEBUG

2. 輸入 A100

3.輸入 MOV CX,0100 ;裝入循環次數

MOV DL,00 ;裝入第一個ASCII碼,隨後每次循環裝入新碼

MOV AH,02

INT 21

INC DL ;INC:遞增指令,每次將資料暫存器 DL 內的數值加 1

LOOP 0105 ;LOOP:循環指令,每執行一次LOOP,CX值減1,並跳

;到循環的起始位址105,直到CX為0,循環停止

INT 20

4.輸入 G即可顯示所有ASCII碼

當我們想任意顯示字元串,如:UNDERSTAND?,則可以使用DOS21H號中斷9H號功能。輸入下行程序,儲存碟並執行看看:

1.輸入 A100

MOV DX,109 ;DSX = 字元串的起始位址

MOV AH,9 ;DOS的09h功能使用

INT 21 ;字元串輸出

INT 20

DB 'UNDERSTAND?$';定義字元串

在彙編語言中,有兩種不同的指令:1.正規指令:如 MOV 等,是屬於CPU的指令,用來告訴CPU在程序執行時應做些什麼,所以它會以運算碼(OP-code)的方式存入記憶體中;2.偽指令:如DB等,是屬於DEBUG等編譯器的指令,用來告訴編譯器在編譯時應做些什麼。DB(Define Byte)指令用來告訴DEBUG 將單引號內的所有ASCII 碼放入記憶體中。使用 9H 功能的字元串必須以$結尾。用D指令可用來檢視DB偽指令將那些內容放入記憶體。

6.輸入 D100

1975:0100 BA 09 01 B4 09 CD 21 CD-20 75 6E 64 65 72 73 74 ......!. underst

1975:0110 61 6E 64 24 8B 46 F8 89-45 04 8B 46 34 00 64 19 and$.F..E..F4.d.

1975:0120 89 45 02 33 C0 5E 5F C9-C3 00 C8 04 00 00 57 56 .E.3.^_.......WV

1975:0130 6B F8 0E 81 C7 FE 53 8B-DF 8B C2 E8 32 FE 0B C0 k.....S.....2...

1975:0140 74 05 33 C0 99 EB 17 8B-45 0C E8 D4 97 8B F0 89 t.3.....E.......

1975:0150 56 FE 0B D0 74 EC 8B 45-08 03 C6 8B 56 FE 5E 5F V...t..E....V.^_

1975:0160 C9 C3 C8 02 00 00 6B D8-0E 81 C3 FE 53 89 5E FE ......k.....S.^.

1975:0170 8B C2 E8 FB FD 0B C0 75-09 8B 5E FE 8B 47 0C E8 .......u..^..G..

現在,我們來分析另一個程序:由鍵盤輸入任意字元串,然後顯示出來。db 20指示DEBUG保留20h個未用的記憶體空間供緩衝區使用。

輸入A100

MOV DX,0116 ;DSX = 緩衝區位址,由DB偽指令確定緩衝區位址

MOV AH,0A ;0Ah 號功能使用

INT 21 ;鍵盤輸入緩衝區

MOV DL,0A ;由於功能Ah在每個字元串最後加一個歸位碼(0Dh由 Enter

MOV AH,02 ;產生),使游標自動回到輸入行的最前端,為了使新輸出的

INT 21 ;字元串不會蓋掉原來輸入的字元串,所以利用功能2h加一

;個換行碼(OAh),使得游標移到下一行的的最前端。

MOV DX,0118 ;裝入字元串的起始位置

MOV AH,09 ;9h功能遇到$符號才會停止輸出,故字元串最後必須加上

INT 21 ;$,否則9h功能會繼續將記憶體中的無用資料胡亂顯示出來

INT 20

DB 20 ;定義緩衝區

送你一句話:學彙編切忌心浮氣燥。

客套話就不講了。工欲善其事,必先利其器。與其說DEBUG 是編譯器,倒不如說它是「直譯器」,DEBUG的A指令只可將一行彙編指令轉成機器語言,且立刻執行。真正編譯器(MASM)的運作是利用文本編輯器(EDIT等)將彙編指令建成一個獨立且附加名為.ASM的文本文件,稱源程序。它是MASM 程序的輸入部分。MASM將輸入的ASM文件,編譯成.OBJ文件,稱為目標程序。OBJ文件僅包含有關程序各部份要載入何處及如何與其他程序合併的訊息,無法直接載入記憶體執行。鏈結程序LINK則可將OBJ文件轉換成可載入記憶體執行(EXEcute)的EXE文件。還可以用EXE2BIN,將符合條件的EXE文件轉成COM文件(COM 文件不但佔用的記憶體最少,而且執行速度最快)。

下面我們用MASM寫一個與用DEBUG寫的第一個程序功能一樣的程序。

用EDIT編輯一個SMILE.ASM的源程式文件。

源程序 DEBUG 程序

prognam segment

assume csrognam

org 100h A100

mov dl,1 mov dl,1

mov ah,2 mov ah,2

int 21h int 21

int 20h int 20

prognam ends

end

比較一下:1.因為MASM會將所有的數值假設為十進制,而DEBUG則只使用十六進制,所以在源程序中,我們必須在有關數位後加上代表進制的字母,如H代表十六進制,D代表十進制。若是以字母開頭的十六進制數位,還必須在字母前加個0,以表示它是數,如0AH。2.源程序增加五行敘述:prognam segment 與 prognam ends 是成對的,用來告訴 MASM 及LINK,此程序將放在一個稱為PROGNAM(PROGram NAMe)的程序段內,其中段名(PROGNAM)可以任取,但其位置必須固定。assume csrognam 必須在程序的開頭,用來告訴編譯器此程序所在段的位置放在CS暫存器中。end用來告訴MASM,程序到此結束, ORG 100H作用相當於DEBUG的A100,從偏移量100開始彙編。COM 文件的所有源程序都必須包含這五行,且必須依相同的次序及位置出現,這點東西記下就行,千篇一律。接著,我們用MASM編譯SMILE.ASM。

輸入 MASM SMILE ←不用打入附加名.ASM。

Microsoft (R) Macro Assembler Version 5.10

Copyright (C) Microsoft Corp 1981, 1988. All rights reserved.

Object filename [SMILE.OBJ]: ←是否改動輸出OBJ檔案名,如不改就ENTER

Source listing [NUL.LST]: ← 是否需要列表文件(LST),不需要就ENTER

Cross-reference [NUL.CRF]: ←是否需要對照文件(CRF),不需要則ENTER

50162 + 403867 Bytes symbol space free

0 Warning Errors ←警告錯誤,表示編譯器對某些語句不理解,通常是輸入錯誤。

0 Severe Errors ←嚴重錯誤,會造成程序無法執行,通常是語法結構錯誤。

如果沒有一個錯誤存在,即可產生OBJ文件。OBJ中包含的是編譯後的二進制結果,它還無法被 DOS載入記憶體中加以執行,必須加以鏈結(Linking)。以LINK將OBJ文件(SMILE.OBJ)鏈結成 EXE 文件(SMILE.EXE)時,。

1.輸入 LINK SMILE ←不用附加名OBJ

Microsoft (R) Overlay Linker Version 3.64

Copyright (C) Microsoft Corp 1981, 1988. All rights reserved.

Run File [SMILE.EXE]: ← 是否改動輸出EXE檔案名,如不改就ENTER

List File [NUL.MAP]: ← 是否需要列表文件(MAP),不需要則ENTER

Libraries [.LIB]: ←是否需要庫文件,要就按鍵輸入檔案名,不要則ENTER

LINK : warning L4021: no stack segment← 由於COM文件不使用堆疊段,所以錯誤訊息

←"no stack segment"並不影響程序正常執行

至此已經產生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:>下,直接輸入檔案名稱 SMILE ,就可以執行這個程序了。

你是否覺得用編譯器產生程序的方法,比 DEBUG 麻煩多了!以小程序而言,的確是如此,但對於較大的程序,你就會發現其優點了。我們再將ASCII程序以編譯器方式再做一次,看看有無差異。首先,用EDIT.COM建立 ASCII.ASM 文件。

prognam segment 定義段

assume csrognam 把上面定義段的段基址放入 CS

mov cx,100h 裝入循環次數

mov dl,0 裝入第一個ASCII碼,隨後每次循環裝入新碼

next: mov ah,2

int 21h

inc dl INC:遞增指令,每次將資料暫存器 DL 內的數值加 1

loop next 循環指令,執行一次,CX減1,直到CX為0,循環停止

int 20h

prognam ends 段終止

end 彙編終止

在彙編語言的源程序中,每一個程序行都包含三項元素:

  start: mov dl,1 ;裝入第一個ASCII碼,隨後每次循環裝入新碼

  標幟符 陳述式 註解

在原始文件中加上註解可使程序更易理解,便於以後參考。每行註解以「;」與程序行分離。編譯器對註解不予理會,註解的資料不會出現在OBJ、EXE或COM文件中。由於我們在寫源程序時,並不知道每一程序行的位址,所以必須以符號名稱來代表相對位址,稱為「標幟符」。我們通常在適當行的適當位置上,按鍵輸入標幟符。標幟符(label)最長可達31 個字元,因此我們在程序中,盡量以簡潔的文字做為標幟符。現在,你可以將此ASCII.ASM 文件編譯成 ASCII.COM 了。1.MASM ASCII,2.LINK ASCII,3.EXE2BIN ASCII ASCII.COM。

注意:當你以編譯器彙編你設計的程序時,常會發生打字錯誤、標幟符名稱拼錯、十六進制數少了h、邏輯錯誤等。彙編老手常給新人的忠告是:最好料到自己所寫的程序一定會有些錯誤(別人告訴我的);如果第一次執行程序後,就得到期望的結果,你最好還是在檢查一遍,因為它可能是錯的。原則上,只要大體的邏輯架構正確,搜尋程序中錯誤的程序,與寫程序本身相比甚至更有意思。寫大程序時,最好能分成許多模組,如此可使程序本身的目的較單純,易於撰寫與查錯,另外也可讓程序中不同部份之間的界限較清楚,節省編譯的時間。如果讀程序有讀不懂的地方最好用紙筆記下有關暫存器、記憶體等內容,在紙上慢慢比劃,就豁然開朗了。

下面我們將寫一個能從鍵盤取得一個十進制的數值,並將其轉換成十六進制數值而顯示於螢幕上的「大程序」。前言:要讓8086執行這樣的功能,我們必須先將此問題分解成一連串的步驟,稱為程序規劃。首先,以流程圖的方式,來確保整個程序在邏輯上沒有問題(不用說了吧!什麼語言都要有此步驟)。這種模組化的規劃方式,稱之為「由上而下的程序規劃」。而在真正寫程序時,卻是從最小的服務機構模組(子程序)開始,當每個模組都完成之後,再合併成大程序;這種大處著眼,小處著手的方式稱為「由下而上的程序設計」。

我們的第一個模組是BINIHEX,其主要用途是從8086的BX暫存器中取出二進制數,並以十六進制方式顯示在螢幕上。注意:子程序如不能獨立執行,實屬正常。

binihex segment

assume cs:binihex

mov ch,4 記錄轉換後的十六進制位數(四位)

rotate: mov cl,4 利用CL當計數器,記錄暫存器數位移動次數

rol bx,cl 循環暫存器BX的內容,以便依序處理4個十六進制數

mov al,bl 把bx低八位bl內資料轉移至al

and al,0fh 把無用位清零

add al,30h 把AL內資料加30H,並存入al

cmp al,3ah 與3ah比較

jl printit 小於3ah則轉移

add al,7h 把AL內資料加30H,並存入al

printit:mov dl,al 把ASCII碼裝入DL

mov ah,2

int 21h

dec ch ch減一,減到零時,零標誌置1

jnz rotate JNZ:當零標誌未置1,則跳到指定位址。即:不等,則轉移

int 20h 從子程序退回主程序

binihex ends

end

利用循環左移指令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等條件轉移指令一起使用,可以形成程序的分支結構,是寫彙編程序常用技巧。

第二個模組DECIBIN 用來接收鍵盤打入的十進制數,並將它轉換成二進制數放於BX 暫存器中,供模組1 BINIHEX使用。

decibin segment

assume cs:decibin

mov bx,0 BX清零

newchar:mov ah,1

int 21h 讀一個鍵盤輸入符號入al,並顯示

sub al,30h al減去30H,結果存於al中,完成ASCII碼轉二進制碼

jl exit 小於零則轉移

cmp al,9d

jg exit 左>右則轉移

cbw 8位al轉換成16位ax

xchg ax,bx 互換ax和bx內資料

mov cx,10d 十進制數10入cx

mul cx 陳述式的值與ax內容相乘,並將結果存於ax

xchg ax,bx

add bx,ax

jmp newchar 無條件轉移

exit: int 20 回主程序

decibin ends

end

CBW 實際結果是:若AL中的值為正,則AH填入00h;反之,則AH填入FFh。XCHG常用於需要暫時保留某個暫存器中的內容時。

當然,還得一個子程序(CRLF)使後顯示的十六進制數不會蓋掉先輸入的十進制數。

crlf segment

assume cs:crlf

mov dl,0dh Enter鍵的ASCII碼0DH入DL

mov ah,2

int 21h

mov dl,0ah 換行的ASSII碼0AH入AH

mov ah,2

int 21h

int 20 回主程序

crlf ends

end

現在我們就可以將BINIHEX、DECIBIN及CRLF等模組合併成一個大程序了。首先,我們要將這三個模組子程序略加改動。然後,再寫一段程序來使用每一個子程序。

crlf proc near;

mov dl,0dh

mov ah,2

int 21h

mov dl,0ah

mov ah,2

int 21h

ret

crlf endp

類似SEGMENT與ENDS的偽指令,PROC與ENDP也是成對出現,用來識別並定義一個程序。其實,PROC 真正的作用只是告訴編譯器:所使用的程序是屬於近程(NEAR)或遠端(FAR)。 一般的程序是由 DEBUG 直接使用的,所以用 INT 20 返回,用 CALL 指令所使用的程序則改用返回指令RET,RET會把控制權轉移到推疊頂端所指的位址,而該位址是由使用此程序的 CALL指令所放入的。

各模組都搞定了,然後我們把子程序組合起來就大功告成

decihex segment 主程序

assume cs:decihex

org 100h

mov cx,4 循環次數入cx;由於子程序要用到cx,故子程序要將cx壓入推疊

repeat: call decibin;使用十進制轉二進制子程序

call crlf 使用增加回、換行符子程序

call binihex 使用二進制轉十六進制並顯示子程序

call crlf

loop repeat 循環4次,可連續運算4次

mov ah,4ch 使用DOS21號中斷4c號功能,結束程序,作用跟INT 20H

int 21H 一樣,但適用面更廣,INT20H退不出時,試一下它

decibin proc near push cx 將cx壓入堆疊,;

│ exit: pop cx 將cx還原; retdecibin endp binihex proc near push cx

│ pop cx retbinihex endp crlf proc near

push cx

│ pop cx retcrlf endpdecihex ends end

CALL指令用來使用子程序,並將控制權轉移到子程序位址,同時將CALL的下行一指令位址定為返回位址,並壓入堆疊中。CALL 可分為近程(NEAR)及遠端(FAR)兩種:1.NEAR:IP的內容被壓入堆疊中,用於程序與程序在同一段中。2.FAR:CS 、IP暫存器的內容依次壓入堆疊中,用於程序與程序在不同段中。PUSH、POP又是一對指令用於將暫存器內容壓入、彈出,用來保護暫存器資料,子程序使用中運用較多。堆疊游標有個「後進先出」原則,像PUSH AX,PUSH BX…POP BX,POP AX這樣才能作到保護資料絲毫不差。

彙編語言超濃縮教學到這要告一段落了,希望能奠定你獨立設計的基礎。而更多更好的技巧則全依賴你平時的積累了。祝你成功!
__________________
http://bbsimg.qianlong.com/upload/01/08/29/68/1082968_1136014649812.gif
psac 目前離線  
送花文章: 3, 收花文章: 1631 篇, 收花: 3205 次
 



發表規則
不可以發文
不可以回覆主題
不可以上傳附加檔案
不可以編輯您的文章

論壇啟用 BB 語法
論壇啟用 表情符號
論壇啟用 [IMG] 語法
論壇禁用 HTML 語法
Trackbacks are 禁用
Pingbacks are 禁用
Refbacks are 禁用


所有時間均為台北時間。現在的時間是 02:29 PM


Powered by vBulletin® 版本 3.6.8
版權所有 ©2000 - 2024, Jelsoft Enterprises Ltd.


SEO by vBSEO 3.6.1