当前位置: IT大杂烩 > Ubuntu  > linux平台学x86汇编(十一):字符串的传送

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

www.someabcd.com  网友分享于:Jun 8, 2018 5:54:33 PM

标签:

【版权声明:尊重原创,转载请保留出处: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 .data
val:
    .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) s
11    leal val, %esi
(gdb)
12    leal output, %edi
(gdb) s
13    movsb
(gdb) s
14    movsw
(gdb) x/s &output
0x80490a8 <output>: "H"
(gdb) s
15    movsl
(gdb) x/s &output
0x80490a8 <output>: "Hel"
(gdb) s
17    movl $1, %eax
(gdb) x/s &output
0x80490a8 <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 .data
val:
    .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
loop_strcpy:
    movsb
    loop loop_strcpy
    movl $1, %eax
    movl $0, %ebx
    int $0x80

事实上,Intel有提供更简单的指令:rep。rep指令按照ecx寄存器值执行其次数后面的字符串指令。示例如下:
# rep.s
.section .data
val:
    .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 &output
0x80490b0 <output>: "Hello, as world!\n"
(gdb)
实际上可以依次多个字节的传送,这时候就需要在ecx寄存器中放置正确的次数,以防超出字符串边界。使用movsl指令传送字符串可以使效率更高,但是必须知道什么时候停止使用movsl指令转回使用movsb指令,这可以通过整数除法来确定。








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

标签:

发布此文章仅为传递网友分享,不代表本站观点,若侵权请联系我们删除,本站将不对此承担任何责任。
Copyright ©2018  IT大杂烩  版权所有  京ICP备11030978号-1 网站地图