字符串的比較與搜索
cmps指令用於比較字符串值,cmps指令有三種格式:cmpsb、cmpsw、cmpsl。隱含的源操作數和目標操作數位置存儲在esi和edi寄存器中,每次執行cmps指令時,根據DF標誌,esi和edi寄存器按照被比較的數據長度遞增或遞減。cmps指令從源字符串中減去目標字符串,並且適當地設置EFLAGS寄存器的進位、符號、溢出、零、奇偶校驗和富足進位標誌。cmps指令執行之後,可以根據字符串的值,使用一般的條件 跳轉指令跳轉到分支。
cmps指令和rep指令一起使用可以對跨越多個字節的字符串重複進行比較。但rep指令不在兩個重複的過程之間檢查標誌狀態,它只關心ecx寄存器中的計數值。所以使用rep指令中的其他指令:repe、repne、repz、repnz。這些指令在每次重複過程中檢查0標誌,如果0標誌被設置,就停止重複。rep其他指令使用如下表:
指令
|
描述
|
repe
|
等於時重複
|
repne
|
不等於時重複
|
repnz
|
不為零時重複
|
repz
|
為零時重複
|
示例:
#cmps.s
.section .data
val1:
.ascii "Hello as!"
val2:
.ascii "Hello wd!"
.section .text
.globl _start
_start:
nop
movl $1, %eax #system call SYS_exit()
leal val1, %esi
leal val2, %edi
movl $9, %ecx
cld
repe cmpsb
je equal
movl %ecx, %ebx
int $0x80
equal:
movl $0, %ebx
int $0x80
該程序把源和目標字符串的位置加載到esi和edi寄存器中,字符串長度加載到ecx寄存器中,repe cmpsb指令逐字節地重複字符串的比較,直到ecx寄存器為0,或者0標誌被設置(說明不匹配)。 程序執行結果如下:
$ ./cmps
$ echo $?
2
ecx寄存器將包含不匹配字符在字符串中的位置,該位置是從字符串的末尾從0開始向回計數。 字符串的掃描使用scas指令,其提供了搜索一個字符或多個字符的方式。
scas指令類似其他字符串指令,有三種格式:scanb、scanw、scanl,三種格式分別比較內存中的一個字節和AL、AX、EAX寄存器的值。scas指令使用edi寄存器作為隱含的目標操作數。
edi寄存器必須包含要掃描的字符串的內存地址,當執行scas指令時,edi寄存器的值按照搜索字符數據長度遞增或遞減。
scas指令的一個非常有用的功能是確定0結尾的字符串導長度,對於0結尾的字符串,要搜索的顯然是0的位置,並且計算找到0經過 多少個字符。如下示例:
# scas.s
.section .data
string:
.asciz "this is a test string!\n"
.section .text
.globl _start
_start:
nop
leal string, %edi #將要用於查找的字符串的內存地址加載到edi寄存器中
movl $0xffff, %ecx #0xffff表明這個程序只能用於長度最大為65535的字符串
movb $0, %al #將要搜索的字符加載到al寄存器中
cld
repne scasb #使用repne指令掃描字符串,獲得搜索位置
jne notfound #如果沒找到,跳轉到notfound分支
subw $0xffff, %cx #如果找到了,那麼其距離字符串末尾的位置就存放在cx寄存器中,從cx寄存器的值中減去字符串的長度
neg %cx #使用neg指令改變結果的值的符號
dec %cx #因為該長度包含表示結尾的0,所以最終值必須減1才能顯示字符串的真正長度。
movl $1, %eax
movl %ecx, %ebx #將計算結果存放在ebx寄存器中。
int $0x80
notfound:
movl $1, %eax
movl $0, %ebx
int $0x80
運行程序結果如下:
$ ./scas
$ echo $?
23