【微機原理與接口 7】—— 常用指令分析4 (串操作指令剖析)

一、關於串操作的一些說明:

雖然我們知道,在高級語言裏面,串 和 一般的數據的標識符會有一些不一樣(比如C++ 裏面整形的 int 以及字符串的 string )但是,在底層語言裏面,他們類型其實都是一樣的二進制數。只不過串是一個數據塊。我們用下圖說明一下:

那麼, 在執行串操作之前,我們需要確定以下的幾件事情:

  1. 串所在的區域,串的首地址(這裏的串包括源串和目標串)
  2. 串的長度
  3. 串操作的方向,這個我們用一張圖來理解:

如果橫向的藍色箭頭表示的是源串首,假如串操作的方向是 由低地址向高地址,那麼實際上要操作的串就是下方的一塊區域;但是如果方向是 由高地址向低地址,那麼要操作的串就應該是上方的一塊區域。二者的串本身完全不一樣!

  1. 串操作的指令之前可以加上一個重複前綴。

下面,我們一一來解釋以下:
【1】首先是串的位置:我們的操作對象是 源串和目標串。其中,源串默認的段首地址存放在 DSDS (數據段裏面),串首地址存放在 SISI,即:DS:SIDS:SI。(其中 DSDS 可以使用段超越變成其他段)
目標串它的段地址默認是在附加段 ESES,串首地址在 DIDI 裏面(注意 ESES 不允許被段超越!)

【2】關於串的長度,我們會將串的長度值存放在 CXCX 裏面。在使用串操作指令之前,我們需要給 CXCX 賦初值

【3】關於串操作的方向,我們使用狀態標識裏面的 DFDF 來表示:如果 DF=0DF = 0 表示的是串操作從低地址向高地址執行如果 DF=1DF = 1,那麼表示從高地址向低地址執行。同樣地,我們也要在使用串操作指令之前,給 DFDF 賦初值:CLDCLD 表示將 DFDF 清零;STDSTD 表示將 DFDF 置1

【4】關於串操作指令前面的循環前綴(這是串操作指令所特有的),重複前綴可以分爲無條件前綴和條件前綴。其中,無條件前綴我們用 REPREP 表示,它的意思是:只要當 CX0CX ≠0的情況下,我們就一直執行 REPREP 後面跟着的語句 我們可以看到,因爲是無條件地反覆執行,因此,後面常常跟串傳輸類指令

而對於條件前綴,我們分兩種:
(1)REPZ,或者說 REPE(都行):它的意思是"相等則重複“當 CX0CX ≠0,且ZF=1ZF = 1時,重複執行
(2)REPNZ,或者說 REPNE:它的意思是“不相等則重複”,即當 CX0CX ≠0,且ZF=0ZF = 0時重複執行
我們可以看到,對於條件前綴,後面常常跟串運算類指令

1.1 串操作指令執行的一般流程

我們用下圖說明:

其中,我們可以看到流程圖主要分成了兩塊:左邊的四個步驟,我們稱之爲初始化。這裏需要特別說明:串操作指令中,每操作完一個字節或者一個字之後,串首指針是指令自動更改的。不需要我們手動設置。而上圖幾乎是所有串操作指令執行都需要經過的流程圖,我們發現:在每操作完一個字節或者一個字之後,並不是立刻就去判斷是不是已經完成了所有操作,而是在修改完地址指針之和,還需要經過修改串長度(這需要我們自己寫程序控制)的這個操作之後,纔到判斷。

下面,我再把這個圖分模塊畫一下:

那麼,試想一下:假如我們的串操作方向是 DF = 0,而且是一個串傳輸指令;那麼在所有數據傳輸完畢之後,串首指針應該是在串尾的後一位!

二、正題——串操作指令

2.1 串傳送指令 MOVS

首先是串傳送:MOVSMOVS,更具體地說,應該分成兩種:MOVSBMOVSBMOVSWMOVSW
MOVSBMOVSB 顧名思義就是傳送1個字節(也就是8位)的串;而 MOVSWMOVSW 則是傳送 1個字的串。

我們看一個例子學習它的用法:

使用 MOVSMOVS指令,將200個字節數據從內存數據段 MEM1 爲首地址的區域送到一個邏輯段 MEM2
爲首地址的區域:(我們下面給出程序的分析):

LEA SI, MEM1     //這句話的意思是給源串的串首賦初值(要賦值給SI寄存器)
LEA DI MEM2      //這句話也是給目標串的串首地址賦初值(要賦值給 DI 寄存器)
MOV CX 200       //給 串的長度賦初值(要賦值給 CX)
CLD              //令 DF = 0,說明是從低地址向高地址執行
REP MOVSB        //無條件重複:只要 CX ≠0 就一直執行串的傳輸
HLT              //當REP跳出來了,就結束

