以下是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.   

    看一下如下实例, 当DI > SI的时候如果正向复制的话就会导致如下情况. 复制函数为了保证效率采用了CPU字长大小的方式进行COPY, 当你是32位的CPU一次拷贝4个字节是最有效率的.初始
    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个指针指向的是同一个位置
      

  2.   

    倒着COPY是一个保护源数据不被破坏的处理
    当然这是一个特例,只在复制的内存区域有交错的情况下发生比如
    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复制。
      

  3.   

    谢谢Hexpate的回复,好详细,我没有想到复制和被复制的内存是可以重叠的,另外@@down里面确实会执行,我是搞错了,像下面在局部变量把定义的位置对调就会产生跳转,昨天搞得晕晕的没有测试出来。同样谢谢CaesarDM。
    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;