曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 7863|回复: 0
打印 上一主题 下一主题

REP 指令

[复制链接]

4917

主题

5879

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34382
跳转到指定楼层
楼主
发表于 2010-8-16 17:15:32 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
REP 指令自己不执行什么操作,它用于按照特定次数重复执行字符串指令,由 ECX 寄存器中的值控制。与循环类似,但不需要额外的 LOOP 指令。REP 指令重复地执行紧跟其后的字符串指令,直到 ECX 中的值为 0 。

1. 逐字节传送字符串
MOVSB 和 REP 一起使用,每次 1 字节地把字符串传送到另一个位置:
.section .data
value1:
     .ascii "This is a test string.\n"

.section .bss
     .lcomm output, 23

.section .text
.global _start

_start:
     nop
     leal value1, %esi
     leal output, %edi
     movl $23, %ecx
     cld
     rep movsb

     movl $1, %eax
     movl $0, %ebx
     int $0x80
调试:
$ gdb -q rep
Reading symbols from /home/beyes/Programming/Assembly/rep...done.
15        movl $23, %ecx
(gdb) s
16        cld
(gdb) s
17        rep movsb
(gdb) s
19        movl $1, %eax
(gdb) x/s &output
0x80490b0 <output>:     "This is a test string.\n"
由上可见, REP 执行了 MOVSB 23 次,但是在调试器中单步执行时,REP 指令仍然只算是一个指令步骤,而不是 23 次。gdb 加 -q 参数表示使用安静模式,即不输出版权信息。

2. 逐块传送字符串
并不只能逐字节传送字符串,使用 MOVSW 和 MOVSL 可以在每次迭代中传送 1 字节以上的数据。
如果使用 MOVSW 和 MOVSL ,则 ECX 就应该包含遍历字符串的迭代次数。例如传送 8 字节的字符串,使用 MOVSB 需要将 ECX 设置为 8,MOVSW 的话就要设置为 4,使用 MOVSL 就要设置为 2 。
使用 MOVSW 和 MOVSL 遍历字符串时,一定要小心不要越界!这种情况如下程序所示:
.section .data
value1:
     .ascii "This is a test string.\n"

value2:
     .ascii "Oops"

.section .bss
     .lcomm output, 23

.section .text
.global _start

_start:
     nop
     leal value1, %esi
     leal output, %edi
     movl $6, %ecx
     cld
     rep movsl

     movl $1, %eax
     movl $0, %ebx
     int $0x80

使用 GDB 调试:
Breakpoint 1 at 0x8048089: file rep2.s, line 22.
(gdb) r
Starting program: /home/beyes/Programming/Assembly/rep2

Breakpoint 1, _start () at rep2.s:22
22        movl $1, %eax
(gdb) x/s &output
0x80490b8 <output>:     "This is a test string.\nO"
上从可以看出,字符串越界了。

3. 传送大型字符串
在传送大型字符串时,使用 MOVSL 指令将使效率提高。从上面的越界程序知道,关键在于什么时候停止使用 MOVSL 并且转回使用 MOVSB 。如果知道了字符串的长度,就可以用除法来确定字符串中包含了多少个双字,然后余数用 MOVSB 进行传送(迭代次数不大于3):
.section .data
string1:
     .asciz "This is a test of the conversion program!\n"
length:
     .int 43

.section .bss
     .lcomm buffer, 43

.section .text
.global _start

_start:
     nop
     leal string1, %esi
     leal buffer, %edi
     movl length, %ecx
     shrl $2, %ecx    # 43/4=10
     
     cld
     rep movsl
     movl length, %ecx
     andl $3, %ecx   #求余下的字节,此处应为3
     rep movsb
     
     movl $1, %eax
     movl $0, %ebx
     int $0x80
执行过 rep movsl 后在 GDB 中看到:
(gdb) x/s &buffer
0x80490d8 <buffer>:     "This is a test of the conversion program"
执行 rep movsb 后看到:
(gdb) n
26        movl $1, %eax
(gdb) x/s &buffer
0x80490d8 <buffer>:     "This is a test of the conversion program!\n"
由上可见,字符串中的最后两个字符被成功的传送了。

其他 REP 指令
虽然 REP 指令很方便,在处理字符串时,也可以使用它的其它版本。除了监视 ECX 的值外,还有监视零标志(ZF)的状态的 REP 指令,如:
指令
描述
REPE
等于时重复
REPNE
不等于时重复
REPNZ
不为零时重复
REPZ
为零时重复
REPE 和 REPZ 指令是相同指令的同义词,REPNE 和 REPNZ 是同义词。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2024-5-14 20:22 , Processed in 0.079357 second(s), 23 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表