文章目錄
字符串操作
串操作指令簡介
主機與外設之間的交互,大多采用字符串的形式,爲了方便地實現字符串操作,簡化程序設計,80x86提供了字符串操作指令
字符串操作指令共有5條:
- 傳送指令 MOVS
- 搜索指令 SCAS
- 比較指令 CMPS
- 讀取指令 LODS
- 存儲指令 STOS
以上指令可使用的重複前綴如下:
- REP,無條件重複CX寄存器指定的次數
- REPE/REPZ,在CX≠0 && ZF=1時重複
- REPNE/REPNZ,在CX≠0 && ZF=0時重複
所有的字符串操作指令,使用相同的寄存器,標誌位和符號
- 源串指示器:DS:SI/ESI
- 目的串指示器:ES:DI/EDI
- 重複次數計數器:CX/ECX
- SCAS指令的搜索值在:AL/AX/EAX中
- LODS指令的目的地址爲:AL/AX/EAX
- STOS指令的源地址爲:AL/AX/EAX
- 傳送方向:
- DF = 0 自動增量
- DF = 1 自動減量
- _SB:不帶操作數的字節串操作指令
- _SW:不帶操作數的字串操作指令
- _SD:不帶操作數的雙字串操作指令
串操作指令
傳送指令
MOVS OPD, OPS
MOVSB:字節傳送
MOVSW:字傳送
MOVSD:雙字傳送
功能:
- DS:[SI] / [ESI] --> ES:[DI] / [EDI]
- 自動修改指針,指向下一個位置
比較指令
CMPS OPD, OPS
CMPSB:字節比較
CMPSW:字比較
CMPSD:雙字比較
功能:
- DS:[SI] / [ESI] – ES:[DI] / [EDI]
- 根據相減的結果,置標誌位,源串與目的串內容不變
- 自動修改指針,指向下一個位置
- 後面一般跟轉移指令
- 串比較指令,是源操作數減去目的操作數
搜索指令
SCAS OPD
SCASB:字節搜索
SCASW:字搜索
SCASD:雙字搜索
功能:
-
字節操作:(AL) – (ES:[DI] / [EDI])
-
字 操 作:(AX) – (ES:[DI] / [EDI])
-
雙字操作:(EAX) – (ES:[DI] / [EDI])
-
根據相減的結果置標誌位,但不保存結果
-
自動修改指針,指向下一個位置
-
主要用來在字符串中搜索某個值
從源串中取數指令
LODS OPD
LODSB:字節串中取數
LODSW:字串中取數
LODSD:雙字串中取數
功能:
-
字節操作:(DS:[DI] / [EDI]) -> (AL)
-
字 操 作:(DS:[DI] / [EDI]) -> (AX)
-
雙字操作:(DS:[DI] / [EDI]) -> (EAX)
-
將字符串存儲區的某個數據,送到累加寄存器中
-
自動修改指針,指向下一個位置
往目的串中存數指令
STOS OPD
STOSB:往字節串中存數
STOSW:往字串中存數
STOSD:往雙字串中存數
功能:
-
字節操作: (AL) -> (DS:[DI] / [EDI])
-
字 操 作:(AX) -> (DS:[DI] / [EDI])
-
雙字操作:(EAX) -> (DS:[DI] / [EDI])
-
將累加寄存器中的值,送到目的串
-
自動修改指針,指向下一個位置
宏功能程序設計
- 子程序的調用,需要額外的時間和空間花銷
- 當重複部分較短時,一般設計成宏指令
- 宏彙編語言提供:宏指令的定義調用、重複彙編、條件彙編
- 宏指令使用三步驟:宏定義、宏調用、宏拓展
宏定義
宏定義使用僞指令 MACRO
和 ENDM
實現
定義格式
宏指令名 MACRO 形參
宏體
ENDM
- 宏指令名,類似於函數名
- 形參可以出現在宏體任何地方,形參以逗號隔開
- 宏體是要重複的部分,包括一系列機器指令和僞指令
- ENDM和MACRO成對出現
- 宏指令一定要放在被調用之前
宏調用
宏指令完成定義後,可以在源程序中調用
調用格式:宏指令名 實際參數
宏拓展
- 宏彙編程序在彙編期間,先掃描宏定義,將宏名字、形參、宏體填入宏定義表中
- 遇到宏調用時,實參替換形參
宏定義於宏調用中的參數
帶間隔符的實參
有時,實參是一串帶間隔符(空格、逗號)的字符串,爲了不至於混淆,用尖括號 <> 將它們括起來,尖括號中的內容代表實參
例如用宏指令定義申請堆棧空間:
STACK0 <500 DUP(0)>
數字實參
- 有時希望用符號做實參,希望傳進去的是符號的值,而不是符號本身,可以符號的前面加
%
- 特殊宏操作符
%
用來將其後的表達式轉換爲對應的值 - % 後面的符號,一定是直接用EQU或者=賦值的符號常量,或者彙編時能確定值的表達式,而不能是變量和寄存器名
宏參數的連接
- 在宏定義中,有些形參需要夾在字符串中,爲了將這種形參標識出來,需要在這樣的形參前面加符號
&
- 如果形參後面還跟有字符串,則還應在形參後面加符號
&
- 宏彙編程序識別後,將符號連成一個完整的字符串
宏體中的變量與標號
- 宏體中經常需要定義一些變量和標號,如果進行了多次宏拓展,則會出現變量或標號重複定義的錯誤
- 爲解決這個問題,提供了僞指令LOCAL
LOCAL 形參
功能:
- 在宏拓展時,宏彙編程序自動爲其後的形參順序生成特殊符號,並用這些特殊符號取代宏體中的形參,從而避免了符號重複定義的錯誤
- LOCAL語句只能作爲宏體的第一條語句,它後面的形參即爲本宏定義中所定義的變量和標號
重複彙編
- 有時源程序中,會連續重複完全相同,或者幾乎完全相同的一組語句
- 這時採用重複彙編方式比把他們定義成宏指令更能簡化程序設計
給定次數
REPT 表達式
重複塊
ENDM
功能:讓宏彙編程序將重複塊連續地彙編“表達式”所指定的次數
不定次數
次數由實參的個數確定,根據實參形式的不同,選擇IRP和IRPC
IRP 形參, <實參1,實參2,...,實參n>
重複塊
ENDM
- 讓宏彙編程序將重複塊重複彙編由實參個數所確定的次數,並在每次重複時,依次用相應位置的實參代替形參
- 實參必須用尖括號括起來,並且各實參之間用逗號隔開
IRPC 形參,字符串
重複塊
ENDM
- 將重複塊重複彙編,重複的次數由字符串中的個數決定,並在每次重複時,依次用相應位置的字符代替形參
- 字符串不帶引號
條件彙編
- 條件彙編是指,允許宏彙編程序根據條件,決定某一段程序是否參加彙編
- 使用條件彙編僞指令時,條件表達式各項的值必須在第一遍掃描中求得,否則表達式不正確
使用格式:
IF ... 條件表達式
條件彙編塊1
ELSE
條件彙編塊2
ENDIF
正條件 | 反條件 | 表達式的形式 | 檢測條件 |
---|---|---|---|
IF | IFE | 數值表達式 | 表達式值不爲0(爲0)爲真 |
IF1 | IF2 | 第一次/第二次掃描 | |
IFDEF | IFNDEF | 符號 | 符號已被(未被)定義或被(未被)說明爲外部符號爲真 |
IFB | IFNB | <參數> | 該參數對應的實參存在(不存在)爲真 |
IFIDN | IFDIF | <參數1>, <參數2> | 字符串參數1與字符串參數2相等(不相等)爲真 |
宏庫的使用
宏庫的建立
- 對於經常使用的宏定義,用戶可以將他們集中在一起,建成宏庫供用戶隨時調用
- 宏庫爲文本文件,文件名任意指定
- 利用TYPE命令可以查看文本的內容
宏庫的使用
- 程序中需要調用宏庫時,首先將宏庫加入到自己的源文件中,然後按照宏庫中各宏定義的規定調用即可
- 僞指令 INCLUDE 用於將宏庫加入源文件一起進行彙編
INCLUDE 文本文件名
功能:將文件內容加入彙編,全部彙編完後,再彙編後面的內容
條件彙編與宏定義的使用
- 條件彙編僞指令常與宏定義一起使用
- 可以使用條件彙編,使宏庫只在第一遍掃描時添加,這樣加快第二次掃描,避免列出長長的彙編列表清單
- 對於宏庫中用不上的宏指令,可以使用僞指令PURGE取消
IF1
INCLUDE MACRO.LIB
ENDIF
PURGE WRITE
宏指令與子程序的比較
- 處理的時間不同:宏指令是在彙編期間,由宏彙編程序處理的;而子程序調用是在目標程序執行期間,由CPU直接執行的
- 處理的方式不同:宏指令必須先定義後使用,宏調用用宏體置換宏指令名,實參置換形參,而子程序的調用不發生這種代碼和參數的置換,而是CPU將控制方向由主程序轉向子程序
- 目標程序的長度不同:由於每次宏調用都要進行宏拓展,因而使用宏指令不會縮短目標程序,而子程序通過CALL指令調用,無論執行多少次,目標代碼只出現一次,因此,目標程序短,佔用空間小
- 執行速度不同:執行子程序需要使用堆棧保護和恢復現場,因而執行速度慢,而宏指令不存在這些問題
- 參數傳遞方式不同:宏調用可實現參數的代換,參數形式不受限制,而子程序參數一般是地址或者操作數
模塊化程序設計
- 在彙編語言中,一個以 END 語句爲結束標誌的源程序,稱爲一個代碼塊
- 它經過彙編源程序彙編後,生成一個目標文件,也稱爲目標模塊
- 連接程序將多個目標模塊連接在一起時,需要兩個信息,一是模塊間通信方式,二是段之間的組合方式
- 通信方式是指:一個模塊可訪問另外模塊中所定義的標號、變量、符號常量的方式
- 組合方式是指:多個模塊以什麼方式組合在一起
組合方式
定位方式
定位方式是對該段起始地址所提出的要求,即告訴連接程序,在各個段裝配在一起時,前一段放完後,後面一個段將從一個什麼樣的起始邊界開始存放
定位方式有4種選擇:
- PARA:節:表示該段要從能被16整除的地址開始存放,即最低4位必須爲0
- WORD:字:表示該段要從偶數地址開始存放,即最低1位必須爲0
- BYTE:字節:表示對該段存放的首地址不作要求,任何地址處都可以開始存放
- PAGE:頁:該段要從能被256整除的地址開始存放,即最低8位必須爲0
其中PARA爲默認方式,不指定時爲此方式
組合方式
組合方式的作用是向連接程序提供本段同其他段的組合關係,可以選擇以下幾種關係
- 不選擇:表示本段與其他段邏輯上不發生關聯
- PUBLIC:表示應將本段與其他模塊中的同名、同 ‘類別’ 段按模塊連接的順序相鄰的連接在一起,組成一個物理段,該段大小不能超過64KB
- STACK:與PUBLIC功能相同,但該方式僅對堆棧段
- COMMON:表示本段和同名、同 ‘類別’ 的其他段應該具有相同的段首址,即將本段與這些段相覆蓋,覆蓋長度取決於最長的COMMON段
- AT表達式:表示將本段裝在根據表達式計算出的段地址上,但AT方式不能包含代碼和初始化數據,不能用於用戶代碼段,僅用於訪問系統數據,表示已在內存中的數據和數據地址
- MEMORY:表示將本段定位在所有連接在一起的段之上(最高地址上),如果幾個段都選擇MEMORY組合方式而又同時連接在一起,那麼只有宏彙編程序遇到的第一段處理爲MEMORY,其它作爲COMMON段
類別
- 段的 ‘類別’ 是用單括號括起來的字符串來表示的
- 連接時,‘類別’ 相同的所有段,按先後順序存放在連續的存儲區,且每段都有自己的起始地址
通信方式
公共符號與外部符號
- 公共符號:不僅可被定義自己的模塊訪問,還可以供其它模塊訪問的符號,用PUBLIC說明
- 外部符號:在該模塊內部訪問,而不在該模塊內定義的符號,用EXTERN說明
PUBLIC 符號
- 用來說明其後的符號是公共符號,可以被其它模塊所引用
- 這些符號必須是在本模塊中定義的符號常量、標號、變量,各名字之間用逗號隔開,一個模塊中的同一個名字僅可被PUBLIC說明一次
- 一般放在程序的開頭
EXTERN 符號:類型
- 用來說明本模塊中需要引用的、由其他模塊所定義的符號
- 這些符號必須在所定義的模塊中聲明爲PUBLIC
- 類型爲:ABS(符號常量)、BYTE、WORD、DWORD、NEAR、FAR
連接程序的功能
連接程序可以將若干個目標模塊連接在一起,連接程序主要有以下功能:
- 將指定的若干個目標模塊和子程序庫中的子程序模塊連接在一起,解決各模塊中段的組合、定位問題,確定目標模塊中浮動地址及公共符號的引用問題,生成一個可再定位的裝入模塊,即能夠執行的文件(.EXE)
- 產生一個地址分配文件(.MAP)
源程序綜合舉例
模塊程序設計中的注意事項
模塊劃分
- 如果一個程序段被很多模塊公用,則他應該該是一個獨立的模塊
- 如果若干程序段處理的數據是公用的,則這些程序段應該放在一個模塊
- 若兩個程序段的利用率差別很大,則應該分屬於兩個模塊
- 一個模塊不能太大,也不能太小,過大則通用性差,過小則時間和空間浪費
- 力求使模塊具有通用性,通用性越強模塊的利用率越高
- 各模塊在功能、邏輯上相互獨立,避免使用轉移語句在模塊間轉來轉去
- 各模塊之間接口簡單,儘量減少公共符號的個數,儘量不公用數據存儲單元,在結構或編排上有聯繫的數據應該放在一個模塊中,以免相互影響
- 每個模塊的結構應該儘量設計成單入口、單出口的形式
程序文件命名
- 標識出程序設計者
- 標識出模塊功能
- 標識出模塊之間的連接關係
標號的定義
- 模塊出處
- 功能名稱
- 分支代號
變量和緩衝區的定義
- 緩衝器或變量標誌:用B爲緩衝器名開頭,用V爲變量名開頭,用S爲字符串開頭
- 第二個字母可表示定義的類型
模塊註釋
爲方便子模塊的調用,在子模塊前面應該有詳細的說明,包括:
- 子模塊的功能
- 入口參數
- 出口參數
- 所用到的主要變量