80x86家族的處理器提供了幾條與數(shù)組一起使用的指令。這些指令稱為串處理指令。它們使用變址寄存器(ESI和EDI)來執(zhí)行一個操作,然后這兩個寄存器自動地進行增1或減1操作。FLAGS寄存器里的方向標志位(DF) 決定了這些變址寄存器是增加還是減少。有兩條指令用來修改方向標志位:
CLD 清方向標志位。這種情況下,變址寄存器是自動增加的。
STD 置方向標志位。這種情況下,變址寄存器是自動減少的。
80x86編程中的一個非常普遍的錯誤就是忘記了把方向標志位明確地設置為正確的狀態(tài)。這就經(jīng)常導致代碼大部分情況下能正常工作(當方向標志位恰好就是所需要的狀態(tài)時),但并不能正常工作在所有情況下。

讀寫內存
最簡單的串處理指令是讀或寫內存或同時讀寫內存。它們可以每次讀或寫一個字節(jié),一個字或一個雙字。圖5.7中的小段偽碼展示了這些指令的作用。這有點需要注意的。首先,ESI是用來讀的,而EDI是用來寫的。如果你能記得SI代表Source Index,源變址寄存器和DI代表Destination Index,目的變址寄存器,那么這個就很容易記住了。其次,注意包含數(shù)據(jù)的寄存器是固定的(AL,AX或EAX)。最后,注意存入串指令使用ES來決定需要寫的段,而不是DS。在保護模式下,這通常不是問題,因為它只有一個數(shù)據(jù)段,而ES應自動地初始化為引用DS(和DS一樣)。但是,在實模式下,將ES初始化為正確的段值對于程序員來說是非常重要的3。圖5.8展示了一個使用這些指令將一個數(shù)組復制到另一數(shù)組的例子。
LODSx和STOSx指令的聯(lián)合使用(如圖5.8中的13和14行)是非常普遍的。事實上,一條MOVSx串處理指令可以用來完成這個聯(lián)合使用的功能。圖5.9描述了這些指令執(zhí)行的操作。圖5.8的第13和14行可以用MOVSD指令來替代,能得到同樣的效果。唯一的區(qū)別就是在循環(huán)時EAX寄存器根本就不會被使用。
REP前綴指令
80x86家族提供了一個特殊的前綴指令,稱為REP,它可以與上面的串處理指令一同使用。這個前綴告訴CPU重復執(zhí)行下條串處理指令一個指定的次數(shù)。ECX寄存器用來計算重復的次數(shù)(和在LOOP指令中的使用是一樣的)。使用REP前綴,在圖5.8中的12到15行的循環(huán)體可以替換成一行:
rep movsd
圖5.10展示了另一個例子:得到一個零數(shù)組。
串比較指令
圖5.11展示了幾個新的串處理指令:它們可以用來比較內存和內存或內存和寄存器。在比較和查找數(shù)組方面,它們是很有用的。它們會像CMP指令一樣設置FLAGS寄存器。CMPSx 指令比較相應的內存空間,而SCASx 根據(jù)一指定的值掃描內存空間。
圖5.12展示了一個代碼小片斷:在一個雙字數(shù)組中查找數(shù)字12。行10里的SCASD指令總是對EDI進行加4操作,即使找到了需要的數(shù)值。因此,如果你想得到數(shù)組中數(shù)12的地址,就必須用EDI減去4(正如行16所做的)。
REPx前綴指令
還有其它可以用在串比較指令中的,像REP一樣的前綴指令。圖5.13展示了兩個新的前綴并描述了它們的操作。REPE 和REPZ作用是一樣的(REPNE和REPNZ也是一樣)。如果重復的串比較指令因為比較的結果而終止了,變址寄存器同樣會進行增量操作而ECX也會進行減1操作;但是FLAGS寄存器將仍然保持著重復終止時的狀態(tài)。因此,使用ZF標志位來確定重復的比較是因為一次比較而結束,還是因為ECX等于0而結束是可能的。
圖5.14展示了一個樣例子代碼片斷:確定兩個內存塊是否相等。例子中行7中的JE指令是用來檢查前面指令的結果。如果重復的比較是因為它找到了兩個不相等的字節(jié)而終止,那么ZF標志位就為0,也就不會執(zhí)行分支;但是,如果比較是因為ECX等于0而結束,那么ZF標志位就為1,而且代碼將分支到equal標號處。
更多建議: