讓我們繼續前編《x86 Assembly 的字串指令、方向指令與重覆指令》的介紹,x86 Assembly 除了 movs 和 cmps 兩個字串指令之外,常用的還有以下 3 個:
scas:掃描由 di / edi 參考的字串,以搜索存儲在 al / ax / eax 中的字元,具體取決於指令大小的後綴。scas 與 repne / repnz 一起使用,以便在找到字元時停止掃描。
stos:將來自 al / ax / eax 的值存儲到 di / edi 參考的位置。 stos 使用 rep 來初始化具有預設值的陣列(任何類型型態)。
lods:從 esi 參考的位置將值加載到 al / ax / eax 中。不應將 lods 與重複指令一起使用,因 accumulator register 會被重複覆蓋。
scas 本質上是一種內置的順序搜索算法(sequential search algorithm)。scas 與用高階語言編寫的順序搜索算法之間的一個潛在差異是,scas 在遍歷字串時一次只能操縱單個字元。高階實作有時會在字串中搜索含多個字元的子字串。但是,不少高階算法也是一次搜索一個字元。 scas 的正常操作是遍歷由 edi 參考的字串,直到找到存儲在 al / ax / eax 中的目標字符,然後退出。stos 也必須有 size identifier 作後綴(例如 scasb, scasw, scasd)。
segment .data
str1: db "abcdefghi", 0
len: EQU ($ - str1)
search: db "e"
segment .text
...
mov esi, str1
mov al, [seach]
mov ecx, len
cld
repne scasb
jnz notfound
...
jmp done
在使用 cmps 時,當如果兩組字串的字元相等,我們要 cmps 重複,並因此使用 repe 或 repz 指令。scas 的執行基本上與 cmps 相反,如果字元對不相等,scas 才需要重複,這表示未找到搜索字符。因此,通常使用 repne 或 repnz 指令執行 scas。
如果 scas 遍歷整個字串而沒有找到匹配項,則 ecx = 0 and zf = 0。如果 scas 確實找到了一個匹配項,則 ecx 值可以為 0 或大於 0,取決於匹配項的位置,但將設置 zf(zf = 1)。與 cmps 相似,我們應將 zf 用作成功的唯一指標。
要搜索的字元必須放在適當的 accumulator register 中(例如, al 表示 8-bit,ax 表示 16-bit 等),我們應首先使用 xor 清除 eax。由於我們正在執行位元組搜索,因此將搜索字符加載到 al 中。edi 用作 source。將以位元組為單位的字串長度加載到 ecx 中之後,我們清除 df(direction flag)並執行 scasb。如上所述,一旦 scas 完成,我們需要檢查 zf 以確定是否找到了搜索字元。因此,如果 zf = 0,我們將使用 jnz 指令跳轉。
stos(Store String)指令對於陣列初始化很有用。 stos 將存儲在 accumulator register(al/ax/eax)的值複製到 edi 參考的存儲位置。 為了初始化多個存儲位置(即整個陣列),請結合使用 stos 和 rep。後接 size identifier(例如 stosb, stosw, stosd)。
xor eax, eax
mov al, 0
lea edi, [dst]
mov ecx, 10
cld
rep stosb
上面例子初始化了一個由 10 個元素組成的陣列,值為零。 由於我們使用後綴 b(表示 byte)執行 stos,因此我們使用al(byte 大小的寄存器)保存即將複製到 dst 陣列每個元素中的值。
lods(load string)指令執行與 stos 指令相反的動作。 lods 將 esi 參考的值複製到 accumulator register 中。 與 stos 和其他字串指令不同,由於 accumulator register 會被重複覆蓋,您可能永遠不會將 lods 與任何重複指令一起使用。lods 也必須有 size identifier 作後綴(例如 lodsb, lodsw, lodsd)。
lea esi, [src]
lodsd