彙編語言——基本控制結構

基本控制結構
字符與字符串的輸入/輸出方法 
DOS系統調用INT 21H提供了字符及字符串的I/O功能,例如:
     01H:從鍵盤讀入一個字符
     02H:顯示一個字符
     09H:顯示一個字符串
     0AH:從鍵盤讀入一個字符串
1. 從鍵盤讀入一個字符
    功能號:01H
    出口參數:AL = 輸入字符的ASCII碼
    功能:等待從鍵盤讀入一個字符,將其ASCII碼送入AL,同時將該字符顯示在屏幕上。
    調用方法:
 mov ah, 1
 int 21h  
    說明:輸入一個字符後,不需要回車。若只鍵入回車,則AL = 0DH。
2. 顯示一個字符
     功能號:02H
     入口參數:DL = 要顯示字符的ASCII碼
    功能:在當前光標位置顯示DL中的字符,光標右移。
     調用方法示例:
 mov dl, 'A' ; 顯示字符'A'
 mov ah, 2
 int 21h  
      說明:顯示字符0DH和0AH將產生回車和換行的作用。
3. 顯示一個字符串
    功能號:09H
    入口參數:DS:DX = 欲顯示字符串在內存的首地址,且字符串必須以'$'(24H)作爲結束符。
    功能:在當前光標位置,顯示由DS:DX所指的、以'$'結尾的字符串,且光標右移。其中,'$'不算在顯示的字符串之內。
    調用方法示例:
 String db 'Hello!', '$'  ; 顯示字符串'Hello!'
  mov ax, seg String  
  mov ds, ax  
  mov dx, offset String
  mov ah, 9
  int 21h  
   4. 從鍵盤讀入一個字符串
    功能號:0AH
    入口參數:DS:DX = 輸入緩衝區首地址
    輸入緩衝區格式:第0字節事先設置爲緩衝區最多能容納的字符個數(包括回車);第1字節將存放實際字符個數(不包括回車),由系統自動設置;從第2字節開始存放實際輸入的字符串,最後爲回車符。
    功能:從鍵盤讀入一個字符串,存入DS:DX所指的緩衝區。
    調用方法示例:
 buf db 10, ?, 10 dup (?)  ; 定義輸入緩衝區
  mov ax, seg buf  
  mov ds, ax  
  lea dx, buf
  mov ah, 0ah
  int 21h  
5. 字符與字符串的輸入/輸出舉例
 DOS系統調用只提供了字符與字符串的輸入/輸出方法。如果要輸入/輸出其它類型的數據,如常用的整數,則必須由應用程序來實現與字符之間的轉換。例如,欲輸出整數126,只能以字符(串)的方式輸出'1' 、 '2' 、 '6' 。
 對於程序員來說,在需要用戶輸入時給出輸入提示,對輸入數據進行有效性檢查,在輸出結果時說明其表示的含義,是一種好的設計習慣。
 
JMP指令的靈活運用 
 用JMP指令實現轉移的多種方法:
 使用標號, 近轉移
 使用標號, 遠轉移
 以通用寄存器表示目標偏移地址
 以內存變量表示目標偏移地址
 以內存變量表示目標的32位分段地址
雙分支結構  
       雙分支結構相當於高級語言的IF-THEN-ELSE形式。IF-THEN結構只是IF-THEN-ELSE形式的特例,即ELSE部分爲空。
      通常,使用條件轉移指令Jcc與無條件轉移指令JMP來實現分支。一般必須先安排比較或算術、邏輯運算等影響標誌位的指令,然後用Jcc指令判斷條件,以實現分支轉移。
      對應於IF-THEN-ELSE結構的80x86彙編語言代碼形如:
 <爲測試條件cc做準備>
         Jcc    ElseCode
         <THEN 程序段>
       jmp     EndOfIF
ElseCode:
    <ELSE 程序段>
EndOfIF:
       注意,程序隱含是順序執行的,在THEN分支體執行後,不會自動跳過ELSE分支體,而是繼續執行其後的代碼。
