pmtest8.asm中lib.inc中MemCpy代码的理解
mov ax, cs
mov ds, ax
mov ax, SelectorFlatRW ;这应该是selectorFlatRW所对应的段描述符的首地址,参见pmtest7.asm
mov es, ax
push LenFoo ;0x0000001c sp:0x000001f7
push OffsetFoo ;0x000001a0 sp:0x000001f3
push ProcFoo ;ProcFoo equ 00401000h sp:0x000001ef
call MemCpy ;前面几个push是MemCpy的参数,sp:0x000001eb,call会由系统自动压入参数,所以前面的sp要加4。
;这段call的功能是把程序拷贝到ProcFoo处
; ------------------------------------------------------------------------
; 内存拷贝,仿 memcpy
; ------------------------------------------------------------------------
; void* MemCpy(void* es:pDest, void* ds:pSrc, int iSize);
; ------------------------------------------------------------------------
MemCpy:
push ebp ;sp:0x000001e7 (这是因为call的参数占有了0x000001eb的堆栈) ebp=0x00000000
mov ebp, esp ;ebp=esp=0x000001e7
push esi ; sp:0x000001e3 ,bp:0x000001e7
push edi ; sp:0xooooo1df ,bp:0x000001e7
push ecx ; sp:0x000001db, bp:0x000001e7 ;为什么要用bp呢,这是因为sp在不断变化中,不适合作为读取指针
mov edi, [ebp + 8] ; Destination ;ebp+8=0x000001ef,指向ProcFoo,值为:00401000h (见pmtest8.asm,319行)
mov esi, [ebp + 12] ; Source ;ebp+12=0x000001f3,指向OffsetFoo,值为:0x000001a0
mov ecx, [ebp + 16] ; Counter ;ebp+16=0x000001f7,指向LenFoo,值为:0x0000001c
.1:
cmp ecx, 0 ; 判断计数器
jz .2 ; 计数器为零时跳出
mov al, [ds:esi] ; ┓ ;ds等于cs (见pmtest8.asm,312行)
inc esi ; ┃
; ┣ 逐字节移动
mov byte [es:edi], al ; ┃ ;es等于selectorFlatRW所对应的段描述符的首地址(见pmtest8.asm,314行)
inc edi ; ┛
dec ecx ; 计数器减一 ;这段程序的功能是把cs:OffsetFoo的程序拷贝到selectorFLatRW段:ProcFoo的地方。
jmp .1 ; 循环 ;selectorFlatRW段首地址为0,所以就是拷贝到ProcFoo的地方,即00401000h处
.2:
mov eax, [ebp + 8] ; 返回值 ;eax=00401000h
pop ecx ;sp:0x000001df
pop edi ;sp:0x000001e3
pop esi ;sp:0x000001e7
mov esp, ebp ;ebp=0x000001e7,esp=ebp,esp=0x000001e7
pop ebp ;sp:0x000001eb,ebp=0x00000000
ret ; 函数结束,返回 ;sp:0x000001ef
; MemCpy 结束-------------------------------------------------------------