在《32位汇编语言学习笔记(19)--缓冲区溢出实验》中,我们曾遇到过一个字符串指令:repnz scas,现在我们要学习另外一个字符串指令:rep movsb。
首先看一个小程序:
section .data
EditBuff: db 'abcdefghijklm ',10
BUFFERLEN equ $-EditBuff
ENDPOS equ 12
INSRTPOS equ 0
section .text
WriteStr:
push eax ; Save pertinent registers
push ebx
mov eax,4 ; Specify sys_write call
mov ebx,1 ; Specify File Descriptor 1: Stdout
int 80H ; Make the kernel call
pop ebx ; Restore pertinent registers
pop eax
ret ; Go home
global _start
_start:
nop
mov ecx,EditBuff
mov edx,BUFFERLEN
call WriteStr
std ; Up-memory transfer
mov ebx,EditBuff+INSRTPOS
mov esi,EditBuff+ENDPOS ; Start at end of text
mov edi,EditBuff+ENDPOS+1 ; Bump text right by 1
mov ecx,ENDPOS-INSRTPOS+1 ; # of chars to bump
rep movsb ; Move 'em!
mov byte [ebx],' '
mov ecx,EditBuff
mov edx,BUFFERLEN
call WriteStr
Exit: mov eax,1 ; Code for Exit Syscall
mov ebx,0 ; Return a code of zero
int 80H ; Make kernel call
程序分析:
mov ecx,EditBuff
mov edx,BUFFERLEN
call WriteStr //打印字符串的初值
std //std指令,设置DF标志位,这会使得rep movsb执行循环拷贝操作时,源地址和目的地址变化方向是从高到低。
mov ebx,EditBuff+INSRTPOS //ebx= EditBuff
mov esi,EditBuff+ENDPOS //esi = &EditBuff[12],esi是rep movsb的源地址,指向’m’。
mov edi,EditBuff+ENDPOS+1 //edi= &EditBuff[13],edi是rep movsb的目的地址,指向第一个空格。
mov ecx,ENDPOS-INSRTPOS+1 //ecx=13,用于rep movsb的循环计数器
rep movsb //通过循环把源地址的数据拷贝到目的地址上,每循环一次ecx就会减1,esi和edi也会减1,当ecx=0时终止循环。执行顺序是:先判断ecx是否为0,如果非0,进行拷贝操作,然后ecx=ecx-1,edi=edi-1,esi=esi-1,进入下一次循环,否则退出循环。因此,循环次数是13。
mov byte [ebx],' ' // EditBuff[0]=’ ’
mov ecx,EditBuff
mov edx,BUFFERLEN
call WriteStr //打印修改后的字符串。
makefile文件:
movsbdemo: movsbdemo.o
ld -o movsbdemo movsbdemo.o
movsbdemo.o: movsbdemo.asm
nasm -f elf -g -F stabs movsbdemo.asm -l movsbdemo.lst
测试:
[root@bogon movsbdemo]# make
nasm -f elf -g -F stabs movsbdemo.asm -l movsbdemo.lst
ld -o movsbdemo movsbdemo.o
[root@bogon movsbdemo]# ./movsbdemo
abcdefghijklm
abcdefghijklm