對應於IF-THEN結構的80x86彙編語言代碼形如:
 <爲測試條件cc做準備>
         Jcc  EndOfIF
         <THEN 程序段>
EndOfIF:

多分支結構  
    多分支結構相當於高級語言的CASE語句。
    多分支程序的設計方法主要有:
 邏輯分解方法
將多分支結構以邏輯等效的方法,分解爲一串雙分支結構。
 地址表方法
   在數據段定義一個地址表,依次存放各分支對應處理程序的入口地址。
   通過將相應處理程序入口地址取入某寄存器,用間接轉移指令實現轉移。
 轉移表方法
   在代碼段建立一個轉移表,依次存放實現各分支的轉移指令。
   通過跳到轉移表的相應位置執行其中的轉移指令,從而實現轉到相應分支的處理程序。

循環結構
 
循環結構的基本形式 
循環結構的兩種基本形式:
 WHILE結構:先判斷、後執行
     其特點是進入循環後,先判斷循環控制條件。若滿足循環結束條件,則退出循環;否則,繼續執行循環體。循環體可能一次也不執行。
 UNTIL結構:先執行、後判斷
     其特點是進入循環後,先執行循環體,然後判斷循環控制條件。若滿足循環結束條件,則退出循環;否則,繼續執行循環體。循環體至少執行一次。該結構相當於PASCAL語言的REPEAT-UNTIL結構或C語言的DO-WHILE結構。
     具體選擇哪一種結構,取決於問題的特性以及使用者的偏好。一般來說,WHILE結構可能用得多一些。
      此外,象高級語言的FOR循環結構,主要用在循環次數已知的情況下。FOR結構總可以轉換爲等價的WHILE或UNTIL結構。
循環程序的控制方法  
(1)計數控制
        適用於循環次數已知的情況,包括正計數與倒計數兩種方法。 
(2)條件控制
        在實際問題中,常常有循環次數未知的情況。此時,就必須通過特定條件來控制循環。
(3)開關控制
        有時,循環內部又有分支,且每次循環執行的分支具有一定規律,這種結構非常類似於多分支結構。此時,可以採用開關來控制循環。具體方法是:
       在進入循環前,預置第一次循環的開關走向;在每次循環結束前,設置下一個開關方向,以便執行相應的操作。
      在實際應用中,開關的形式多種多樣。例如,設置一個狀態變量,取值0、1和2,分別表示執行的不同操作,就是一個開關。
(4)邏輯尺控制
       如果循環內分支的規律性不強,開關控制方法就難以勝任了。一種較有效的方法就是邏輯尺控制。所謂邏輯尺,就是一個位串,用1位或多位來控制每次循環所執行的操作。
 
串操作
串操作指令及其用途
1.  串操作指令
(1) MOVS(Move String):串傳送
       語法格式:
 MOVSB
 MOVSW
 MOVSD
      功能描述:
 ES:[DI] = DS:[SI];
         if ( DF = 0 ) then
               SI = SI + size;     DI = DI + size;
       else
               SI = SI – size;      DI = DI – size;
        endif
      其中,size = 1(B)、2(W)或4(D)。
      也就是說,MOVS(B/W/D)將DS:SI所指源串的1個元素(字節/字/雙字)複製到ES:DI所指的內存單元。然後,SI和DI增加或減少1/2/4。若DF = 0,則增加,否則減少。
      對標誌位的影響:無。
(2)LODS(Load String):串裝入
      語法格式:
 LODSB
 LODSW
 LODSD
      功能描述:
 AL/AX/EAX = DS:[SI];
         if ( DF = 0 )then
              SI = SI + size;
       else
              SI = SI – size;
        endif
      其中, size = 1(B)、2(W)或4(D)。
      也就是說,LODS(B/W/D)將DS:SI所指源串的1個元素(字節/字/雙字)複製到AL/AX/EAX。然後,SI增加或減少1/2/4。若DF = 0,則增加,否則減少。
      對標誌位的影響:無。
 
