码迷,mamicode.com
首页 > 系统相关 > 详细

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

时间:2015-05-09 16:32:04      阅读:166      评论:0      收藏:0      [点我收藏+]

标签:

【版权声明:尊重原创,转载请保留出处: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汇编(十一):字符串的传送

标签:

原文地址:http://blog.csdn.net/shallnet/article/details/45602199

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!