在《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