|
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 是同义词。 |
|