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

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