當然也是可以用 MOVSWMOVSW的,這樣的話,我們的 CX 就要賦初值爲 100 了,因此 MOVSWMOVSW一次操作16位

那麼,假如我們想要驗證我們傳輸的串對不對,那麼就需要將這兩個串進行比較。因此就引出了串比較指令:

2.2 串比較指令 CMPS

同樣地,CMPS 也分爲:CMPSB, CMPSW。它執行的是啥呢?—— 目標串 - 源串,但是結果並不返回目標串。也即是實現兩串的比較。

對於串比較指令,我們一般在它前面加條件前綴。

那麼,依舊是剛剛的例子,我們在傳輸完了 200 個字節的串之後,想要檢測一下是否正確傳輸,我們就需要比較兩個串了:下面是程序分析:

	LEA SI, MEM1
	LEA DI MEM2
	MOV CX, 200
	CLD             //上面四條語句全都是初始化
	REPE CMPSB
	JZ STOP         //JZ 表示當 ZF = 1 時執行跳轉,執行到這裏如果ZF仍然爲1說明兩串一樣
	DEC SI          //完成SI的自減,回顧上面的流程圖,SI現在是在串低的後一位
	MOV AL, [SI]
	MOV BX, SI
STOP: HLT

首先,我們明確一件事情:REPE 的意思是相同即重複(CX0CX≠0,且 ZF=1ZF = 1),也就是說當比較的串一樣時,就繼續比。那麼 REPE 退出的情況有什麼呢?

  1. CX = 0(說明比完了,那麼就是兩個串完全一樣)
  2. CX0CX≠0,但是 ZF=0ZF = 0(說明在中間有兩個串不一樣的地方了)

JZ 表示當 ZF=1ZF = 1 時執行跳轉,跳轉到 STOP

2.3 串掃描指令

我們常常使用的是 SCASBSCASBSCASWSCASW。當我們使用 SCASB,SCASWSCASB, SCASW 時,源操作數是不用寫出來的,但是要在程序的前面聲明。(注意:使用 SCASB,SCASWSCASB, SCASW 時,源操作數是 ALAL 或者 AXAX。當使用 SCASBSCASB時,一次操作一個字節單元,源操作數就是 ALAL)

另外,說一下 SCASB,SCASWSCASB, SCASW 都幹了什麼:

我們以 SCASBSCASB 爲例,它執行的是將 ALAL 裏面存放的字節依次 和串內的每一個字節單元相減,但是結果不返回,影響標誌位 ZFZF,用於搜索串裏面有沒有哪個字節單元的內容和 ALAL 的一樣。

舉一個例子:在 ES段中從 2000H 單元開始存放了 10 個字符,尋找其中有沒有字符 ‘A’,若有則記錄搜索次數,將搜索次數寫入 DATA1 單元,並將 ‘A’ 寫入 DATA2 單元。

首先,我們要明確一件事情:目標串地址在 ES:DI 裏面。

		MOV DI, 2000H     //先給DI 賦值
		MOV BX, DI        //地址備份,用於後面計算搜索次數
		MOV CX, 10        //因爲如果採用SCASB,那麼就是一個字節一個字節搜索,10次
		CLD
		REPNZ SCASB       //“若不相等則重複”,如果不相等,即ZF = 0 ,那麼就一直搜索
		JZ FOUND          //若 ZF = 1 就跳轉到 FOUND(ZF=1 說明找到一樣的了)
		MOV DI, 0
		JMP DONE
FOUND:  DEC DI  //因爲 DI 是先自增之後才進入判斷的,所以在跳出之後DI 會在 'A' 的後一個單元
		MOV DATA1, DI
		INC DC
		SUB DI, BX        //計算搜索次數
DONE: 	MOV DATA2,DI
		HLT 

2.4 串加載與串存儲

【1】首先是串加載,我們用 LODSBLODSBLODSWLODSW,既然是 加載,那麼就是將串中的數據裝載到某個地方,因此,在 LODSBLODSBLODSWLODSW 中,串是作爲源操作數的,地址在 [DS:SI][DS:SI]

如果使用的是 LODSBLODSB,那麼它執行的操作是將數據段中地址爲 SISI 的單元裝入 ALAL
如果使用的是 LODSWLODSW,那麼它執行的操作是將數據段中地址爲 SISI 的單元裝入 AXAX

【2】下面是串存儲,我們用 STOSBSTOSBSTOSWSTOSW,既然是存儲,就是把某個內容存儲進串裏。因此,此時串就作爲目標串,地址爲:[EI:DI][EI:DI]

如果使用的是 STOSBSTOSB,那麼它執行的是將 ALAL 裏面的內容存儲進 [ES:DI][ES:DI]
如果使用的是 STOSWSTOSW,那麼它執行的是將 AXAX 裏面的內容存儲進 [ES:DI][ES:DI]

注意:在串加載與串存儲中,是已經限定了 AX,ALAX,AL 的!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章