linux平台学x86汇编(十三 ):字符串的比较与搜索

【版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途】

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
时间: 2024-08-09 22:02:11

linux平台学x86汇编(十三 ):字符串的比较与搜索的相关文章

linux平台学x86汇编(十二):字符串的存储与加载

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 字符串的存储与加载是指,将字符串的值加载到寄存器和将其传回内存位置中.其使用指令lods指令和stos指令. lods指令用于把内存中的字符串值传送到eax寄存器中,该指令有三种不同格式:lodsb(1字节).lodsw(2字节).lodsl(4字节).lods指令使用esi寄存器作为隐含的源操作数.esi寄存器必须包含要加载的字符串所在的内存地址. 在使用lods指令把字符

linux平台学x86汇编(三):相关开发工具

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 类似于其它高级语言,编写汇编语言,必须有一个开发环境,那么也就需要适当的工具了.搭建汇编语言至少应该有下面这些工具:汇编器.链接器.调试器.下下面看看在汇编语言开发环境中如何使用它们. 汇编器 汇编器用于把汇编语言源代码转换为处理器指令码.选择的汇编器必须能够生成所在系统的处理器系列指令码.汇编语言源代码程序有3个部分:操作码助记符.数据段.命令.但是每种汇编器对于每个部分使

linux平台学x86汇编(四):从“hello world!”开始

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 汇编语言程序由定义好的段构成,每个段有各自的目的.三个最常用的的段如下:数据段.bss段.文本段.文本段是可执行程序内声明指令码的地方,所有汇编程序都必须有文本段,数据段和bss段是可选的,但是在程序中经常使用.数据段声明带有初始值的变量,bss段声明使用0值初始化的数据元素,这些元素常用作汇编程序的缓冲区.下图为汇编语言程序的布局. GNU汇编器使用.section命令语句

linux平台学x86汇编(八):条件跳转

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 在此之前我们使用的汇编代码示例都是从第一条指令开始,直到最后最后一条指令程序退出.但实际上和高级语言类似,汇编代码也提供指令来改变程序处理数据方式. 正常情况下,程序要执行要执行的下一条指令是在指令指针寄存器中,指令指针确定程序中哪条指令是应该执行的下一条指令. 当指令指针在程序指令中移动时,EIP寄存器会递增.指令长度可能是多个字节,所以指向下一条指令不仅仅是每次是指令指针

linux平台学x86汇编(十九):C语言中调用汇编函数

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 除了内联汇编以外,还有一种途径可以把汇编代码整合到C/C++语言中,C/C++语言可以直接调用汇编函数,把输入值传递给函数,然后从函数获得输出值. 如果希望汇编语言函数和C/C++程序一起工作,就必须显示地遵守C样式的函数格式,也就是说所有输入变量都必须从堆栈读取,并且大多数输入值都返回到EAX嫁寄存器中.在汇编函数代码中,C样式函数对于可以修改哪些寄存器和函数必须保留哪些寄

linux平台学x86汇编(十五):使用命令行参数

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 在高级语言中,程序在命令行上启动时常常带一个或多个参数,在汇编语言中也可以实现这一特性.在实现这一特性之前,我们先了解一下linux如何从命令行执行程序. 每一个应用程序开始执行时,系统都会为该程序分配一块内存区域,并且每个程序都分配相同的虚拟内存地址.虚拟内存地址由操作系统映射到物理内存地址.在Linux中,程序的虚拟内存地址是从0x80480000开始,到地址0xbfff

linux平台学x86汇编(十六):在汇编语言中调用C库函数

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 其实在汇编语言中也是可以使用C库函数的,这一节我们来看一下如何在汇编语言中调用C库函数以使得我们的程序看上去很方便地和用户交互. C库包括C程序通用的喝多函数,如printf和exit等,下面我们紧接着上一节的知识来实现一个两整数想加的计算并输出计算结果的程序. # libc.s .section .data output: .asciz "The result is %d.

linux平台学x86汇编(十七):在汇编中使用linux系统调用

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 在前面章节我们已经看到,启动系统调用需要使用INT指令.linux系统调用位于中断0x80,执行INT指令时,所有操作转移到内核中的系统调用处理程序,完成后执行转移到INT指令之后的下一条指令. linux的系统调用在如下文件(32位系统)可以查看: $ cat /usr/include/asm/unistd_32.h #ifndef _ASM_X86_UNISTD_32_H

linux平台学x86汇编(五):使用gdb调试汇编程序

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 正如C语言一样,编写所有语言程序一样会出现一些一些错误,发生错误时,我们可以使用调试器一步一步运行程序以监视数据是如何被处理的.本节使用GNU调试器检查上一节hello程序,监视处理过程中寄存器和内存的值的变化.要调试汇编语言程序,在编译时,需要使用-gstabs参数重新汇编源代码,使用了该参数编译出来的可执行文件要比之前稍大一些,因为添加了附加信息.上一节程序不使用-gst