【版权声明:尊重原创,转载请保留出处: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寄存器中。
如下是一个示例:
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19# 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之后调试运行如下:
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2710 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寄存器设置为字符串长度来进行控制。如下:
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20# 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寄存器值执行其次数后面的字符串指令。示例如下:
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18# 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之后调试运行如下:
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
1413 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汇编(十一):字符串的传送的全部内容,更多相关linux平台学x86汇编(十一):字符串内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复