(3)STOS(Store String):串存儲
      語法格式:
 STOSB
 STOSW
 STOSD
      功能描述:
 ES:[DI] = AL/AX/EAX;
         if ( DF = 0 )then
                   DI = DI + size;
       else
                        DI = DI – size;
        endif
      其中,size = 1(B)、2(W)或4(D)。
      也就是說,STOS(B/W/D)將AL/AX/EAX的值複製到ES:DI所指的內存單元。然後,DI增加或減少1/2/4。若DF = 0,則增加,否則減少。
      對標誌位的影響:無。
(4)CMPS(Compare Strings):串比較
      語法格式:
 CMPSB
 CMPSW
 CMPSD
      功能描述:
 DS:[SI] – ES:[DI];
         if ( DF = 0 )then
               SI = SI + size;  DI = DI + size;
       else
               SI = SI – size;  DI = DI – size;
        endif
      其中,size = 1(B)、2(W)或4(D)。
      也就是說,CMPS(B/W/D)將DS:SI所指源串的1個元素(字節/字/雙字)與ES:DI所指目的串的1個元素(字節/字/雙字)進行比較,根據比較結果設置標誌位。然後,SI和DI增加或減少1/2/4。若DF = 0,則增加,否則減少。
      對標誌位的影響:同CMP。
(5)SCAS(Scan String):串掃描
      語法格式:
 SCASB
 SCASW
 SCASD
      功能描述:
 AL/AX/EAX – ES:[DI];
         if ( DF = 0 )then
                   DI = DI + size;
       else
                   DI = DI – size;
        endif
      其中,size = 1(B)、2(W)或4(D)。
       也就是說,SCAS(B/W/D)將AL/AX/EAX與ES:DI所指目的串的1個字節/字/雙字進行比較,根據比較結果設置標誌位。然後,DI增加或減少1/2/4。若DF = 0,則增加,否則減少。
 
(6)重複前綴
 REP  ; 當CX <> 0時,重複執行後面的串指令
   ; 每執行1次,CX = CX – 1
   ; 只能用在MOVS、LODS或STOS(B/W/D)之前
 REPZ/REPE ; 當CX <> 0且ZF = 1時,重複執行後面的串指令
   ; 每執行1次,CX = CX – 1
   ; 只能用在CMPS(B/W/D)或SCAS(B/W/D)之前
 REPNZ/REPNE ; 當CX <> 0且ZF = 0時,重複執行後面的串指令
   ; 每執行1次,CX = CX – 1
   ; 只能用在CMPS(B/W/D)或SCAS(B/W/D)之前
      說明:
           若CX初值爲0,則不執行任何操作,而且標誌位不變。
 
2. 串指令的共性
 源串:地址由DS:SI表示。
 目的串:地址由ES:DI表示。
 自動修改地址:每次數據操作後,SI和DI自動遞增或遞減,取決於操作的數據類型(字節、字或雙字)以及DF的值。若DF = 0, 則SI和DI自動增加1、2或4。否則,減1、2或4。可以使用CLD或STD指令設置DF。
 計數器:使用重複前綴時,由CX表示數據個數,每重複1次操作,CX減1。
3. 串指令的用途
      串指令主要用於處理連續的內存單元,與重複前綴配合使用更有效。例如:
      MOVS用於將一個內存塊的數據複製到另一塊;
      CMPS用於比較兩個內存區的數據;
      SCAS可以在一個內存區中掃描與給定值首次匹配或不匹配的元素;
      STOS能將一個內存區的所有單元初始化爲給定值。
      LODS一般不用重複前綴。
 
字符串處理
1. ASCII字符串的表示方法
     字符串是一種特殊的數據串,比其它類型的串更常使用,因此,有時將字符串簡稱爲串。
     ASCII字符串的表示方法主要有下列兩種:
     (1)長度前綴法。
由首字節指出字符串長度,常被稱作Pascal串,爲Pascal語言的大多數版本所支持。例如:
 String1 db    6, 'String‘
(2)0終止法。
以0作爲結束標誌,常被稱作C串,爲C/C++語言所採用。例如:
 String2 db    ' String ', 0
2. 字符串處理舉例
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章