linux平台学x86汇编(十一):字符串的传送

来源:互联网 发布:卖家如何做淘宝客 编辑:程序博客网 时间:2024/04/29 11:26
【版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途】
        在高级语言中,我们经常操作字符串,比如字符串拷贝、比较、查找等。在汇编语言中也有实现这些操作的命令。这一节讲述在汇编语言中字符串传送相关操作命令。
        movs指令可以把字符串从一个内存位置传送到另一个内存位置,指令后面跟表示长度的字符:movsb(1字节)、movsw(2字节)、movsl(4字节)。该指令使用隐含的源和目标操作数。隐含源操作数是esi寄存器,其指向源字符串的内存位置。隐含目标操作数是edi寄存器,其指向字符串要被复制到的目标内存位置。
        在使用GNU汇编时,有两种方式加载esi和edi的值,第一种使用间接寻址,例如: movl $val, %edi,其将变量val的32位内存地址传送给edi。第二种是使用lea命令,lea指令加载一个对象的有效地址,源操作数指向一个内存位置,比如leal val,%edi 把val标签的32位内存位置加载到edi寄存器中。
如下是一个示例:
# movs.s.section .dataval:    .ascii "Hello, as world!\n".section .bss    .lcomm output, 17.section .text.globl _start_start:    nop    leal val, %esi    leal output, %edi    movsb    movsw    movsl    movl $1, %eax    movl $0, %ebx    int $0x80
make之后调试运行如下:
10    nop(gdb) s11    leal val, %esi(gdb)12    leal output, %edi(gdb) s13    movsb(gdb) s14    movsw(gdb) x/s &output0x80490a8 <output>: "H"(gdb) s15    movsl(gdb) x/s &output0x80490a8 <output>: "Hel"(gdb) s17    movl $1, %eax(gdb) x/s &output0x80490a8 <output>: "Hello, "(gdb) 
可以看到在每一条movs指令之后output的内存情况,在每一次执行movs指令时,数据传送后,edi和edi寄存器会自动改变,为下一次做准备。在本示例中,寄存器是递增的,寄存器向递增还是递减方向改变取决于EFLAFS寄存器中DF标志。如果DF标志被清零,在每条movs指令执行后esi和edi寄存器就会递增,如果DF标志被设置,在每条movs指令执行后esi和edi寄存器就会递减。如果要确保DF被设置为正确的方向,在编写代码时,可以显示去设置:cld指令用于将DF标志清零,std指令用于设置DF标志。
如果要复制较长的字符串,为了简单可以movs指令放到循环当中,通过把ecx寄存器设置为字符串长度来进行控制。如下:
# movs.s.section .dataval:    .ascii "Hello, as world!\n".section .bss    .lcomm output, 17.section .text.globl _start_start:    nop    leal val, %esi    leal output, %edi    movl $17, %ecxloop_strcpy:    movsb    loop loop_strcpy    movl $1, %eax    movl $0, %ebx    int $0x80
事实上,Intel有提供更简单的指令:rep。rep指令按照ecx寄存器值执行其次数后面的字符串指令。示例如下:
# rep.s.section .dataval:    .ascii "Hello, as world!\n".section .bss    .lcomm output, 17.section .text.globl _start_start:    nop    leal val, %esi    leal output, %edi    movl $17, %ecx    cld    rep movsb    movl $1, %eax    movl $0, %ebx    int $0x80
make之后调试运行如下:
13    movl $17, %ecx(gdb)15    cld(gdb)16    rep movsb(gdb)18    movl $1, %eax(gdb) x/s &output0x80490b0 <output>: "Hello, as world!\n"(gdb)
实际上可以依次多个字节的传送,这时候就需要在ecx寄存器中放置正确的次数,以防超出字符串边界。使用movsl指令传送字符串可以使效率更高,但是必须知道什么时候停止使用movsl指令转回使用movsb指令,这可以通过整数除法来确定。
1 0
原创粉丝点击