曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 6407|回复: 0
打印 上一主题 下一主题

字符串比较(CMPS指令)

[复制链接]

4917

主题

5879

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34382
跳转到指定楼层
楼主
发表于 2010-8-17 13:14:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
CMPS 系列指令用于比较字符串值,和其他字符串指令一样,CMPS 有 3 种格式:
      CMPSB: 比较字节值
      CMPSW: 比较字(2字节)值
      CMPSL: 比较双字(4字节)值
和其他字符串指令一样,隐含的源和目标操作数的位置同样存储在 ESI 和 EDI 中。每次执行 CMPS 指令时,根据 DF 标志的设置情况,ESI 和 EDI 按照比较的数据长度递增或递减。

CMPS 指令从源字符串中减去目标字符串,并且适当的设置 EFLAGS 寄存器的进位、符号、溢出、零、奇偶校验和辅助进位标志。CMPS 指令执行后,可以根据字符串的值,使用一般条件跳转指令跳转到分支。

测试程序:
.section .data
value1:
     .ascii "Test"
value2:
     .ascii "Test"

.section .text
.global _start

_start:
     nop
     movl $1, %eax
     leal value1, %esi
     leal value2, %edi
     cld
     cmpsl
     je equal
     movl $1, %ebx
     int $0x80
equal:
     movl $0, %ebx
     int $0x80
运行输出:
$ ./cmps
$ echo $?
0
需要注意的是,上面的 CMPSL 只能比较 4 个 个字符。对于更长的字符串比较,采用的方法是结合 REP 指令。REP 指令不在两个重复的过程之间检查标志的状态,它只关心 ECX 中的计数值。解决方法是,使用 REPE、REPNE、REPZ 和 REPNZ 指令。如下程序演示:
.section .data
value1:
     .ascii "This is a test of the CMPS instrunctions"
value2:
     .ascii "This is a test of the CMPS instrunctions"

.section .text
.global _start
_start:
     nop
     movl $1, %eax
     leal value1, %esi
     leal value2, %edi
     movl $39, %ecx
     cld
     repe cmpsb
     je equal
     movl %ecx, %ebx
     int $0x80
equal:
     movl $0, %ebx
     int $0x80
上面两条字符串是一样的,所以程序会运行到 je equal 这条语句,此时在 GDB 中可以看到 ZF 标志被置位。如果将上面 value2 中的 instructions 中的 i 改为 I,那么程序在比较到 i 时,程序也会停止重复,然后将 ECX 中的值赋予 EBX,以返回出来,这时 ECX 中的值也就等于 nstructions 的字符个数,即 11 个。

字符串不等
比较字符串相等的情况比较容易,但是比较字符串不等则没有那么简单。如比较 "test" 和 “boomerang” 到底是哪个大呢?表面上看去,boomerang 比较长,理所当然的会认为是 boomerang 大,其实不然。比较字符串的大小,有专门的方法确定。
最常用的方法称为词典式顺序(lexicographical order),这通常也称为字典顺序(dictionary order)。辞典式顺序基本规则如下:
      按字母表顺序,较低的字母小于较高的字母
      大写字母小于小写字母
这些规则遵循 ASCII 编码标准。对于长度相同的字符串,字符串 "test" 将小于 "west",但大于 "Test"。这里需要注意一点,即使两个字符串长度一样,但并不是要将字符串中的每个字符的 ASCII 码相加后再比较,而是依次每个比较。也就是说,第 1 个字符一样,就接着比较第 2 个,如果第 2 个不一样,比较到此停止,最后看谁大谁小。当处理长度不同的字符串时,要困难一些。

比较两个长度不一样的字符串时,则按照当度短一些的字符串中的字符数量进行比较。如果短字符串大于长字符串中相同数量的字符,那么短字符串就大于长字符串;反之,则短字符串就小于长字符串;若短字符串等于长字符串中相同数量的字符,那么长字符串就大于短字符串。如下例子所示:
"test" 大于 "boomerang"
“test" 小于 "velocity"
"test" 小于 "test1"
测试程序:
.section .data
string1:
         .ascii "test"
length1:
         .int 4
string2:
         .ascii "uaaa"
length2:
         .int 4

.section .text
.global _start

_start:
         nop
         leal string1, %esi
         leal string2, %edi
         movl length1, %ecx
         movl length2, %eax
         cmpl %eax, %ecx    #比较两个字符串的长度
         ja   longer        #以短字符串的长度为标准(短字符串长度放在ecx中)
         xchg %ecx, %eax
longer:
         cld
         repe cmpsb
         je equal
         jg greater
less:
         movl $1, %eax
         movl $255, %ebx   #255是返回值,表示 string1 小于 string2
         int $0x80
greater:
         movl $1, %eax     
         movl $1, %ebx     #1是返回值,表示 string1 大于 string2
         int $0x80
equal:                      #短字符串中所有字符(按照顺序)是长字符串的子集
         movl length1, %ecx  #比较两个字符串的长度,长的则大,否则为小
         movl length2, %eax
         jg greater
         jl less
         movl $1, %eax
         movl $0, %ebx       #如果两个字符串完全相等则返回 0
         int $0x80
运行输出:
$ ./strcom
$ echo $?
255
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2024-4-29 05:33 , Processed in 0.066299 second(s), 22 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表