以下是D7 CopyMemory的源码,有两个问题不太明白,望高手解答
1.CMP EDI,ESI,当EDI>ESI(P1>P2)的时候会JMP到@@down,难后倒着执行复制?REP MOVS*这些指令的执行会关系到ESI,EDI谁大谁小?
2.在调试的时候发现都是执行上面的代码,不会JMP到@@down,调整定义P1,P2对应变量的位置也没用,是编译器做了优化吗?我是用下面的代码在D2010测试的。procedure _CopyMemory(P1, P2: Pointer; Len: Integer); assembler;
asm
PUSH ESI
PUSH EDI
MOV EDI,EAX { destination address }
MOV ESI,EDX { source address }
MOV EAX,ECX
CMP EDI,ESI
JA @@down
JE @@exit
SAR ECX,2 { copy count DIV 4 dwords }
JS @@exit
REP MOVSD
MOV ECX,EAX
AND ECX,03H
REP MOVSB { copy count MOD 4 bytes }
JMP @@exit
@@down:
LEA ESI,[ESI+ECX-4] { point ESI to last dword of source }
LEA EDI,[EDI+ECX-4] { point EDI to last dword of dest }
SAR ECX,2 { copy count DIV 4 dwords }
JS @@exit
STD
REP MOVSD
MOV ECX,EAX
AND ECX,03H { copy count MOD 4 bytes }
ADD ESI,4-1 { point to last byte of rest }
ADD EDI,4-1
REP MOVSB
CLD
@@exit:
POP EDI
POP ESI
end;
1.CMP EDI,ESI,当EDI>ESI(P1>P2)的时候会JMP到@@down,难后倒着执行复制?REP MOVS*这些指令的执行会关系到ESI,EDI谁大谁小?
2.在调试的时候发现都是执行上面的代码,不会JMP到@@down,调整定义P1,P2对应变量的位置也没用,是编译器做了优化吗?我是用下面的代码在D2010测试的。procedure _CopyMemory(P1, P2: Pointer; Len: Integer); assembler;
asm
PUSH ESI
PUSH EDI
MOV EDI,EAX { destination address }
MOV ESI,EDX { source address }
MOV EAX,ECX
CMP EDI,ESI
JA @@down
JE @@exit
SAR ECX,2 { copy count DIV 4 dwords }
JS @@exit
REP MOVSD
MOV ECX,EAX
AND ECX,03H
REP MOVSB { copy count MOD 4 bytes }
JMP @@exit
@@down:
LEA ESI,[ESI+ECX-4] { point ESI to last dword of source }
LEA EDI,[EDI+ECX-4] { point EDI to last dword of dest }
SAR ECX,2 { copy count DIV 4 dwords }
JS @@exit
STD
REP MOVSD
MOV ECX,EAX
AND ECX,03H { copy count MOD 4 bytes }
ADD ESI,4-1 { point to last byte of rest }
ADD EDI,4-1
REP MOVSB
CLD
@@exit:
POP EDI
POP ESI
end;
SI -> 1
DI-> 2
3
4
5
6
7
8第一轮
1
1
2
SI-> 3
DI-> 4
6
7
8第2轮
1
1
2
3
3
4
Si 6
Di 7
看到了吗, 这不是我们想要的结果, 这个时候只有反着进行copy才能达到我们想要的效果.
另外你说交换了位置也不会执行down我认为可能是你看错了, 再者可能是你的2个指针指向的是同一个位置
当然这是一个特例,只在复制的内存区域有交错的情况下发生比如
var a :array[0..n] of ByteCopyMemory(@a[10], @a[0],20);在复制到第11个字节时,其实该内存已经变成了a[0]的内容。所以,判断一下ESI EDI的大小,决定是正向还是反向Copy是非常有必要的。至后面的REP MOVSD,REP MOVSB,只是在适用范围使用最快的运算来搬字节,每次按DWORD大小复制,当字节不足4字节时,按BYTE复制。
var
//arr2: array [1..10] of Byte;
arr1: array [1..10] of Byte;
arr2: array [1..10] of Byte;
begin
...
CopyMemory(@arr1,@arr2,10);
end;