技术宅的结界

 找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 1216|回复: 10
收起左侧

【C】memcpy真的就只是复制内存吗?然而并没有那么简单。

[复制链接]

1008

主题

2235

帖子

5万

积分

用户组: 管理员

一只技术宅

UID
1
精华
200
威望
265 点
宅币
16762 个
贡献
33386 次
宅之契约
0 份
在线时间
1598 小时
注册时间
2014-1-26
发表于 2017-5-29 21:14:48 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有帐号?立即注册→加入我们

x
曾有人在QQ群里发了一个代码片段,自己实现memcpy的功能,然后内容大概如下:
[C] 纯文本查看 复制代码
void COPY(void *dest, void *src, size_t len)
{
    char *cdest = dest;
    char *csrc = src;
    size_t i;
    for(i = 0; i < len; i++)
        cdest[i] = csrc[i];
}
代码非常简单直白,通俗易懂,但我们真的有必要造个这样的轮子吗?先不说别的,memcpy真的就是这样实现的吗?
我们来看一下VS2012的memcpy的反汇编。这里我随便搞了个工程然后随便打了些代码,要的就是在执行memcpy的时候戳个断点进去看。
zakkuri.png
嗯可以看到VS2012的memcpy是拿汇编写的而且我们可以看到源码。我把它复制出来,详细的解释在后面,这里只做参考,可掠过。
[Asm] 纯文本查看 复制代码
--- f:\dd\vctools\crt_bld\SELF_X86\crt\src\INTEL\memcpy.asm --------------------
        dst:ptr byte, \
        src:ptr byte, \
        count:IWORD

        ; destination pointer
        ; source pointer
        ; number of bytes to copy

        OPTION PROLOGUE:NONE, EPILOGUE:NONE

        push    edi             ;U - save edi
0012B090 57                   push        edi  
        push    esi             ;V - save esi
0012B091 56                   push        esi  

;                   size param/4   prolog byte  #reg saved
        .FPO ( 0, 3           , $-_MEM_     , 2, 0, 0 )

        mov     esi,[esp + 010h]     ;U - esi = source
0012B092 8B 74 24 10          mov         esi,dword ptr [esp+10h]  
        mov     ecx,[esp + 014h]     ;V - ecx = number of bytes to move
0012B096 8B 4C 24 14          mov         ecx,dword ptr [esp+14h]  
        mov     edi,[esp + 0Ch]      ;U - edi = dest
0012B09A 8B 7C 24 0C          mov         edi,dword ptr [esp+0Ch]  

;
; Check for overlapping buffers:
;       If (dst <= src) Or (dst >= src + Count) Then
;               Do normal (Upwards) Copy
;       Else
;               Do Downwards Copy to avoid propagation
;

        mov     eax,ecx         ;V - eax = byte count...
0012B09E 8B C1                mov         eax,ecx  

        mov     edx,ecx         ;U - edx = byte count...
0012B0A0 8B D1                mov         edx,ecx  
        add     eax,esi         ;V - eax = point past source end
0012B0A2 03 C6                add         eax,esi  

        cmp     edi,esi         ;U - dst <= src ?
0012B0A4 3B FE                cmp         edi,esi  
        jbe     short CopyUp    ;V - yes, copy toward higher addresses
0012B0A6 76 08                jbe         CopyUp (012B0B0h)  

        cmp     edi,eax         ;U - dst < (src + count) ?
0012B0A8 3B F8                cmp         edi,eax  
        jb      CopyDown        ;V - yes, copy toward lower addresses
0012B0AA 0F 82 68 03 00 00    jb          TrailUpVec+50h (012B418h)  

;
; Copy toward higher addresses.
;
CopyUp:
;
        ; See if Enhanced Fast Strings is supported.
        ; ENFSTRG supported?
        bt      __favor, __FAVOR_ENFSTRG
0012B0B0 0F BA 25 FC 63 17 00 01 bt          dword ptr ds:[1763FCh],1  
        jnc     CopyUpSSE2Check                 ; no jump
0012B0B8 73 07                jae         CopyUp+11h (012B0C1h)  
        ;
        ; use Enhanced Fast Strings
        rep     movsb
0012B0BA F3 A4                rep movs    byte ptr es:[edi],byte ptr [esi]  
        jmp     TrailUp0         ; Done
0012B0BC E9 17 03 00 00       jmp         TrailUpVec+10h (012B3D8h)  
CopyUpSSE2Check:
;
; Next, see if we can use a "fast" copy SSE2 routine
        ; block size greater than min threshold?
        cmp     ecx,080h
0012B0C1 81 F9 80 00 00 00    cmp         ecx,80h  
        jb      Dword_align  ; length too small go use dwords
0012B0C7 0F 82 CE 01 00 00    jb          CopyUp+1EBh (012B29Bh)  
        ; alignments equal?
        mov     eax,edi
0012B0CD 8B C7                mov         eax,edi  
        xor     eax,esi
0012B0CF 33 C6                xor         eax,esi  
        test    eax,15
0012B0D1 A9 0F 00 00 00       test        eax,0Fh  
        jne     AtomChk   ; Not aligned go check Atom
0012B0D6 75 0E                jne         CopyUp+36h (012B0E6h)  
        bt      __isa_enabled, __ISA_AVAILABLE_SSE2
0012B0D8 0F BA 25 00 50 17 00 01 bt          dword ptr ds:[175000h],1  
        jc      VEC_memcpy ; yes, go SSE2 copy (params already set)
0012B0E0 0F 82 DA 04 00 00    jb          TrailDownVec+5Ch (012B5C0h)  
AtomChk:
        ; Is Atom supported?
        bt      __favor, __FAVOR_ATOM
0012B0E6 0F BA 25 FC 63 17 00 00 bt          dword ptr ds:[1763FCh],0  
        jnc     Dword_align ; no,jump
0012B0EE 0F 83 A7 01 00 00    jae         CopyUp+1EBh (012B29Bh)  

        ; check if dst is 4 byte aligned
        test    edi, 3
0012B0F4 F7 C7 03 00 00 00    test        edi,3  
        jne     CopyLeadUp
0012B0FA 0F 85 B8 01 00 00    jne         CopyUp+208h (012B2B8h)  

        ; check if src is 4 byte aligned
        test    esi, 3
0012B100 F7 C6 03 00 00 00    test        esi,3  
        jne     Dword_align_Ok
0012B106 0F 85 97 01 00 00    jne         CopyUp+1F3h (012B2A3h)  

; A software pipelining vectorized memcpy loop using PALIGN instructions

; (1) copy the first bytes to align dst up to the nearest 16-byte boundary
; 4 byte align -> 12 byte copy, 8 byte align -> 8 byte copy, 12 byte align -> 4 byte copy
PalignHead4:
        bt      edi, 2
0012B10C 0F BA E7 02          bt          edi,2  
        jae     PalignHead8
0012B110 73 0D                jae         CopyUp+6Fh (012B11Fh)  
        mov     eax, dword ptr [esi]
0012B112 8B 06                mov         eax,dword ptr [esi]  
        sub     ecx, 4
0012B114 83 E9 04             sub         ecx,4  
        lea     esi, byte ptr [esi+4]
0012B117 8D 76 04             lea         esi,[esi+4]  
        mov     dword ptr [edi], eax
0012B11A 89 07                mov         dword ptr [edi],eax  
        lea     edi, byte ptr [edi+4]
0012B11C 8D 7F 04             lea         edi,[edi+4]  

PalignHead8:
        bt      edi, 3
0012B11F 0F BA E7 03          bt          edi,3  
        jae     PalignLoop
0012B123 73 11                jae         CopyUp+86h (012B136h)  
        movq    xmm1, qword ptr [esi]
0012B125 F3 0F 7E 0E          movq        xmm1,mmword ptr [esi]  
        sub     ecx, 8
0012B129 83 E9 08             sub         ecx,8  
        lea     esi, byte ptr [esi+8]
0012B12C 8D 76 08             lea         esi,[esi+8]  
        movq    qword ptr [edi], xmm1
0012B12F 66 0F D6 0F          movq        mmword ptr [edi],xmm1  
        lea     edi, byte ptr [edi+8]
0012B133 8D 7F 08             lea         edi,[edi+8]  

;(2) Use SSE palign loop
PalignLoop:
        test    esi, 7
0012B136 F7 C6 07 00 00 00    test        esi,7  
        je      MovPalign8
0012B13C 74 63                je          CopyUp+0F1h (012B1A1h)  
        bt      esi, 3
0012B13E 0F BA E6 03          bt          esi,3  
        jae     MovPalign4
0012B142 0F 83 B2 00 00 00    jae         CopyUp+14Ah (012B1FAh)  

PALIGN_memcpy 12
0012B148 66 0F 6F 4E F4       movdqa      xmm1,xmmword ptr [esi-0Ch]  
0012B14D 8D 76 F4             lea         esi,[esi-0Ch]  
PalignLoop12:
0012B150 66 0F 6F 5E 10       movdqa      xmm3,xmmword ptr [esi+10h]  
0012B155 83 E9 30             sub         ecx,30h  
0012B158 66 0F 6F 46 20       movdqa      xmm0,xmmword ptr [esi+20h]  
0012B15D 66 0F 6F 6E 30       movdqa      xmm5,xmmword ptr [esi+30h]  
0012B162 8D 76 30             lea         esi,[esi+30h]  
0012B165 83 F9 30             cmp         ecx,30h  
0012B168 66 0F 6F D3          movdqa      xmm2,xmm3  
0012B16C 66 0F 3A 0F D9 0C    palignr     xmm3,xmm1,0Ch  
0012B172 66 0F 7F 1F          movdqa      xmmword ptr [edi],xmm3  
0012B176 66 0F 6F E0          movdqa      xmm4,xmm0  
0012B17A 66 0F 3A 0F C2 0C    palignr     xmm0,xmm2,0Ch  
0012B180 66 0F 7F 47 10       movdqa      xmmword ptr [edi+10h],xmm0  
0012B185 66 0F 6F CD          movdqa      xmm1,xmm5  
0012B189 66 0F 3A 0F EC 0C    palignr     xmm5,xmm4,0Ch  
0012B18F 66 0F 7F 6F 20       movdqa      xmmword ptr [edi+20h],xmm5  
0012B194 8D 7F 30             lea         edi,[edi+30h]  
0012B197 7D B7                jge         CopyUp+0A0h (012B150h)  
0012B199 8D 76 0C             lea         esi,[esi+0Ch]  
        jmp     PalignTail
0012B19C E9 AF 00 00 00       jmp         CopyUp+1A0h (012B250h)  

PALIGN_memcpy 8
0012B1A1 66 0F 6F 4E F8       movdqa      xmm1,xmmword ptr [esi-8]  
0012B1A6 8D 76 F8             lea         esi,[esi-8]  
0012B1A9 8D 49 00             lea         ecx,[ecx]  
PalignLoop8:
0012B1AC 66 0F 6F 5E 10       movdqa      xmm3,xmmword ptr [esi+10h]  
0012B1B1 83 E9 30             sub         ecx,30h  
0012B1B4 66 0F 6F 46 20       movdqa      xmm0,xmmword ptr [esi+20h]  
0012B1B9 66 0F 6F 6E 30       movdqa      xmm5,xmmword ptr [esi+30h]  
0012B1BE 8D 76 30             lea         esi,[esi+30h]  
0012B1C1 83 F9 30             cmp         ecx,30h  
0012B1C4 66 0F 6F D3          movdqa      xmm2,xmm3  
0012B1C8 66 0F 3A 0F D9 08    palignr     xmm3,xmm1,8  
0012B1CE 66 0F 7F 1F          movdqa      xmmword ptr [edi],xmm3  
0012B1D2 66 0F 6F E0          movdqa      xmm4,xmm0  
0012B1D6 66 0F 3A 0F C2 08    palignr     xmm0,xmm2,8  
0012B1DC 66 0F 7F 47 10       movdqa      xmmword ptr [edi+10h],xmm0  
0012B1E1 66 0F 6F CD          movdqa      xmm1,xmm5  
0012B1E5 66 0F 3A 0F EC 08    palignr     xmm5,xmm4,8  
0012B1EB 66 0F 7F 6F 20       movdqa      xmmword ptr [edi+20h],xmm5  
0012B1F0 8D 7F 30             lea         edi,[edi+30h]  
0012B1F3 7D B7                jge         CopyUp+0FCh (012B1ACh)  
0012B1F5 8D 76 08             lea         esi,[esi+8]  
        jmp     PalignTail
0012B1F8 EB 56                jmp         CopyUp+1A0h (012B250h)  

PALIGN_memcpy 4
0012B1FA 66 0F 6F 4E FC       movdqa      xmm1,xmmword ptr [esi-4]  
0012B1FF 8D 76 FC             lea         esi,[esi-4]  
0012B202 8B FF                mov         edi,edi  
PalignLoop4:
0012B204 66 0F 6F 5E 10       movdqa      xmm3,xmmword ptr [esi+10h]  
0012B209 83 E9 30             sub         ecx,30h  
0012B20C 66 0F 6F 46 20       movdqa      xmm0,xmmword ptr [esi+20h]  
0012B211 66 0F 6F 6E 30       movdqa      xmm5,xmmword ptr [esi+30h]  
0012B216 8D 76 30             lea         esi,[esi+30h]  
0012B219 83 F9 30             cmp         ecx,30h  
0012B21C 66 0F 6F D3          movdqa      xmm2,xmm3  
0012B220 66 0F 3A 0F D9 04    palignr     xmm3,xmm1,4  
0012B226 66 0F 7F 1F          movdqa      xmmword ptr [edi],xmm3  
0012B22A 66 0F 6F E0          movdqa      xmm4,xmm0  
0012B22E 66 0F 3A 0F C2 04    palignr     xmm0,xmm2,4  
0012B234 66 0F 7F 47 10       movdqa      xmmword ptr [edi+10h],xmm0  
0012B239 66 0F 6F CD          movdqa      xmm1,xmm5  
0012B23D 66 0F 3A 0F EC 04    palignr     xmm5,xmm4,4  
0012B243 66 0F 7F 6F 20       movdqa      xmmword ptr [edi+20h],xmm5  
0012B248 8D 7F 30             lea         edi,[edi+30h]  
0012B24B 7D B7                jge         CopyUp+154h (012B204h)  
0012B24D 8D 76 04             lea         esi,[esi+4]  

;(3) Copy the tailing bytes.
PalignTail:
        cmp    ecx,10h
0012B250 83 F9 10             cmp         ecx,10h  
        jl     PalignTail4
0012B253 7C 13                jl          CopyUp+1B8h (012B268h)  
        movdqu xmm1,xmmword ptr [esi]
0012B255 F3 0F 6F 0E          movdqu      xmm1,xmmword ptr [esi]  
        sub    ecx, 10h
0012B259 83 E9 10             sub         ecx,10h  
        lea    esi, xmmword ptr [esi+10h]
0012B25C 8D 76 10             lea         esi,[esi+10h]  
        movdqa xmmword ptr [edi],xmm1
0012B25F 66 0F 7F 0F          movdqa      xmmword ptr [edi],xmm1  
        lea    edi, xmmword ptr [edi+10h]
0012B263 8D 7F 10             lea         edi,[edi+10h]  
        jmp    PalignTail
0012B266 EB E8                jmp         CopyUp+1A0h (012B250h)  

PalignTail4:
        bt      ecx, 2
0012B268 0F BA E1 02          bt          ecx,2  
        jae     PalignTail8
0012B26C 73 0D                jae         CopyUp+1CBh (012B27Bh)  
        mov     eax, dword ptr [esi]
0012B26E 8B 06                mov         eax,dword ptr [esi]  
        sub     ecx,4
0012B270 83 E9 04             sub         ecx,4  
        lea     esi, byte ptr [esi+4]
0012B273 8D 76 04             lea         esi,[esi+4]  
        mov     dword ptr [edi], eax
0012B276 89 07                mov         dword ptr [edi],eax  
        lea     edi, byte ptr [edi+4]
0012B278 8D 7F 04             lea         edi,[edi+4]  

PalignTail8:
        bt      ecx, 3
0012B27B 0F BA E1 03          bt          ecx,3  
        jae     PalignTailLE3
0012B27F 73 11                jae         CopyUp+1E2h (012B292h)  
        movq    xmm1, qword ptr [esi]
0012B281 F3 0F 7E 0E          movq        xmm1,mmword ptr [esi]  
        sub     ecx,8
0012B285 83 E9 08             sub         ecx,8  
        lea     esi, byte ptr [esi+8]
0012B288 8D 76 08             lea         esi,[esi+8]  
        movq    qword ptr [edi], xmm1
0012B28B 66 0F D6 0F          movq        mmword ptr [edi],xmm1  
        lea     edi, byte ptr [edi+8]
0012B28F 8D 7F 08             lea         edi,[edi+8]  

PalignTailLE3:
        mov     eax, dword ptr TrailUpVec[ecx*4]
0012B292 8B 04 8D C8 B3 12 00 mov         eax,dword ptr [ecx*4+12B3C8h]  
        jmp     eax
0012B299 FF E0                jmp         eax  

; The algorithm for forward moves is to align the destination to a dword
; boundary and so we can move dwords with an aligned destination.  This
; occurs in 3 steps.
;
;   - move x = ((4 - Dest & 3) & 3) bytes
;   - move y = ((L-x) >> 2) dwords
;   - move (L - x - y*4) bytes
;

Dword_align:
        test    edi,11b         ;U - destination dword aligned?
0012B29B F7 C7 03 00 00 00    test        edi,3  
        jnz     short CopyLeadUp ;V - if we are not dword aligned already, align
0012B2A1 75 15                jne         CopyUp+208h (012B2B8h)  
Dword_align_Ok:
        shr     ecx,2           ;U - shift down to dword count
0012B2A3 C1 E9 02             shr         ecx,2  
        and     edx,11b         ;V - trailing byte count
0012B2A6 83 E2 03             and         edx,3  

        cmp     ecx,8           ;U - test if small enough for unwind copy
0012B2A9 83 F9 08             cmp         ecx,8  
        jb      short CopyUnwindUp ;V - if so, then jump
0012B2AC 72 2A                jb          CopyUp+228h (012B2D8h)  

        rep     movsd           ;N - move all of our dwords
0012B2AE F3 A5                rep movs    dword ptr es:[edi],dword ptr [esi]  

        jmp     dword ptr TrailUpVec[edx*4] ;N - process trailing bytes
0012B2B0 FF 24 95 C8 B3 12 00 jmp         dword ptr [edx*4+12B3C8h]  
0012B2B7 90                   nop  

;
; Code to do optimal memory copies for non-dword-aligned destinations.
;

; The following length check is done for two reasons:
;
;    1. to ensure that the actual move length is greater than any possiale
;       alignment move, and
;
;    2. to skip the multiple move logic for small moves where it would
;       be faster to move the bytes with one instruction.
;

        align   @WordSize
CopyLeadUp:

        mov     eax,edi         ;U - get destination offset
0012B2B8 8B C7                mov         eax,edi  
        mov     edx,11b         ;V - prepare for mask
0012B2BA BA 03 00 00 00       mov         edx,3  

        sub     ecx,4           ;U - check for really short string - sub for adjust
0012B2BF 83 E9 04             sub         ecx,4  
        jb      short ByteCopyUp ;V - branch to just copy bytes
0012B2C2 72 0C                jb          CopyUp+220h (012B2D0h)  

        and     eax,11b         ;U - get offset within first dword
0012B2C4 83 E0 03             and         eax,3  
        add     ecx,eax         ;V - update size after leading bytes copied
0012B2C7 03 C8                add         ecx,eax  

        jmp     dword ptr LeadUpVec[eax*4-4] ;N - process leading bytes
0012B2C9 FF 24 85 DC B2 12 00 jmp         dword ptr [eax*4+12B2DCh]  

        align   @WordSize
ByteCopyUp:
        jmp     dword ptr TrailUpVec[ecx*4+16] ;N - process just bytes
0012B2D0 FF 24 8D D8 B3 12 00 jmp         dword ptr [ecx*4+12B3D8h]  
0012B2D7 90                   nop  

        align   @WordSize
CopyUnwindUp:
        jmp     dword ptr UnwindUpVec[ecx*4] ;N - unwind dword copy
0012B2D8 FF 24 8D 5C B3 12 00 jmp         dword ptr [ecx*4+12B35Ch]  
0012B2DF 90                   nop
--- 无源文件 -----------------------------------------------------------------------
0012B2E0 EC                   in          al,dx  
0012B2E1 B2 12                mov         dl,12h  
0012B2E3 00 18                add         byte ptr [eax],bl  
0012B2E5 B3 12                mov         bl,12h  
0012B2E7 00 3C B3             add         byte ptr [ebx+esi*4],bh  
0012B2EA 12 00                adc         al,byte ptr [eax]  
LeadUp1:
0012B2EC 23 D1                and         edx,ecx  
0012B2EE 8A 06                mov         al,byte ptr [esi]  
0012B2F0 88 07                mov         byte ptr [edi],al  
0012B2F2 8A 46 01             mov         al,byte ptr [esi+1]  
0012B2F5 88 47 01             mov         byte ptr [edi+1],al  
0012B2F8 8A 46 02             mov         al,byte ptr [esi+2]  
0012B2FB C1 E9 02             shr         ecx,2  
0012B2FE 88 47 02             mov         byte ptr [edi+2],al  
0012B301 83 C6 03             add         esi,3  
0012B304 83 C7 03             add         edi,3  
0012B307 83 F9 08             cmp         ecx,8  
0012B30A 72 CC                jb          CopyUp+228h (012B2D8h)  
0012B30C F3 A5                rep movs    dword ptr es:[edi],dword ptr [esi]  
0012B30E FF 24 95 C8 B3 12 00 jmp         dword ptr [edx*4+12B3C8h]  
0012B315 8D 49 00             lea         ecx,[ecx]  
LeadUp2:
0012B318 23 D1                and         edx,ecx  
0012B31A 8A 06                mov         al,byte ptr [esi]  
0012B31C 88 07                mov         byte ptr [edi],al  
0012B31E 8A 46 01             mov         al,byte ptr [esi+1]  
0012B321 C1 E9 02             shr         ecx,2  
0012B324 88 47 01             mov         byte ptr [edi+1],al  
0012B327 83 C6 02             add         esi,2  
0012B32A 83 C7 02             add         edi,2  
0012B32D 83 F9 08             cmp         ecx,8  
0012B330 72 A6                jb          CopyUp+228h (012B2D8h)  
0012B332 F3 A5                rep movs    dword ptr es:[edi],dword ptr [esi]  
0012B334 FF 24 95 C8 B3 12 00 jmp         dword ptr [edx*4+12B3C8h]  
0012B33B 90                   nop  
LeadUp3:
0012B33C 23 D1                and         edx,ecx  
0012B33E 8A 06                mov         al,byte ptr [esi]  
0012B340 88 07                mov         byte ptr [edi],al  
0012B342 83 C6 01             add         esi,1  
0012B345 C1 E9 02             shr         ecx,2  
0012B348 83 C7 01             add         edi,1  
0012B34B 83 F9 08             cmp         ecx,8  
0012B34E 72 88                jb          CopyUp+228h (012B2D8h)  
0012B350 F3 A5                rep movs    dword ptr es:[edi],dword ptr [esi]  
0012B352 FF 24 95 C8 B3 12 00 jmp         dword ptr [edx*4+12B3C8h]  
0012B359 8D 49 00             lea         ecx,[ecx]  
0012B35C BF B3 12 00 AC       mov         edi,0AC0012B3h  
0012B361 B3 12                mov         bl,12h  
0012B363 00 A4 B3 12 00 9C B3 add         byte ptr [ebx+esi*4-4C63FFEEh],ah  
0012B36A 12 00                adc         al,byte ptr [eax]  
0012B36C 94                   xchg        eax,esp  
0012B36D B3 12                mov         bl,12h  
0012B36F 00 8C B3 12 00 84 B3 add         byte ptr [ebx+esi*4-4C7BFFEEh],cl  
0012B376 12 00                adc         al,byte ptr [eax]  
0012B378 7C B3                jl          LeadUpVec+4Dh (012B32Dh)  
0012B37A 12 00                adc         al,byte ptr [eax]  
UnwindUp7:
0012B37C 8B 44 8E E4          mov         eax,dword ptr [esi+ecx*4-1Ch]  
0012B380 89 44 8F E4          mov         dword ptr [edi+ecx*4-1Ch],eax  
UnwindUp6:
0012B384 8B 44 8E E8          mov         eax,dword ptr [esi+ecx*4-18h]  
0012B388 89 44 8F E8          mov         dword ptr [edi+ecx*4-18h],eax  
UnwindUp5:
0012B38C 8B 44 8E EC          mov         eax,dword ptr [esi+ecx*4-14h]  
0012B390 89 44 8F EC          mov         dword ptr [edi+ecx*4-14h],eax  
UnwindUp4:
0012B394 8B 44 8E F0          mov         eax,dword ptr [esi+ecx*4-10h]  
0012B398 89 44 8F F0          mov         dword ptr [edi+ecx*4-10h],eax  
UnwindUp3:
0012B39C 8B 44 8E F4          mov         eax,dword ptr [esi+ecx*4-0Ch]  
0012B3A0 89 44 8F F4          mov         dword ptr [edi+ecx*4-0Ch],eax  
UnwindUp2:
0012B3A4 8B 44 8E F8          mov         eax,dword ptr [esi+ecx*4-8]  
0012B3A8 89 44 8F F8          mov         dword ptr [edi+ecx*4-8],eax  
UnwindUp1:
0012B3AC 8B 44 8E FC          mov         eax,dword ptr [esi+ecx*4-4]  
0012B3B0 89 44 8F FC          mov         dword ptr [edi+ecx*4-4],eax  
0012B3B4 8D 04 8D 00 00 00 00 lea         eax,[ecx*4]  
0012B3BB 03 F0                add         esi,eax  
0012B3BD 03 F8                add         edi,eax  
UnwindUp0:
0012B3BF FF 24 95 C8 B3 12 00 jmp         dword ptr [edx*4+12B3C8h]  
0012B3C6 8B FF                mov         edi,edi  
0012B3C8 D8 B3 12 00 E0 B3    fdiv        dword ptr [ebx-4C1FFFEEh]  
0012B3CE 12 00                adc         al,byte ptr [eax]  
0012B3D0 EC                   in          al,dx  
0012B3D1 B3 12                mov         bl,12h  
0012B3D3 00 00                add         byte ptr [eax],al  
0012B3D5 B4 12                mov         ah,12h  
0012B3D7 00 8B 44 24 0C 5E    add         byte ptr [ebx+5E0C2444h],cl  
0012B3DD 5F                   pop         edi  
0012B3DE C3                   ret  
0012B3DF 90                   nop  
TrailUp1:
0012B3E0 8A 06                mov         al,byte ptr [esi]  
0012B3E2 88 07                mov         byte ptr [edi],al  
0012B3E4 8B 44 24 0C          mov         eax,dword ptr [esp+0Ch]  
0012B3E8 5E                   pop         esi  
0012B3E9 5F                   pop         edi  
0012B3EA C3                   ret  
0012B3EB 90                   nop  
TrailUp2:
0012B3EC 8A 06                mov         al,byte ptr [esi]  
0012B3EE 88 07                mov         byte ptr [edi],al  
0012B3F0 8A 46 01             mov         al,byte ptr [esi+1]  
0012B3F3 88 47 01             mov         byte ptr [edi+1],al  
0012B3F6 8B 44 24 0C          mov         eax,dword ptr [esp+0Ch]  
0012B3FA 5E                   pop         esi  
0012B3FB 5F                   pop         edi  
0012B3FC C3                   ret  
0012B3FD 8D 49 00             lea         ecx,[ecx]  
TrailUp3:
0012B400 8A 06                mov         al,byte ptr [esi]  
0012B402 88 07                mov         byte ptr [edi],al  
0012B404 8A 46 01             mov         al,byte ptr [esi+1]  
0012B407 88 47 01             mov         byte ptr [edi+1],al  
0012B40A 8A 46 02             mov         al,byte ptr [esi+2]  
0012B40D 88 47 02             mov         byte ptr [edi+2],al  
0012B410 8B 44 24 0C          mov         eax,dword ptr [esp+0Ch]  
0012B414 5E                   pop         esi  
0012B415 5F                   pop         edi  
0012B416 C3                   ret  
0012B417 90                   nop  
CopyDown:
0012B418 8D 74 31 FC          lea         esi,[ecx+esi-4]  
0012B41C 8D 7C 39 FC          lea         edi,[ecx+edi-4]  
0012B420 F7 C7 03 00 00 00    test        edi,3  
0012B426 75 24                jne         TrailUpVec+84h (012B44Ch)  
0012B428 C1 E9 02             shr         ecx,2  
0012B42B 83 E2 03             and         edx,3  
0012B42E 83 F9 08             cmp         ecx,8  
0012B431 72 0D                jb          TrailUpVec+78h (012B440h)  
0012B433 FD                   std  
0012B434 F3 A5                rep movs    dword ptr es:[edi],dword ptr [esi]  
0012B436 FC                   cld  
0012B437 FF 24 95 64 B5 12 00 jmp         dword ptr [edx*4+12B564h]  
0012B43E 8B FF                mov         edi,edi  
CopyUnwindDown:
0012B440 F7 D9                neg         ecx  
0012B442 FF 24 8D 14 B5 12 00 jmp         dword ptr [ecx*4+12B514h]  
0012B449 8D 49 00             lea         ecx,[ecx]  
CopyLeadDown:
0012B44C 8B C7                mov         eax,edi  
0012B44E BA 03 00 00 00       mov         edx,3  
0012B453 83 F9 04             cmp         ecx,4  
0012B456 72 0C                jb          TrailUpVec+9Ch (012B464h)  
0012B458 83 E0 03             and         eax,3  
0012B45B 2B C8                sub         ecx,eax  
0012B45D FF 24 85 68 B4 12 00 jmp         dword ptr [eax*4+12B468h]  
ByteCopyDown:
0012B464 FF 24 8D 64 B5 12 00 jmp         dword ptr [ecx*4+12B564h]  
0012B46B 90                   nop  
0012B46C 78 B4                js          TrailUpVec+5Ah (012B422h)  
0012B46E 12 00                adc         al,byte ptr [eax]  
0012B470 9C                   pushfd  
0012B471 B4 12                mov         ah,12h  
0012B473 00 C4                add         ah,al  
0012B475 B4 12                mov         ah,12h  
0012B477 00 8A 46 03 23 D1    add         byte ptr [edx-2EDCFCBAh],cl  
0012B47D 88 47 03             mov         byte ptr [edi+3],al  
0012B480 83 EE 01             sub         esi,1  
0012B483 C1 E9 02             shr         ecx,2  
0012B486 83 EF 01             sub         edi,1  
0012B489 83 F9 08             cmp         ecx,8  
0012B48C 72 B2                jb          TrailUpVec+78h (012B440h)  
0012B48E FD                   std  
0012B48F F3 A5                rep movs    dword ptr es:[edi],dword ptr [esi]  
0012B491 FC                   cld  
0012B492 FF 24 95 64 B5 12 00 jmp         dword ptr [edx*4+12B564h]  
0012B499 8D 49 00             lea         ecx,[ecx]  
LeadDown2:
0012B49C 8A 46 03             mov         al,byte ptr [esi+3]  
0012B49F 23 D1                and         edx,ecx  
0012B4A1 88 47 03             mov         byte ptr [edi+3],al  
0012B4A4 8A 46 02             mov         al,byte ptr [esi+2]  
0012B4A7 C1 E9 02             shr         ecx,2  
0012B4AA 88 47 02             mov         byte ptr [edi+2],al  
0012B4AD 83 EE 02             sub         esi,2  
0012B4B0 83 EF 02             sub         edi,2  
0012B4B3 83 F9 08             cmp         ecx,8  
0012B4B6 72 88                jb          TrailUpVec+78h (012B440h)  
0012B4B8 FD                   std  
0012B4B9 F3 A5                rep movs    dword ptr es:[edi],dword ptr [esi]  
0012B4BB FC                   cld  
0012B4BC FF 24 95 64 B5 12 00 jmp         dword ptr [edx*4+12B564h]  
0012B4C3 90                   nop  
LeadDown3:
0012B4C4 8A 46 03             mov         al,byte ptr [esi+3]  
0012B4C7 23 D1                and         edx,ecx  
0012B4C9 88 47 03             mov         byte ptr [edi+3],al  
0012B4CC 8A 46 02             mov         al,byte ptr [esi+2]  
0012B4CF 88 47 02             mov         byte ptr [edi+2],al  
0012B4D2 8A 46 01             mov         al,byte ptr [esi+1]  
0012B4D5 C1 E9 02             shr         ecx,2  
0012B4D8 88 47 01             mov         byte ptr [edi+1],al  
0012B4DB 83 EE 03             sub         esi,3  
0012B4DE 83 EF 03             sub         edi,3  
0012B4E1 83 F9 08             cmp         ecx,8  
0012B4E4 0F 82 56 FF FF FF    jb          TrailUpVec+78h (012B440h)  
0012B4EA FD                   std  
0012B4EB F3 A5                rep movs    dword ptr es:[edi],dword ptr [esi]  
0012B4ED FC                   cld  
0012B4EE FF 24 95 64 B5 12 00 jmp         dword ptr [edx*4+12B564h]  
0012B4F5 8D 49 00             lea         ecx,[ecx]  
0012B4F8 18 B5 12 00 20 B5    sbb         byte ptr [ebp-4ADFFFEEh],dh  
0012B4FE 12 00                adc         al,byte ptr [eax]  
0012B500 28 B5 12 00 30 B5    sub         byte ptr [ebp-4ACFFFEEh],dh  
0012B506 12 00                adc         al,byte ptr [eax]  
0012B508 38 B5 12 00 40 B5    cmp         byte ptr [ebp-4ABFFFEEh],dh  
0012B50E 12 00                adc         al,byte ptr [eax]  
0012B510 48                   dec         eax  
0012B511 B5 12                mov         ch,12h  
0012B513 00 5B B5             add         byte ptr [ebx-4Bh],bl  
0012B516 12 00                adc         al,byte ptr [eax]  
UnwindDown7:
0012B518 8B 44 8E 1C          mov         eax,dword ptr [esi+ecx*4+1Ch]  
0012B51C 89 44 8F 1C          mov         dword ptr [edi+ecx*4+1Ch],eax  
UnwindDown6:
0012B520 8B 44 8E 18          mov         eax,dword ptr [esi+ecx*4+18h]  
0012B524 89 44 8F 18          mov         dword ptr [edi+ecx*4+18h],eax  
UnwindDown5:
0012B528 8B 44 8E 14          mov         eax,dword ptr [esi+ecx*4+14h]  
0012B52C 89 44 8F 14          mov         dword ptr [edi+ecx*4+14h],eax  
UnwindDown4:
0012B530 8B 44 8E 10          mov         eax,dword ptr [esi+ecx*4+10h]  
0012B534 89 44 8F 10          mov         dword ptr [edi+ecx*4+10h],eax  
UnwindDown3:
0012B538 8B 44 8E 0C          mov         eax,dword ptr [esi+ecx*4+0Ch]  
0012B53C 89 44 8F 0C          mov         dword ptr [edi+ecx*4+0Ch],eax  
UnwindDown2:
0012B540 8B 44 8E 08          mov         eax,dword ptr [esi+ecx*4+8]  
0012B544 89 44 8F 08          mov         dword ptr [edi+ecx*4+8],eax  
UnwindDown1:
0012B548 8B 44 8E 04          mov         eax,dword ptr [esi+ecx*4+4]  
0012B54C 89 44 8F 04          mov         dword ptr [edi+ecx*4+4],eax  
0012B550 8D 04 8D 00 00 00 00 lea         eax,[ecx*4]  
0012B557 03 F0                add         esi,eax  
0012B559 03 F8                add         edi,eax  
UnwindDown0:
0012B55B FF 24 95 64 B5 12 00 jmp         dword ptr [edx*4+12B564h]  
0012B562 8B FF                mov         edi,edi  
0012B564 74 B5                je          UnwindDownVec+23h (012B51Bh)  
0012B566 12 00                adc         al,byte ptr [eax]  
0012B568 7C B5                jl          UnwindDownVec+27h (012B51Fh)  
0012B56A 12 00                adc         al,byte ptr [eax]  
0012B56C 8C B5 12 00 A0 B5    mov         word ptr [ebp-4A5FFFEEh],st(-2)  
0012B572 12 00                adc         al,byte ptr [eax]  
TrailDown0:
0012B574 8B 44 24 0C          mov         eax,dword ptr [esp+0Ch]  
0012B578 5E                   pop         esi  
0012B579 5F                   pop         edi  
0012B57A C3                   ret  
0012B57B 90                   nop  
TrailDown1:
0012B57C 8A 46 03             mov         al,byte ptr [esi+3]  
0012B57F 88 47 03             mov         byte ptr [edi+3],al  
0012B582 8B 44 24 0C          mov         eax,dword ptr [esp+0Ch]  
0012B586 5E                   pop         esi  
0012B587 5F                   pop         edi  
0012B588 C3                   ret  
0012B589 8D 49 00             lea         ecx,[ecx]  
TrailDown2:
0012B58C 8A 46 03             mov         al,byte ptr [esi+3]  
0012B58F 88 47 03             mov         byte ptr [edi+3],al  
0012B592 8A 46 02             mov         al,byte ptr [esi+2]  
0012B595 88 47 02             mov         byte ptr [edi+2],al  
0012B598 8B 44 24 0C          mov         eax,dword ptr [esp+0Ch]  
0012B59C 5E                   pop         esi  
0012B59D 5F                   pop         edi  
0012B59E C3                   ret  
0012B59F 90                   nop  
TrailDown3:
0012B5A0 8A 46 03             mov         al,byte ptr [esi+3]  
0012B5A3 88 47 03             mov         byte ptr [edi+3],al  
0012B5A6 8A 46 02             mov         al,byte ptr [esi+2]  
0012B5A9 88 47 02             mov         byte ptr [edi+2],al  
0012B5AC 8A 46 01             mov         al,byte ptr [esi+1]  
0012B5AF 88 47 01             mov         byte ptr [edi+1],al  
0012B5B2 8B 44 24 0C          mov         eax,dword ptr [esp+0Ch]  
0012B5B6 5E                   pop         esi  
0012B5B7 5F                   pop         edi  
0012B5B8 C3                   ret  
0012B5B9 8D A4 24 00 00 00 00 lea         esp,[esp]  
VEC_memcpy:
0012B5C0 57                   push        edi  
0012B5C1 8B C6                mov         eax,esi  
0012B5C3 83 E0 0F             and         eax,0Fh  
0012B5C6 85 C0                test        eax,eax  
0012B5C8 0F 85 D2 00 00 00    jne         TrailDownVec+13Ch (012B6A0h)  
L_Aligned:
0012B5CE 8B D1                mov         edx,ecx  
0012B5D0 83 E1 7F             and         ecx,7Fh  
0012B5D3 C1 EA 07             shr         edx,7  
0012B5D6 74 65                je          TrailDownVec+0D9h (012B63Dh)  
0012B5D8 8D A4 24 00 00 00 00 lea         esp,[esp]  
0012B5DF 90                   nop  
L_1:
0012B5E0 66 0F 6F 06          movdqa      xmm0,xmmword ptr [esi]  
0012B5E4 66 0F 6F 4E 10       movdqa      xmm1,xmmword ptr [esi+10h]  
0012B5E9 66 0F 6F 56 20       movdqa      xmm2,xmmword ptr [esi+20h]  
0012B5EE 66 0F 6F 5E 30       movdqa      xmm3,xmmword ptr [esi+30h]  
0012B5F3 66 0F 7F 07          movdqa      xmmword ptr [edi],xmm0  
0012B5F7 66 0F 7F 4F 10       movdqa      xmmword ptr [edi+10h],xmm1  
0012B5FC 66 0F 7F 57 20       movdqa      xmmword ptr [edi+20h],xmm2  
0012B601 66 0F 7F 5F 30       movdqa      xmmword ptr [edi+30h],xmm3  
0012B606 66 0F 6F 66 40       movdqa      xmm4,xmmword ptr [esi+40h]  
0012B60B 66 0F 6F 6E 50       movdqa      xmm5,xmmword ptr [esi+50h]  
0012B610 66 0F 6F 76 60       movdqa      xmm6,xmmword ptr [esi+60h]  
0012B615 66 0F 6F 7E 70       movdqa      xmm7,xmmword ptr [esi+70h]  
0012B61A 66 0F 7F 67 40       movdqa      xmmword ptr [edi+40h],xmm4  
0012B61F 66 0F 7F 6F 50       movdqa      xmmword ptr [edi+50h],xmm5  
0012B624 66 0F 7F 77 60       movdqa      xmmword ptr [edi+60h],xmm6  
0012B629 66 0F 7F 7F 70       movdqa      xmmword ptr [edi+70h],xmm7  
0012B62E 8D B6 80 00 00 00    lea         esi,[esi+80h]  
0012B634 8D BF 80 00 00 00    lea         edi,[edi+80h]  
0012B63A 4A                   dec         edx  
0012B63B 75 A3                jne         TrailDownVec+7Ch (012B5E0h)  
L_1a:
0012B63D 85 C9                test        ecx,ecx  
0012B63F 74 4F                je          TrailDownVec+12Ch (012B690h)  
0012B641 8B D1                mov         edx,ecx  
0012B643 C1 EA 04             shr         edx,4  
0012B646 85 D2                test        edx,edx  
0012B648 74 17                je          TrailDownVec+0FDh (012B661h)  
0012B64A 8D 9B 00 00 00 00    lea         ebx,[ebx]  
L_2:
0012B650 66 0F 6F 06          movdqa      xmm0,xmmword ptr [esi]  
0012B654 66 0F 7F 07          movdqa      xmmword ptr [edi],xmm0  
0012B658 8D 76 10             lea         esi,[esi+10h]  
0012B65B 8D 7F 10             lea         edi,[edi+10h]  
0012B65E 4A                   dec         edx  
0012B65F 75 EF                jne         TrailDownVec+0ECh (012B650h)  
L_Trailing:
0012B661 83 E1 0F             and         ecx,0Fh  
0012B664 74 2A                je          TrailDownVec+12Ch (012B690h)  
0012B666 8B C1                mov         eax,ecx  
0012B668 C1 E9 02             shr         ecx,2  
0012B66B 74 0D                je          TrailDownVec+116h (012B67Ah)  
L_TrailDword:
0012B66D 8B 16                mov         edx,dword ptr [esi]  
0012B66F 89 17                mov         dword ptr [edi],edx  
0012B671 8D 76 04             lea         esi,[esi+4]  
0012B674 8D 7F 04             lea         edi,[edi+4]  
0012B677 49                   dec         ecx  
0012B678 75 F3                jne         TrailDownVec+109h (012B66Dh)  
L_TrailBytes:
0012B67A 8B C8                mov         ecx,eax  
0012B67C 83 E1 03             and         ecx,3  
0012B67F 74 0F                je          TrailDownVec+12Ch (012B690h)  
L_TrailNextByte:
0012B681 8A 06                mov         al,byte ptr [esi]  
0012B683 88 07                mov         byte ptr [edi],al  
0012B685 46                   inc         esi  
0012B686 47                   inc         edi  
0012B687 49                   dec         ecx  
0012B688 75 F7                jne         TrailDownVec+11Dh (012B681h)  
0012B68A 8D 9B 00 00 00 00    lea         ebx,[ebx]  
L_Return:
0012B690 58                   pop         eax  
0012B691 5E                   pop         esi  
0012B692 5F                   pop         edi  
0012B693 C3                   ret  
0012B694 8D A4 24 00 00 00 00 lea         esp,[esp]  
0012B69B EB 03                jmp         TrailDownVec+13Ch (012B6A0h)  
0012B69D CC                   int         3  
0012B69E CC                   int         3  
0012B69F CC                   int         3  
L_Notaligned:
0012B6A0 BA 10 00 00 00       mov         edx,10h  
0012B6A5 2B D0                sub         edx,eax  
0012B6A7 2B CA                sub         ecx,edx  
0012B6A9 51                   push        ecx  
0012B6AA 8B C2                mov         eax,edx  
0012B6AC 8B C8                mov         ecx,eax  
0012B6AE 83 E1 03             and         ecx,3  
0012B6B1 74 09                je          TrailDownVec+158h (012B6BCh)  
L_Byte:
0012B6B3 8A 16                mov         dl,byte ptr [esi]  
0012B6B5 88 17                mov         byte ptr [edi],dl  
0012B6B7 46                   inc         esi  
0012B6B8 47                   inc         edi  
0012B6B9 49                   dec         ecx  
0012B6BA 75 F7                jne         TrailDownVec+14Fh (012B6B3h)  
L_MovDword:
0012B6BC C1 E8 02             shr         eax,2  
0012B6BF 74 0D                je          TrailDownVec+16Ah (012B6CEh)  
L_Dword:
0012B6C1 8B 16                mov         edx,dword ptr [esi]  
0012B6C3 89 17                mov         dword ptr [edi],edx  
0012B6C5 8D 76 04             lea         esi,[esi+4]  
0012B6C8 8D 7F 04             lea         edi,[edi+4]  
0012B6CB 48                   dec         eax  
0012B6CC 75 F3                jne         TrailDownVec+15Dh (012B6C1h)  
L_Adjustcnt:
0012B6CE 59                   pop         ecx  
0012B6CF E9 FA FE FF FF       jmp         TrailDownVec+6Ah (012B5CEh)  
一个memcpy竟然有700+行,这简直比想象中的长得多,没错,确实不是简简单单地一个rep movsb就复制了内存的。它为什么这样做呢?我来分析一下。
首先开头的废话先不看,这里面有这样的几行注释:

;
; Check for overlapping buffers:
;       If (dst <= src) Or (dst >= src + Count) Then
;               Do normal (Upwards) Copy
;       Else
;               Do Downwards Copy to avoid propagation
;


我给翻译一下:检查缓冲区是否有重叠:
    如果 目标在源的前面 或者 目标不在源的长度范围内 那么
        做通常的(向后的)复制
    否则
        做向前的复制来避免错误复制(复制成片段重复的内容)(虽然括号里的内容是脑补翻译。此外注意我把“向上复制”翻译为“向后复制”,“向下复制”翻译为“向前复制”,请留意)

嗯虽说C语言规范说memmove能保证缓冲区重叠也能正常复制而memcpy则行为未定义,但VS2012还是做了保守的处理。毕竟比起性能消耗(而且反正后面是有优化的,我接下来讲),少一个坑是一个坑。

接下来从CopyUp开始看:这是正常的向后复制的代码实现。

然后,它先检测“增强快速串处理”是否支持,是的话,直接rep movsb

        ; See if Enhanced Fast Strings is supported.
        ; ENFSTRG supported?

        bt      __favor, __FAVOR_ENFSTRG
        jnc     CopyUpSSE2Check                 ; no jump
        ;
        ; use Enhanced Fast Strings

        rep     movsb
        jmp     TrailUp0         ; Done

嗯也就是CPU如果没有这个功能的话,它还有其它的优化手段。可以从jnc CopyUpSSE2Check这条指令看出,它会检测CPU是否支持SSE2指令集,然后使用SSE2指令集进行加速复制。

CopyUpSSE2Check:
;
; Next, see if we can use a "fast" copy SSE2 routine
        ; block size greater than min threshold?

        cmp     ecx,080h
        jb      Dword_align  ; length too small go use dwords
        ; alignments equal?

        mov     eax,edi
        xor     eax,esi
        test    eax,15
        jne     AtomChk   ; Not aligned go check Atom
        bt      __isa_enabled, __ISA_AVAILABLE_SSE2
        jc      VEC_memcpy ; yes, go SSE2 copy (params already set)

先判断要复制的内容是否超过128字节,没有的话,因为此时再用SSE2的加速意义不大,此时它会跳到使用REP MOVSD的地方进行复制。
然后检查源地址和目标地址是不是都是16字节对齐的,如果没有对齐的话,检查CPU是不是Atom的,如果是对齐的,检查SSE2是否可用,可用的话直接跳去用SSE2的指令。

AtomChk:
        ; Is Atom supported?
        bt      __favor, __FAVOR_ATOM
        jnc     Dword_align ; no,jump

        ; check if dst is 4 byte aligned
        test    edi, 3
        jne     CopyLeadUp

        ; check if src is 4 byte aligned
        test    esi, 3
        jne     Dword_align_Ok

如果不是Atom处理器的话,直接跳到使用REP MOVSD的地方进行复制。
如果是的话,检查目标是否4字节对齐,不是的话跳到CopyLeadUp(CopyLeadUp的入口处的注释写的是“用于对未对齐的数据进行复制”)
然后再检查源是否4字节对齐,不是的话跳到使用REP MOVSD的、已经判断过目标是否对齐的那个地方继续执行。

; A software pipelining vectorized memcpy loop using PALIGN instructions

; (1) copy the first bytes to align dst up to the nearest 16-byte boundary
; 4 byte align -> 12 byte copy, 8 byte align -> 8 byte copy, 12 byte align -> 4 byte copy

PalignHead4:
        bt      edi, 2
        jae     PalignHead8
        mov     eax, dword ptr [esi]
        sub     ecx, 4
        lea     esi, byte ptr [esi+4]
        mov     dword ptr [edi], eax
        lea     edi, byte ptr [edi+4]

此处是:一个使用PALIGN指令的软件处理管线的向量化内存循环
(1)复制开头的几个字节来让目标地址对齐到最近的16字节边界
4字节对齐 -> 12字节复制;8字节对齐 -> 8字节复制;12字节对齐->4字节复制
判断目标地址是否已经是4字节对齐了,是的话进行8字节对齐。
4字节对齐,直接mov搞定。

PalignHead8:
        bt      edi, 3
        jae     PalignLoop
        movq    xmm1, qword ptr [esi]
        sub     ecx, 8
        lea     esi, byte ptr [esi+8]
        movq    qword ptr [edi], xmm1
        lea     edi, byte ptr [edi+8]

8字节对齐,判断目标地址是否已经8字节对齐了,是的话直接进入复制循环。
不是的话,拿movq指令做一次8字节复制搞定。

;(2) Use SSE palign loop
PalignLoop:
        test    esi, 7
        je      MovPalign8
        bt      esi, 3
        jae     MovPalign4

这里判断源是否8字节对齐,是的话进行8字节复制;如果源是4字节对齐的,进行4字节复制,否则进行12字节复制。

PALIGN_memcpy 12
0012B148 66 0F 6F 4E F4       movdqa      xmm1,xmmword ptr [esi-0Ch]  
0012B14D 8D 76 F4             lea         esi,[esi-0Ch]  

PalignLoop12:
0012B150 66 0F 6F 5E 10       movdqa      xmm3,xmmword ptr [esi+10h]  
0012B155 83 E9 30             sub         ecx,30h  
0012B158 66 0F 6F 46 20       movdqa      xmm0,xmmword ptr [esi+20h]  
0012B15D 66 0F 6F 6E 30       movdqa      xmm5,xmmword ptr [esi+30h]  
0012B162 8D 76 30             lea         esi,[esi+30h]  
0012B165 83 F9 30             cmp         ecx,30h  
0012B168 66 0F 6F D3          movdqa      xmm2,xmm3  
0012B16C 66 0F 3A 0F D9 0C    palignr     xmm3,xmm1,0Ch  
0012B172 66 0F 7F 1F          movdqa      xmmword ptr [edi],xmm3  
0012B176 66 0F 6F E0          movdqa      xmm4,xmm0  
0012B17A 66 0F 3A 0F C2 0C    palignr     xmm0,xmm2,0Ch  
0012B180 66 0F 7F 47 10       movdqa      xmmword ptr [edi+10h],xmm0  
0012B185 66 0F 6F CD          movdqa      xmm1,xmm5  
0012B189 66 0F 3A 0F EC 0C    palignr     xmm5,xmm4,0Ch  
0012B18F 66 0F 7F 6F 20       movdqa      xmmword ptr [edi+20h],xmm5  
0012B194 8D 7F 30             lea         edi,[edi+30h]  
0012B197 7D B7                jge         CopyUp+0A0h (012B150h)  
0012B199 8D 76 0C             lea         esi,[esi+0Ch]  

        jmp     PalignTail
0012B19C E9 AF 00 00 00       jmp         CopyUp+1A0h (012B250h)  

上面这一部分似乎没有复制方式的源码,目测masm钦定的宏干的事儿。这是12字节对齐复制。

PALIGN_memcpy 8
0012B1A1 66 0F 6F 4E F8       movdqa      xmm1,xmmword ptr [esi-8]  
0012B1A6 8D 76 F8             lea         esi,[esi-8]  
0012B1A9 8D 49 00             lea         ecx,[ecx]  

PalignLoop8:
0012B1AC 66 0F 6F 5E 10       movdqa      xmm3,xmmword ptr [esi+10h]  
0012B1B1 83 E9 30             sub         ecx,30h  
0012B1B4 66 0F 6F 46 20       movdqa      xmm0,xmmword ptr [esi+20h]  
0012B1B9 66 0F 6F 6E 30       movdqa      xmm5,xmmword ptr [esi+30h]  
0012B1BE 8D 76 30             lea         esi,[esi+30h]  
0012B1C1 83 F9 30             cmp         ecx,30h  
0012B1C4 66 0F 6F D3          movdqa      xmm2,xmm3  
0012B1C8 66 0F 3A 0F D9 08    palignr     xmm3,xmm1,8  
0012B1CE 66 0F 7F 1F          movdqa      xmmword ptr [edi],xmm3  
0012B1D2 66 0F 6F E0          movdqa      xmm4,xmm0  
0012B1D6 66 0F 3A 0F C2 08    palignr     xmm0,xmm2,8  
0012B1DC 66 0F 7F 47 10       movdqa      xmmword ptr [edi+10h],xmm0  
0012B1E1 66 0F 6F CD          movdqa      xmm1,xmm5  
0012B1E5 66 0F 3A 0F EC 08    palignr     xmm5,xmm4,8  
0012B1EB 66 0F 7F 6F 20       movdqa      xmmword ptr [edi+20h],xmm5  
0012B1F0 8D 7F 30             lea         edi,[edi+30h]  
0012B1F3 7D B7                jge         CopyUp+0FCh (012B1ACh)  
0012B1F5 8D 76 08             lea         esi,[esi+8]  

        jmp     PalignTail
0012B1F8 EB 56                jmp         CopyUp+1A0h (012B250h)  

上面这里是8字节对齐的复制。

PALIGN_memcpy 4
0012B1FA 66 0F 6F 4E FC       movdqa      xmm1,xmmword ptr [esi-4]  
0012B1FF 8D 76 FC             lea         esi,[esi-4]  
0012B202 8B FF                mov         edi,edi  

PalignLoop4:
0012B204 66 0F 6F 5E 10       movdqa      xmm3,xmmword ptr [esi+10h]  
0012B209 83 E9 30             sub         ecx,30h  
0012B20C 66 0F 6F 46 20       movdqa      xmm0,xmmword ptr [esi+20h]  
0012B211 66 0F 6F 6E 30       movdqa      xmm5,xmmword ptr [esi+30h]  
0012B216 8D 76 30             lea         esi,[esi+30h]  
0012B219 83 F9 30             cmp         ecx,30h  
0012B21C 66 0F 6F D3          movdqa      xmm2,xmm3  
0012B220 66 0F 3A 0F D9 04    palignr     xmm3,xmm1,4  
0012B226 66 0F 7F 1F          movdqa      xmmword ptr [edi],xmm3  
0012B22A 66 0F 6F E0          movdqa      xmm4,xmm0  
0012B22E 66 0F 3A 0F C2 04    palignr     xmm0,xmm2,4  
0012B234 66 0F 7F 47 10       movdqa      xmmword ptr [edi+10h],xmm0  
0012B239 66 0F 6F CD          movdqa      xmm1,xmm5  
0012B23D 66 0F 3A 0F EC 04    palignr     xmm5,xmm4,4  
0012B243 66 0F 7F 6F 20       movdqa      xmmword ptr [edi+20h],xmm5  
0012B248 8D 7F 30             lea         edi,[edi+30h]  
0012B24B 7D B7                jge         CopyUp+154h (012B204h)  
0012B24D 8D 76 04             lea         esi,[esi+4]  


上面这里是4字节对齐复制。

;(3) Copy the tailing bytes.
PalignTail:
        cmp    ecx,10h
        jl     PalignTail4
        movdqu xmm1,xmmword ptr [esi]
        sub    ecx, 10h
        lea    esi, xmmword ptr [esi+10h]
        movdqa xmmword ptr [edi],xmm1
        lea    edi, xmmword ptr [edi+10h]
        jmp    PalignTail

上面这里是复制结尾的字节。

PalignTail4:
        bt      ecx, 2
        jae     PalignTail8
        mov     eax, dword ptr [esi]
        sub     ecx,4
        lea     esi, byte ptr [esi+4]
        mov     dword ptr [edi], eax
        lea     edi, byte ptr [edi+4]

PalignTail8:
        bt      ecx, 3
        jae     PalignTailLE3
        movq    xmm1, qword ptr [esi]
        sub     ecx,8
        lea     esi, byte ptr [esi+8]
        movq    qword ptr [edi], xmm1
        lea     edi, byte ptr [edi+8]

PalignTailLE3:
        mov     eax, dword ptr TrailUpVec[ecx*4]
        jmp     eax

上面的代码,是根据对齐的方式做最后的处理。

; The algorithm for forward moves is to align the destination to a dword
; boundary and so we can move dwords with an aligned destination.  This
; occurs in 3 steps.
;
;   - move x = ((4 - Dest & 3) & 3) bytes
;   - move y = ((L-x) >> 2) dwords
;   - move (L - x - y*4) bytes
;


Dword_align:
        test    edi,11b         ;U - destination dword aligned?
        jnz     short CopyLeadUp ;V - if we are not dword aligned already, align
Dword_align_Ok:
        shr     ecx,2           ;U - shift down to dword count
        and     edx,11b         ;V - trailing byte count

        cmp     ecx,8           ;U - test if small enough for unwind copy
        jb      short CopyUnwindUp ;V - if so, then jump

        rep     movsd           ;N - move all of our dwords

        jmp     dword ptr TrailUpVec[edx*4] ;N - process trailing bytes

这里就是之前所说的使用REP MOVSD的地方进行复制。但即使是使用REP MOVSD,也要判断地址是否是对齐的,只有在对齐的状态下,才适合这样复制。不然会掉速。

;
; Code to do optimal memory copies for non-dword-aligned destinations.
;

; The following length check is done for two reasons:
;
;    1. to ensure that the actual move length is greater than any possiale
;       alignment move, and
;
;    2. to skip the multiple move logic for small moves where it would
;       be faster to move the bytes with one instruction.
;


        align   @WordSize
CopyLeadUp:

        mov     eax,edi         ;U - get destination offset
        mov     edx,11b         ;V - prepare for mask

        sub     ecx,4           ;U - check for really short string - sub for adjust
        jb      short ByteCopyUp ;V - branch to just copy bytes

        and     eax,11b         ;U - get offset within first dword
        add     ecx,eax         ;V - update size after leading bytes copied

        jmp     dword ptr LeadUpVec[eax*4-4] ;N - process leading bytes

        align   @WordSize
ByteCopyUp:
        jmp     dword ptr TrailUpVec[ecx*4+16] ;N - process just bytes

        align   @WordSize
CopyUnwindUp:
        jmp     dword ptr UnwindUpVec[ecx*4] ;N - unwind dword copy

此处的代码负责对没有进行4字节对齐的地址的数据的复制操作进行优化。后面的检测代码存在的原因有两个:
1、确保要复制的数据的长度超出任何可能的对齐长度
2、跳过多个复制逻辑让小的复制能更快一些

后面的部分没有源文件我也不分析了,不过值得留意的一个片段,我这里专门提一下:

L_1:
0012B5E0 66 0F 6F 06          movdqa      xmm0,xmmword ptr [esi]  
0012B5E4 66 0F 6F 4E 10       movdqa      xmm1,xmmword ptr [esi+10h]  
0012B5E9 66 0F 6F 56 20       movdqa      xmm2,xmmword ptr [esi+20h]  
0012B5EE 66 0F 6F 5E 30       movdqa      xmm3,xmmword ptr [esi+30h]  
0012B5F3 66 0F 7F 07          movdqa      xmmword ptr [edi],xmm0  
0012B5F7 66 0F 7F 4F 10       movdqa      xmmword ptr [edi+10h],xmm1  
0012B5FC 66 0F 7F 57 20       movdqa      xmmword ptr [edi+20h],xmm2  
0012B601 66 0F 7F 5F 30       movdqa      xmmword ptr [edi+30h],xmm3  
0012B606 66 0F 6F 66 40       movdqa      xmm4,xmmword ptr [esi+40h]  
0012B60B 66 0F 6F 6E 50       movdqa      xmm5,xmmword ptr [esi+50h]  
0012B610 66 0F 6F 76 60       movdqa      xmm6,xmmword ptr [esi+60h]  
0012B615 66 0F 6F 7E 70       movdqa      xmm7,xmmword ptr [esi+70h]  
0012B61A 66 0F 7F 67 40       movdqa      xmmword ptr [edi+40h],xmm4  
0012B61F 66 0F 7F 6F 50       movdqa      xmmword ptr [edi+50h],xmm5  
0012B624 66 0F 7F 77 60       movdqa      xmmword ptr [edi+60h],xmm6  
0012B629 66 0F 7F 7F 70       movdqa      xmmword ptr [edi+70h],xmm7  


这里面使用了8个SSE2寄存器进行复制操作,每个寄存器能存储16个字节,用这种方式进行复制的时候,这些movdqa指令其实有可能是并发执行的,尤其是你的内存是多通道的情况。此处进行数据量大的内容的复制的时候,效率应该会有很大的提升。

VS2012的memcpy函数,根据数据的量的大小对齐的情况,对每一种情况都进行了优化处理,各方面证明了它是无可替代的。不是什么时候,自己造的轮子都比别人的好。

评分

参与人数 1威望 +16 贡献 +32 收起 理由
cyycoish + 16 + 32 赞!

查看全部评分

本帖被以下淘专辑推荐:

85

主题

263

帖子

3536

积分

用户组: 管理员

No. 418

UID
418
精华
13
威望
52 点
宅币
1969 个
贡献
1135 次
宅之契约
0 份
在线时间
252 小时
注册时间
2014-8-9
发表于 2017-5-30 17:10:53 | 显示全部楼层
这个帖子简直漂亮!
这边发一个别人用C实现的malloc,当然,malloc也不是那么简单的!
ftp://gee.cs.oswego.edu/pub/misc/malloc.c
注意这个开源代码协议是public domain。
In the beginning I was not the best.
And the world was also not the best.
But I still know that I am who I am.
Because I think that it is good.
I have been working hard.
I have been keeping growth with the world.
And it was so.

25

主题

86

帖子

1157

积分

用户组: 版主

UID
1821
精华
6
威望
57 点
宅币
891 个
贡献
36 次
宅之契约
0 份
在线时间
204 小时
注册时间
2016-7-12
发表于 2017-5-30 23:30:45 | 显示全部楼层
[Asm] 纯文本查看 复制代码
       page    ,132
        title   memcpy - Copy source memory bytes to destination
;***
;memcpy.asm - contains memcpy and memmove routines
;
;       Copyright (c) Microsoft Corporation. All rights reserved.
;
;Purpose:
;       memcpy() copies a source memory buffer to a destination buffer.
;       Overlapping buffers are not treated specially, so propogation may occur.
;       memmove() copies a source memory buffer to a destination buffer.
;       Overlapping buffers are treated specially, to avoid propogation.
;
;*******************************************************************************

        .xlist
        include cruntime.inc
        .list
        .xmm

M_EXIT  macro
        ret                     ; _cdecl return
        endm    ; M_EXIT

PALIGN_memcpy macro d
MovPalign&d&:
        movdqa      xmm1,xmmword ptr [esi-d]
        lea         esi, byte ptr [esi-d]
    align   @WordSize
PalignLoop&d&:
        movdqa  xmm3,xmmword ptr [esi+10h]
        sub     ecx,30h
        movdqa  xmm0,xmmword ptr [esi+20h]
        movdqa  xmm5,xmmword ptr [esi+30h]
        lea     esi, xmmword ptr [esi+30h]
        cmp     ecx,30h
        movdqa  xmm2,xmm3

        palignr xmm3,xmm1,d

        movdqa  xmmword ptr [edi],xmm3
        movdqa  xmm4,xmm0

        palignr xmm0,xmm2,d

        movdqa  xmmword ptr [edi+10h],xmm0
        movdqa  xmm1,xmm5

        palignr xmm5,xmm4,d

        movdqa  xmmword ptr [edi+20h],xmm5
        lea     edi, xmmword ptr [edi+30h]
        jge     PalignLoop&d&
        lea     esi, xmmword ptr [esi+d]

        endm    ; PALIGN_memcpy

        CODESEG

    extrn   __isa_available:dword
    extrn   __isa_enabled:dword
    extrn   __favor:dword

page
;***
;memcpy - Copy source buffer to destination buffer
;
;Purpose:
;       memcpy() copies a source memory buffer to a destination memory buffer.
;       This routine does NOT recognize overlapping buffers, and thus can lead
;       to propogation.
;       For cases where propogation must be avoided, memmove() must be used.
;
;       Algorithm:
;
;           Same as memmove. See Below
;
;
;memmove - Copy source buffer to destination buffer
;
;Purpose:
;       memmove() copies a source memory buffer to a destination memory buffer.
;       This routine recognize overlapping buffers to avoid propogation.
;       For cases where propogation is not a problem, memcpy() can be used.
;
;   Algorithm:
;
;       void * memmove(void * dst, void * src, size_t count)
;       {
;               void * ret = dst;
;
;               if (dst <= src || dst >= (src + count)) {
;                       /*
;                        * Non-Overlapping Buffers
;                        * copy from lower addresses to higher addresses
;                        */
;                       while (count--)
;                               *dst++ = *src++;
;                       }
;               else {
;                       /*
;                        * Overlapping Buffers
;                        * copy from higher addresses to lower addresses
;                        */
;                       dst += count - 1;
;                       src += count - 1;
;
;                       while (count--)
;                               *dst-- = *src--;
;                       }
;
;               return(ret);
;       }
;
;
;Entry:
;       void *dst = pointer to destination buffer
;       const void *src = pointer to source buffer
;       size_t count = number of bytes to copy
;
;Exit:
;       Returns a pointer to the destination buffer in AX/DX:AX
;
;Uses:
;       CX, DX
;
;Exceptions:
;*******************************************************************************

ifdef MEM_MOVE
        _MEM_     equ <memmove>
else  ; MEM_MOVE
        _MEM_     equ <memcpy>
endif  ; MEM_MOVE

%       public  _MEM_
_MEM_   proc \
        dst:ptr byte, \
        src:ptr byte, \
        count:IWORD

        ; destination pointer
        ; source pointer
        ; number of bytes to copy

        OPTION PROLOGUE:NONE, EPILOGUE:NONE

        push    edi             ;U - save edi
        push    esi             ;V - save esi

;                   size param/4   prolog byte  #reg saved
        .FPO ( 0, 3           , $-_MEM_     , 2, 0, 0 )

        mov     esi,[esp + 010h]     ;U - esi = source
        mov     ecx,[esp + 014h]     ;V - ecx = number of bytes to move
        mov     edi,[esp + 0Ch]      ;U - edi = dest

;
; Check for overlapping buffers:
;       If (dst <= src) Or (dst >= src + Count) Then
;               Do normal (Upwards) Copy
;       Else
;               Do Downwards Copy to avoid propagation
;

        mov     eax,ecx         ;V - eax = byte count...

        mov     edx,ecx         ;U - edx = byte count...
        add     eax,esi         ;V - eax = point past source end

        cmp     edi,esi         ;U - dst <= src ?
        jbe     short CopyUp    ;V - yes, copy toward higher addresses

        cmp     edi,eax         ;U - dst < (src + count) ?
        jb      CopyDown        ;V - yes, copy toward lower addresses

;
; Copy toward higher addresses.
;
CopyUp:
;
        ; See if Enhanced Fast Strings is supported.
        ; ENFSTRG supported?
        bt      __favor, __FAVOR_ENFSTRG
        jnc     CopyUpSSE2Check                 ; no jump
        ;
        ; use Enhanced Fast Strings
        rep     movsb
        jmp     TrailUp0         ; Done
CopyUpSSE2Check:
;
; Next, see if we can use a "fast" copy SSE2 routine
        ; block size greater than min threshold?
        cmp     ecx,080h
        jb      Dword_align  ; length too small go use dwords
        ; alignments equal?
        mov     eax,edi
        xor     eax,esi
        test    eax,15
        jne     AtomChk   ; Not aligned go check Atom
        bt      __isa_enabled, __ISA_AVAILABLE_SSE2
        jc      VEC_memcpy ; yes, go SSE2 copy (params already set)
AtomChk:
        ; Is Atom supported?
        bt      __favor, __FAVOR_ATOM
        jnc     Dword_align ; no,jump

        ; check if dst is 4 byte aligned
        test    edi, 3
        jne     CopyLeadUp

        ; check if src is 4 byte aligned
        test    esi, 3
        jne     Dword_align_Ok

; A software pipelining vectorized memcpy loop using PALIGN instructions

; (1) copy the first bytes to align dst up to the nearest 16-byte boundary
; 4 byte align -> 12 byte copy, 8 byte align -> 8 byte copy, 12 byte align -> 4 byte copy
PalignHead4:
        bt      edi, 2
        jae     PalignHead8
        mov     eax, dword ptr [esi]
        sub     ecx, 4
        lea     esi, byte ptr [esi+4]
        mov     dword ptr [edi], eax
        lea     edi, byte ptr [edi+4]

PalignHead8:
        bt      edi, 3
        jae     PalignLoop
        movq    xmm1, qword ptr [esi]
        sub     ecx, 8
        lea     esi, byte ptr [esi+8]
        movq    qword ptr [edi], xmm1
        lea     edi, byte ptr [edi+8]

;(2) Use SSE palign loop
PalignLoop:
        test    esi, 7
        je      MovPalign8
        bt      esi, 3
        jae     MovPalign4

PALIGN_memcpy 12
        jmp     PalignTail

PALIGN_memcpy 8
        jmp     PalignTail

PALIGN_memcpy 4

;(3) Copy the tailing bytes.
PalignTail:
        cmp    ecx,10h
        jl     PalignTail4
        movdqu xmm1,xmmword ptr [esi]
        sub    ecx, 10h
        lea    esi, xmmword ptr [esi+10h]
        movdqa xmmword ptr [edi],xmm1
        lea    edi, xmmword ptr [edi+10h]
        jmp    PalignTail

PalignTail4:
        bt      ecx, 2
        jae     PalignTail8
        mov     eax, dword ptr [esi]
        sub     ecx,4
        lea     esi, byte ptr [esi+4]
        mov     dword ptr [edi], eax
        lea     edi, byte ptr [edi+4]

PalignTail8:
        bt      ecx, 3
        jae     PalignTailLE3
        movq    xmm1, qword ptr [esi]
        sub     ecx,8
        lea     esi, byte ptr [esi+8]
        movq    qword ptr [edi], xmm1
        lea     edi, byte ptr [edi+8]

PalignTailLE3:
        mov     eax, dword ptr TrailUpVec[ecx*4]
        jmp     eax

; The algorithm for forward moves is to align the destination to a dword
; boundary and so we can move dwords with an aligned destination.  This
; occurs in 3 steps.
;
;   - move x = ((4 - Dest & 3) & 3) bytes
;   - move y = ((L-x) >> 2) dwords
;   - move (L - x - y*4) bytes
;

Dword_align:
        test    edi,11b         ;U - destination dword aligned?
        jnz     short CopyLeadUp ;V - if we are not dword aligned already, align
Dword_align_Ok:
        shr     ecx,2           ;U - shift down to dword count
        and     edx,11b         ;V - trailing byte count

        cmp     ecx,8           ;U - test if small enough for unwind copy
        jb      short CopyUnwindUp ;V - if so, then jump

        rep     movsd           ;N - move all of our dwords

        jmp     dword ptr TrailUpVec[edx*4] ;N - process trailing bytes

;
; Code to do optimal memory copies for non-dword-aligned destinations.
;

; The following length check is done for two reasons:
;
;    1. to ensure that the actual move length is greater than any possiale
;       alignment move, and
;
;    2. to skip the multiple move logic for small moves where it would
;       be faster to move the bytes with one instruction.
;

        align   @WordSize
CopyLeadUp:

        mov     eax,edi         ;U - get destination offset
        mov     edx,11b         ;V - prepare for mask

        sub     ecx,4           ;U - check for really short string - sub for adjust
        jb      short ByteCopyUp ;V - branch to just copy bytes

        and     eax,11b         ;U - get offset within first dword
        add     ecx,eax         ;V - update size after leading bytes copied

        jmp     dword ptr LeadUpVec[eax*4-4] ;N - process leading bytes

        align   @WordSize
ByteCopyUp:
        jmp     dword ptr TrailUpVec[ecx*4+16] ;N - process just bytes

        align   @WordSize
CopyUnwindUp:
        jmp     dword ptr UnwindUpVec[ecx*4] ;N - unwind dword copy

        align   @WordSize
LeadUpVec       dd      LeadUp1, LeadUp2, LeadUp3

        align   @WordSize
LeadUp1:
        and     edx,ecx         ;U - trailing byte count
        mov     al,[esi]        ;V - get first byte from source

        mov     [edi],al        ;U - write second byte to destination
        mov     al,[esi+1]      ;V - get second byte from source

        mov     [edi+1],al      ;U - write second byte to destination
        mov     al,[esi+2]      ;V - get third byte from source

        shr     ecx,2           ;U - shift down to dword count
        mov     [edi+2],al      ;V - write third byte to destination

        add     esi,3           ;U - advance source pointer
        add     edi,3           ;V - advance destination pointer

        cmp     ecx,8           ;U - test if small enough for unwind copy
        jb      short CopyUnwindUp ;V - if so, then jump

        rep     movsd           ;N - move all of our dwords

        jmp     dword ptr TrailUpVec[edx*4] ;N - process trailing bytes

        align   @WordSize
LeadUp2:
        and     edx,ecx         ;U - trailing byte count
        mov     al,[esi]        ;V - get first byte from source

        mov     [edi],al        ;U - write second byte to destination
        mov     al,[esi+1]      ;V - get second byte from source

        shr     ecx,2           ;U - shift down to dword count
        mov     [edi+1],al      ;V - write second byte to destination

        add     esi,2           ;U - advance source pointer
        add     edi,2           ;V - advance destination pointer

        cmp     ecx,8           ;U - test if small enough for unwind copy
        jb      short CopyUnwindUp ;V - if so, then jump

        rep     movsd           ;N - move all of our dwords

        jmp     dword ptr TrailUpVec[edx*4] ;N - process trailing bytes

        align   @WordSize
LeadUp3:
        and     edx,ecx         ;U - trailing byte count
        mov     al,[esi]        ;V - get first byte from source

        mov     [edi],al        ;U - write second byte to destination
        add     esi,1           ;V - advance source pointer

        shr     ecx,2           ;U - shift down to dword count
        add     edi,1           ;V - advance destination pointer

        cmp     ecx,8           ;U - test if small enough for unwind copy
        jb      short CopyUnwindUp ;V - if so, then jump

        rep     movsd           ;N - move all of our dwords

        jmp     dword ptr TrailUpVec[edx*4] ;N - process trailing bytes

        align   @WordSize
UnwindUpVec     dd      UnwindUp0, UnwindUp1, UnwindUp2, UnwindUp3
                dd      UnwindUp4, UnwindUp5, UnwindUp6, UnwindUp7

UnwindUp7:
        mov     eax,[esi+ecx*4-28] ;U - get dword from source
                                   ;V - spare
        mov     [edi+ecx*4-28],eax ;U - put dword into destination
UnwindUp6:
        mov     eax,[esi+ecx*4-24] ;U(entry)/V(not) - get dword from source
                                   ;V(entry) - spare
        mov     [edi+ecx*4-24],eax ;U - put dword into destination
UnwindUp5:
        mov     eax,[esi+ecx*4-20] ;U(entry)/V(not) - get dword from source
                                   ;V(entry) - spare
        mov     [edi+ecx*4-20],eax ;U - put dword into destination
UnwindUp4:
        mov     eax,[esi+ecx*4-16] ;U(entry)/V(not) - get dword from source
                                   ;V(entry) - spare
        mov     [edi+ecx*4-16],eax ;U - put dword into destination
UnwindUp3:
        mov     eax,[esi+ecx*4-12] ;U(entry)/V(not) - get dword from source
                                   ;V(entry) - spare
        mov     [edi+ecx*4-12],eax ;U - put dword into destination
UnwindUp2:
        mov     eax,[esi+ecx*4-8] ;U(entry)/V(not) - get dword from source
                                  ;V(entry) - spare
        mov     [edi+ecx*4-8],eax ;U - put dword into destination
UnwindUp1:
        mov     eax,[esi+ecx*4-4] ;U(entry)/V(not) - get dword from source
                                  ;V(entry) - spare
        mov     [edi+ecx*4-4],eax ;U - put dword into destination

        lea     eax,[ecx*4]     ;V - compute update for pointer

        add     esi,eax         ;U - update source pointer
        add     edi,eax         ;V - update destination pointer
UnwindUp0:
        jmp     dword ptr TrailUpVec[edx*4] ;N - process trailing bytes

;-----------------------------------------------------------------------------

        align   @WordSize
TrailUpVec      dd      TrailUp0, TrailUp1, TrailUp2, TrailUp3

        align   @WordSize
TrailUp0:
        mov     eax,[esp + 0Ch] ;U - return pointer to destination
        pop     esi             ;V - restore esi
        pop     edi             ;U - restore edi
                                ;V - spare
        M_EXIT

        align   @WordSize
TrailUp1:
        mov     al,[esi]        ;U - get byte from source
                                ;V - spare
        mov     [edi],al        ;U - put byte in destination
        mov     eax,[esp + 0Ch] ;V - return pointer to destination
        pop     esi             ;U - restore esi
        pop     edi             ;V - restore edi
        M_EXIT

        align   @WordSize
TrailUp2:
        mov     al,[esi]        ;U - get first byte from source
                                ;V - spare
        mov     [edi],al        ;U - put first byte into destination
        mov     al,[esi+1]      ;V - get second byte from source
        mov     [edi+1],al      ;U - put second byte into destination
        mov     eax,[esp + 0Ch] ;V - return pointer to destination
        pop     esi             ;U - restore esi
        pop     edi             ;V - restore edi
        M_EXIT

        align   @WordSize
TrailUp3:
        mov     al,[esi]        ;U - get first byte from source
                                ;V - spare
        mov     [edi],al        ;U - put first byte into destination
        mov     al,[esi+1]      ;V - get second byte from source
        mov     [edi+1],al      ;U - put second byte into destination
        mov     al,[esi+2]      ;V - get third byte from source
        mov     [edi+2],al      ;U - put third byte into destination
        mov     eax,[esp + 0Ch] ;V - return pointer to destination
        pop     esi             ;U - restore esi
        pop     edi             ;V - restore edi
        M_EXIT

;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------

;
; Copy down to avoid propogation in overlapping buffers.
;
        align   @WordSize
CopyDown:
        lea     esi,[esi+ecx-4] ;U - point to 4 bytes before src buffer end
        lea     edi,[edi+ecx-4] ;V - point to 4 bytes before dest buffer end
;
; See if the destination start is dword aligned
;

        test    edi,11b         ;U - test if dword aligned
        jnz     short CopyLeadDown ;V - if not, jump

        shr     ecx,2           ;U - shift down to dword count
        and     edx,11b         ;V - trailing byte count

        cmp     ecx,8           ;U - test if small enough for unwind copy
        jb      short CopyUnwindDown ;V - if so, then jump

        std                     ;N - set direction flag
        rep     movsd           ;N - move all of our dwords
        cld                     ;N - clear direction flag back

        jmp     dword ptr TrailDownVec[edx*4] ;N - process trailing bytes

        align   @WordSize
CopyUnwindDown:
        neg     ecx             ;U - negate dword count for table merging
                                ;V - spare

        jmp     dword ptr UnwindDownVec[ecx*4+28] ;N - unwind copy

        align   @WordSize
CopyLeadDown:

        mov     eax,edi         ;U - get destination offset
        mov     edx,11b         ;V - prepare for mask

        cmp     ecx,4           ;U - check for really short string
        jb      short ByteCopyDown ;V - branch to just copy bytes

        and     eax,11b         ;U - get offset within first dword
        sub     ecx,eax         ;U - to update size after lead copied

        jmp     dword ptr LeadDownVec[eax*4-4] ;N - process leading bytes

        align   @WordSize
ByteCopyDown:
        jmp     dword ptr TrailDownVec[ecx*4] ;N - process just bytes

        align   @WordSize
LeadDownVec     dd      LeadDown1, LeadDown2, LeadDown3

        align   @WordSize
LeadDown1:
        mov     al,[esi+3]      ;U - load first byte
        and     edx,ecx         ;V - trailing byte count

        mov     [edi+3],al      ;U - write out first byte
        sub     esi,1           ;V - point to last src dword

        shr     ecx,2           ;U - shift down to dword count
        sub     edi,1           ;V - point to last dest dword

        cmp     ecx,8           ;U - test if small enough for unwind copy
        jb      short CopyUnwindDown ;V - if so, then jump

        std                     ;N - set direction flag
        rep     movsd           ;N - move all of our dwords
        cld                     ;N - clear direction flag

        jmp     dword ptr TrailDownVec[edx*4] ;N - process trailing bytes

        align   @WordSize
LeadDown2:
        mov     al,[esi+3]      ;U - load first byte
        and     edx,ecx         ;V - trailing byte count

        mov     [edi+3],al      ;U - write out first byte
        mov     al,[esi+2]      ;V - get second byte from source

        shr     ecx,2           ;U - shift down to dword count
        mov     [edi+2],al      ;V - write second byte to destination

        sub     esi,2           ;U - point to last src dword
        sub     edi,2           ;V - point to last dest dword

        cmp     ecx,8           ;U - test if small enough for unwind copy
        jb      short CopyUnwindDown ;V - if so, then jump

        std                     ;N - set direction flag
        rep     movsd           ;N - move all of our dwords
        cld                     ;N - clear direction flag

        jmp     dword ptr TrailDownVec[edx*4] ;N - process trailing bytes

        align   @WordSize
LeadDown3:
        mov     al,[esi+3]      ;U - load first byte
        and     edx,ecx         ;V - trailing byte count

        mov     [edi+3],al      ;U - write out first byte
        mov     al,[esi+2]      ;V - get second byte from source

        mov     [edi+2],al      ;U - write second byte to destination
        mov     al,[esi+1]      ;V - get third byte from source

        shr     ecx,2           ;U - shift down to dword count
        mov     [edi+1],al      ;V - write third byte to destination

        sub     esi,3           ;U - point to last src dword
        sub     edi,3           ;V - point to last dest dword

        cmp     ecx,8           ;U - test if small enough for unwind copy
        jb      CopyUnwindDown  ;V - if so, then jump

        std                     ;N - set direction flag
        rep     movsd           ;N - move all of our dwords
        cld                     ;N - clear direction flag

        jmp     dword ptr TrailDownVec[edx*4] ;N - process trailing bytes

;------------------------------------------------------------------

        align   @WordSize
UnwindDownVec   dd      UnwindDown7, UnwindDown6, UnwindDown5, UnwindDown4
                dd      UnwindDown3, UnwindDown2, UnwindDown1, UnwindDown0

UnwindDown7:
        mov     eax,[esi+ecx*4+28] ;U - get dword from source
                                   ;V - spare
        mov     [edi+ecx*4+28],eax ;U - put dword into destination
UnwindDown6:
        mov     eax,[esi+ecx*4+24] ;U(entry)/V(not) - get dword from source
                                   ;V(entry) - spare
        mov     [edi+ecx*4+24],eax ;U - put dword into destination
UnwindDown5:
        mov     eax,[esi+ecx*4+20] ;U(entry)/V(not) - get dword from source
                                   ;V(entry) - spare
        mov     [edi+ecx*4+20],eax ;U - put dword into destination
UnwindDown4:
        mov     eax,[esi+ecx*4+16] ;U(entry)/V(not) - get dword from source
                                   ;V(entry) - spare
        mov     [edi+ecx*4+16],eax ;U - put dword into destination
UnwindDown3:
        mov     eax,[esi+ecx*4+12] ;U(entry)/V(not) - get dword from source
                                   ;V(entry) - spare
        mov     [edi+ecx*4+12],eax ;U - put dword into destination
UnwindDown2:
        mov     eax,[esi+ecx*4+8] ;U(entry)/V(not) - get dword from source
                                   ;V(entry) - spare
        mov     [edi+ecx*4+8],eax ;U - put dword into destination
UnwindDown1:
        mov     eax,[esi+ecx*4+4] ;U(entry)/V(not) - get dword from source
                                  ;V(entry) - spare
        mov     [edi+ecx*4+4],eax ;U - put dword into destination

        lea     eax,[ecx*4]     ;V - compute update for pointer

        add     esi,eax         ;U - update source pointer
        add     edi,eax         ;V - update destination pointer
UnwindDown0:
        jmp     dword ptr TrailDownVec[edx*4] ;N - process trailing bytes

;-----------------------------------------------------------------------------

        align   @WordSize
TrailDownVec    dd      TrailDown0, TrailDown1, TrailDown2, TrailDown3

        align   @WordSize
TrailDown0:
        mov     eax,[esp + 0Ch] ;U - return pointer to destination
                                ;V - spare
        pop     esi             ;U - restore esi
        pop     edi             ;V - restore edi
        M_EXIT

        align   @WordSize
TrailDown1:
        mov     al,[esi+3]      ;U - get byte from source
                                ;V - spare
        mov     [edi+3],al      ;U - put byte in destination
        mov     eax,[esp + 0Ch] ;V - return pointer to destination
        pop     esi             ;U - restore esi
        pop     edi             ;V - restore edi
        M_EXIT

        align   @WordSize
TrailDown2:
        mov     al,[esi+3]      ;U - get first byte from source
                                ;V - spare
        mov     [edi+3],al      ;U - put first byte into destination
        mov     al,[esi+2]      ;V - get second byte from source
        mov     [edi+2],al      ;U - put second byte into destination
        mov     eax,[esp + 0Ch] ;V - return pointer to destination
        pop     esi             ;U - restore esi
        pop     edi             ;V - restore edi
        M_EXIT

        align   @WordSize
TrailDown3:
        mov     al,[esi+3]      ;U - get first byte from source
                                ;V - spare
        mov     [edi+3],al      ;U - put first byte into destination
        mov     al,[esi+2]      ;V - get second byte from source
        mov     [edi+2],al      ;U - put second byte into destination
        mov     al,[esi+1]      ;V - get third byte from source
        mov     [edi+1],al      ;U - put third byte into destination
        mov     eax,[esp + 0Ch] ;V - return pointer to destination
        pop     esi             ;U - restore esi
        pop     edi             ;V - restore edi
        M_EXIT


align       16
VEC_memcpy:
        push        edi         ; save dst for returning
        mov         eax, esi
        and         eax, 0Fh
        ; eax = src and dst alignment (src mod 16)
        test        eax, eax
        jne         L_Notaligned

        ; in:
        ;  edi = dst (16 byte aligned)
        ;  esi = src (16 byte aligned)
        ;  ecx = len is >= (128 - head alignment bytes)
        ; do block copy using SSE2 stores
L_Aligned:
        mov         edx, ecx
        and         ecx, 7Fh
        shr         edx, 7
        je          L_1a
        ; ecx = loop count
        ; edx = remaining copy length
align       16
 L_1:
        movdqa      xmm0,xmmword ptr [esi]
        movdqa      xmm1,xmmword ptr [esi + 10h]
        movdqa      xmm2,xmmword ptr [esi + 20h]
        movdqa      xmm3,xmmword ptr [esi + 30h]
        movdqa      xmmword ptr [edi],xmm0
        movdqa      xmmword ptr [edi + 10h],xmm1
        movdqa      xmmword ptr [edi + 20h],xmm2
        movdqa      xmmword ptr [edi + 30h],xmm3
        movdqa      xmm4,xmmword ptr [esi + 40h]
        movdqa      xmm5,xmmword ptr [esi + 50h]
        movdqa      xmm6,xmmword ptr [esi + 60h]
        movdqa      xmm7,xmmword ptr [esi + 70h]
        movdqa      xmmword ptr [edi + 40h],xmm4
        movdqa      xmmword ptr [edi + 50h],xmm5
        movdqa      xmmword ptr [edi + 60h],xmm6
        movdqa      xmmword ptr [edi + 70h],xmm7
        lea         esi,[esi + 80h]
        lea         edi,[edi + 80h]
        dec         edx
        jne         L_1
L_1a:
        test        ecx, ecx
        je          L_Return

        ; ecx = length (< 128 bytes)
        mov         edx, ecx
        shr         edx, 4
        test        edx, edx
        je          L_Trailing
        ; if > 16 bytes do a loop (16 bytes at a time)
        ; edx - loop count
        ; edi = dst
        ; esi = src
align 16
L_2:
        movdqa      xmm0, xmmword ptr [esi]
        movdqa      xmmword ptr [edi], xmm0
        lea         esi, [esi + 10h]
        lea         edi, [edi + 10h]
        dec         edx
        jne         L_2

L_Trailing:

        ; last 1-15 bytes: step back according to dst and src alignment and do a 16-byte copy
        ; esi = src
        ; eax = src alignment  (set at the start of the procedure and preserved up to here)
        ; edi = dst
        and         ecx, 0Fh
        ; ecx = remaining len
        je          L_Return

        ; get dword aligned
        mov     eax, ecx  ; save remaining len and calc number of dwords
        shr     ecx, 2
        je      L_TrailBytes ; if none try bytes
L_TrailDword:
        mov     edx, dword ptr [esi]
        mov     dword ptr [edi], edx
        lea     esi, [esi+4]
        lea     edi, [edi+4]
        dec     ecx
        jne     L_TrailDword
L_TrailBytes:
        mov     ecx, eax
        and     ecx, 03h
        je      L_Return ; if none return
L_TrailNextByte:
        mov     al, byte ptr [esi]
        mov     byte ptr [edi], al
        inc     esi
        inc     edi
        dec     ecx
        jne     L_TrailNextByte
align 16
L_Return:
        ; return dst
        pop     eax      ; Get destination for return
        pop     esi
        pop     edi
        M_EXIT

; dst addr is not 16 byte aligned
align 16
L_Notaligned:

; copy the first the first 1-15 bytes to align both src and dst up to the nearest 16-byte boundary:

; in
; esi = src
; edi = dst
; eax = src and dst alignment
; ecx = length

        mov     edx, 010h
        sub     edx, eax   ; calc num bytes to get it aligned
        sub     ecx, edx   ; calc new length and save it
        push    ecx
        mov     eax, edx   ; save alignment byte count for dwords
        mov     ecx, eax   ; set exc to rep count
        and     ecx, 03h
        je      L_MovDword ; if no bytes go do dwords
L_Byte:
        mov     dl, byte ptr [esi]  ; move the bytes
        mov     byte ptr [edi], dl
        inc     esi       ; inc the adrs
        inc     edi
        dec     ecx       ; dec the counter
        jne     L_Byte
L_MovDword:
        shr     eax, 2     ; get dword count
        je      L_Adjustcnt ; if none go to main loop
L_Dword:
        mov     edx, dword ptr [esi] ; move the dwords
        mov     dword ptr [edi], edx
        lea     esi, [esi+4] ; inc the adrs
        lea     edi, [edi+4]
        dec     eax          ; dec the counter
        jne     L_Dword
L_Adjustcnt:
        pop     ecx       ; retrive the adjusted length
        jmp     L_Aligned


_MEM_   endp
        end

25

主题

86

帖子

1157

积分

用户组: 版主

UID
1821
精华
6
威望
57 点
宅币
891 个
贡献
36 次
宅之契约
0 份
在线时间
204 小时
注册时间
2016-7-12
发表于 2017-5-30 23:35:16 | 显示全部楼层
本帖最后由 Ayala 于 2017-5-30 23:57 编辑

[Asm] 纯文本查看 复制代码
        page    ,132
        title   memcpy - Copy source memory bytes to destination
;***
;memcpy.asm - contains memcpy and memmove routines
;
;       Copyright (c) Microsoft Corporation. All rights reserved.
;
;Purpose:
;       memcpy() copies a source memory buffer to a destination buffer.
;       Overlapping buffers are not treated specially, so propogation may occur.
;       memmove() copies a source memory buffer to a destination buffer.
;       Overlapping buffers are treated specially, to avoid propogation.
;
;*******************************************************************************

include ksamd64.inc
        subttl  "memcpy"

;***
;memcpy - Copy source buffer to destination buffer
;
;Purpose:
;       memcpy() copies a source memory buffer to a destination memory buffer.
;       This routine does NOT recognize overlapping buffers, and thus can lead
;       to propogation.
;       For cases where propogation must be avoided, memmove() must be used.
;
;       Algorithm:
;
;       void * memcpy(void * dst, void * src, size_t count)
;       {
;               void * ret = dst;
;
;               /*
;                * copy from lower addresses to higher addresses
;                */
;               while (count--)
;                       *dst++ = *src++;
;
;               return(ret);
;       }
;
;memmove - Copy source buffer to destination buffer
;
;Purpose:
;       memmove() copies a source memory buffer to a destination memory buffer.
;       This routine recognize overlapping buffers to avoid propogation.
;       For cases where propogation is not a problem, memcpy() can be used.
;
;   Algorithm:
;
;       void * memmove(void * dst, void * src, size_t count)
;       {
;               void * ret = dst;
;
;               if (dst <= src || dst >= (src + count)) {
;                       /*
;                        * Non-Overlapping Buffers
;                        * copy from lower addresses to higher addresses
;                        */
;                       while (count--)
;                               *dst++ = *src++;
;                       }
;               else {
;                       /*
;                        * Overlapping Buffers
;                        * copy from higher addresses to lower addresses
;                        */
;                       dst += count - 1;
;                       src += count - 1;
;
;                       while (count--)
;                               *dst-- = *src--;
;                       }
;
;               return(ret);
;       }
;
;
;Entry:
;       void *dst = pointer to destination buffer
;       const void *src = pointer to source buffer
;       size_t count = number of bytes to copy
;
;Exit:
;       Returns a pointer to the destination buffer in AX/DX:AX
;
;Uses:
;       CX, DX
;
;Exceptions:
;*******************************************************************************
        extrn   __favor:dword
        extrn   __ImageBase:byte
        extrn   __memcpy_nt_iters:qword     ; defined in cpu_disp.c

__FAVOR_ENFSTRG equ 1

        public memmove

        LEAF_ENTRY_ARG3 memcpy, _TEXT, dst:ptr byte, src:ptr byte, count:dword

        OPTION PROLOGUE:NONE, EPILOGUE:NONE

        memmove = memcpy

        mov     r11, rcx                ; save destination address
        mov     r10, rdx                ; save source address
        cmp     r8, 16                  ; if 16 bytes or less
        jbe     MoveBytes16             ; go move them quick
        cmp     r8, 32                  ; check for length <= 32 (we know its > 16)
        jbe     Move17to32              ; go handle lengths 17-32 as a special case
        sub     rdx, rcx                ; compute offset to source buffer
        jae     CopyUp                  ; if above or equal, go move up
        mov     rax, r10                ; else check that src+count < dst
        add     rax, r8                 ; src + count
        cmp     rcx, rax                ; (src + count) < dst
        jl      CopyDown                ; no, buffers overlap go move downward

 CopyUp:
        cmp     r8, 128
        jbe     XmmCopySmall

        bt      __favor, __FAVOR_ENFSTRG ; check for ENFSTRG (enhanced fast strings)
        jnc     XmmCopyUp               ; If Enhanced Fast String not available, use XMM

        ; use Enhanced Fast Strings
        ; but first align the destination dst to 16 byte alignment
        mov     rax, r11                ; return original destination pointer
        mov     r11, rdi                ; save rdi in r11
        mov     rdi, rcx                ; move destination pointer to rdi
        mov     rcx, r8                 ; move length to rcx
        mov     r8, rsi                 ; save rsi in r8
        mov     rsi, r10                ; move source pointer to rsi
        rep     movsb                   ; copy source to destination buffer
        mov     rsi, r8                 ; restore rsi
        mov     rdi, r11                ; restore rdi
        ret

; Handle lengths 17-32 as a special case using XMM registers.
; This allows the regular code to assume that there will always be enough
; bytes for the "deferred" block of 16. Also any case that can be handled
; with just two stores is handled with just two stores, the regular code
; will always do 3 stores for unaligned moves that have a remainder.
; No assumptions are made here about buffer alignment or overlap.
; We load the entire string to be moved in 2 xmm registers before storing
; anything, so this works for any arrangement of overlapping buffers.
;
; dst is in rcx (can modify) and r11 (must preserve for return value)
; src is in r10 (should preserve for consistency)
; rdx is the offset from the dst to the source, so rcx + rdx is the src
; r8 is the length, and is known to be 17 <= r8 <= 32
;
; When length < 32 the first 16 bytes includes some of the last 16 bytes
; and we will store (length - 32) bytes twice. (E.g. in the worst case
; of len 17 we are storing the middle 15 bytes of the buffer twice).
; This is still much faster than doing logic and branching with 1, 2, 4
; and 8 byte conditional copies.
;
        align   16

Move17to32:
        movups  xmm0, [rdx]             ; load first 16 bytes of src
        movups  xmm1, (-16)[rdx + r8]   ; load last 16 bytes of src
        movups  [rcx], xmm0             ; store first 16 bytes of dst
        movups  (-16)[rcx + r8], xmm1   ; store last 16 bytes of dst
        mov     rax, rcx                ; set destination address
        ret

;
; Move residual bytes.
;

        align   16

MoveBytes16:
         mov    rax, rcx                ; mov destination address to rax
         lea    r9, OFFSET __ImageBase
         mov    ecx, [(IMAGEREL  MoveSmall) + r9 +r8*4]
         add    rcx, r9
         jmp    rcx

MoveSmall dd  IMAGEREL MoveSmall0
          dd  IMAGEREL MoveSmall1
          dd  IMAGEREL MoveSmall2
          dd  IMAGEREL MoveSmall3
          dd  IMAGEREL MoveSmall4
          dd  IMAGEREL MoveSmall5
          dd  IMAGEREL MoveSmall6
          dd  IMAGEREL MoveSmall7
          dd  IMAGEREL MoveSmall8
          dd  IMAGEREL MoveSmall9
          dd  IMAGEREL MoveSmall10
          dd  IMAGEREL MoveSmall11
          dd  IMAGEREL MoveSmall12
          dd  IMAGEREL MoveSmall13
          dd  IMAGEREL MoveSmall14
          dd  IMAGEREL MoveSmall15
          dd  IMAGEREL MoveSmall16

        align   16

MoveSmall0::
        ret

MoveSmall2::
        movzx   ecx, word ptr [rdx]     ; get two byte from source
        mov     [rax], cx               ; write two bytes to destination
        ret

MoveSmall8::
        mov     rcx, qword ptr [rdx]    ; get eight bytes from source
        mov     [rax], rcx              ; write eight bytes to destination
        ret

MoveSmall3::
        movzx   ecx, word ptr [rdx]     ; get two bytes from source
        movzx   r8d, byte ptr 2[rdx]    ; get last byte from source
        mov     [rax], cx               ; write two bytes to destination
        mov     2[rax], r8b             ; write last byte to destination
        ret

MoveSmall1::
        movzx   ecx, byte ptr [rdx]     ; get byte from source
        mov     [rax], cl               ; write byte to destination
        ret

MoveSmall16::
        movdqu  xmm0, xmmword ptr [rdx] ; get sixteen bytes from source
        movdqu  xmmword ptr [rax], xmm0 ; write sixteen bytes to destination
        ret

        align   16
MoveSmall11::
        mov     r8, qword ptr [rdx]     ; get eight bytes from source
        movzx   ecx, word ptr 8[rdx]    ; get two bytes from source
        movzx   r9d, byte ptr 10[rdx]   ; get last byte from source
        mov     [rax], r8               ; write eight bytes to destination
        mov     8[rax], cx              ; write two bytes to destination
        mov     10[rax], r9b            ; write last byte to destination
        mov     rcx, r11                ; set destination address
        ret

MoveSmall4::
        mov     ecx, dword ptr [rdx]    ; get four bytes from source
        mov     [rax], ecx              ; write four bytes to destination
        ret

        align   16
MoveSmall5::
        mov     ecx, dword ptr [rdx]    ; get four bytes from source
        movzx   r8d, byte ptr 4[rdx]    ; get last byte from source
        mov     [rax], ecx              ; write four bytes to destination
        mov     4[rax], r8b             ; write last byte to destination
        ret

        align   16
MoveSmall6::
        mov     ecx, dword ptr [rdx]    ; get four bytes from source
        movzx   r8d, word ptr 4[rdx]    ; get two bytes from source
        mov     [rax], ecx              ; write four bytes to destination
        mov     4[rax], r8w             ; write two bytes to destination
        ret

        align   16
MoveSmall7::
        mov     ecx, dword ptr [rdx]    ; get four bytes from source
        movzx   r8d, word ptr 4[rdx]    ; get two bytes from source
        movzx   r9d, byte ptr 6[rdx]    ; get last byte from source
        mov     [rax], ecx              ; write four bytes to destination
        mov     4[rax], r8w             ; write two bytes to destination
        mov     6[rax], r9b             ; write last byte to destination
        ret

MoveSmall13::
        mov     r8, qword ptr [rdx]     ; get eight bytes from source
        mov     ecx, dword ptr 8[rdx]   ; get four bytes from source
        movzx   r9d, byte ptr 12[rdx]   ; get last bytes from source
        mov     [rax], r8               ; write eight bytes to destination
        mov     8[rax], ecx             ; write four bytes  to destination
        mov     12[rax], r9b            ; write last byte to destination
        ret

        align   16
MoveSmall9::
        mov     r8, qword ptr [rdx]     ; get eight bytes from source
        movzx   ecx, byte ptr 8[rdx]    ; get last byte from source
        mov     [rax], r8               ; write eight bytes to destination
        mov     8[rax], cl              ; write last byte to destination
        ret

        align   16
MoveSmall10::
        mov     r8, qword ptr [rdx]     ; get eight bytes from source
        movzx   ecx, word ptr 8[rdx]    ; get two bytes from source
        mov     [rax], r8               ; write eight bytes to destination
        mov     8[rax], cx              ; write two bytes to destination
        ret

        align   16
MoveSmall12::
        mov     r8, qword ptr [rdx]     ; get eight bytes from source
        mov     ecx, dword ptr 8[rdx]   ; get four bytes from source
        mov     [rax], r8               ; write eight bytes to destination
        mov     8[rax], ecx             ; write four bytes to destination
        ret

        align   16
MoveSmall14::
        mov     r8, qword ptr [rdx]     ; get eight bytes from source
        mov     ecx, dword ptr 8[rdx]   ; get four bytes from source
        movzx   r9d, word ptr 12[rdx]   ; get two bytes from source
        mov     [rax], r8               ; write eight bytes to destination
        mov     8[rax], ecx             ; write four bytes to destination
        mov     12[rax], r9w            ; write two bytes to destination
        ret

        align   16
MoveSmall15::
        mov     r8, qword ptr [rdx]     ; get eight bytes from source
        mov     ecx, dword ptr 8[rdx]   ; get four bytes from source
        movzx   r9d, word ptr 12[rdx]   ; get two bytes from source
        movzx   r10d, byte ptr 14[rdx]  ; get last byte from source
        mov     [rax], r8               ; write eight bytes to destination
        mov     8[rax], ecx             ; write four bytes to destination
        mov     12[rax], r9w            ; write two bytes to destination
        mov     14[rax], r10b           ; write last byte to destination
        ret

;
; Memcpy up using SSE instructions.
;
; Preconditions:
;       destination in rcx (destructable) and r11 (must preserve for return value)
;       source in r10
;       length in r8, must be greater than 16
;       offset from dest to src in rdx
;       source addr > dest addr or else buffers don't overlap
;
; Aligned stores are much faster on AMD hardware, so start by moving however many
; bytes must be moved so updated dst is 16-byte aligned. We need to copy
; (16 - (dest mod 16)) bytes, but it's faster to just do an unaligned copy of 16
; bytes and then start the aligned loop as usual at ((dest - (dest mod 16)) + 16).
; This results in (dest mod 16) bytes being copied twice. This is a lot faster
; than a bunch of code to copy maybe 1 then maybe 2 then maybe 4 then maybe 8
; bytes to achieve dst alignement.
;
; We know the src address is greater than the dst, but not by how much. In the
; case where the difference is less than 16 we must be careful about the bytes
; that will be stored twice. We must do both loads before either store, or the
; second load of those bytes will get the wrong values. We handle this by
; loading the last 16 bytes that can be stored at an aligned address, but
; deferring the store of those bytes to the remainder code, so it can load the
; remainder before storing the deferred bytes. Since either or both of the two
; loops can be skipped, the preconditions needed by the remainder  code must
; also apply to the loops. These conditions are:
;  - r8 is the count remaining, not including the deferred bytes
;  - [rcx + rdx] and [rcx] as usual point to the src and dst where the number
;    number of bytes given by r8 should be copied from and to.
;  - xmm0 holds the 16 deferred bytes that need to be stored at (-16)[rcx]
;
        align   16
XmmCopyUp:
        movups  xmm0, [rcx + rdx]       ; load deferred bytes
        add     r8, rcx                 ; r8 points 1 byte past end
        add     rcx, 16                 ; update to next block.
        test    r11b, 15                ; test if destination aligned
        jz      XmmCopyLargeTest        ; go try 128-byte blocks
;
; Move alignment bytes.
;
XmmCopyAlign:
        movaps  xmm1, xmm0              ; save initial bytes in xmm1
        and     rcx, -16                ; rcx is 16 bytes past first 16-byte align point
        movups  xmm0, [rcx + rdx]       ; load aligned deferred-store bytes
        add     rcx, 16                 ; update to next block
        movups  [r11], xmm1             ; now safe to store 16 unaligned at start
;
; See if we can move any 128-byte blocks.
;
XmmCopyLargeTest:
        sub     r8, rcx                 ; r8 restored to count remaining
        mov     r9, r8                  ; copy count of bytes remaining
        shr     r9, 7                   ; compute number of 128-byte blocks
        jz      XmmCopySmallTest        ; if z jump around to 2nd loop
        movaps  (-16)[rcx], xmm0        ; going into 1st loop, ok to store deferred bytes
        cmp     r9, __memcpy_nt_iters   ; threshold defined by cpu_disp.c
        jna     short XmmCopyLargeInner ; jump into 1st loop
        jmp     XmmCopyLargeInnerNT     ; long enough so non-temporal worth it, jump into nt loop

;
; Move 128-byte blocks
;
        align   16
;
; When possible, non-mov instructions are put between a load and store
; so their execution can overlap the store.
; The jnz is likewise moved earlier to come before the last store pair.
; Pairs of loads/stores are used to overlap cache latencies.
; movups and movaps are equally fast on aligned storage, we use movaps
; to document movs that we *know* are going to be aligned, movups otherwise.
; xmm0 must be preloaded before jumping into this loop, and the last
; store must be deferred (and the bytes to store left in xmm0) for the
; following loop and/or the remainder code.
;
XmmCopyLargeOuter:
        movaps  (-32)[rcx], xmm0        ; store 7th chunk from prior iteration
        movaps  (-16)[rcx], xmm1        ; store 8th chunk from prior iteration
XmmCopyLargeInner:                      ; enter loop here with xmm0 preloaded.
        movups  xmm0, [rcx + rdx]       ; load first 16 byte chunk
        movups  xmm1, 16[rcx + rdx]     ; load 2nd 16 byte chunk
        add     rcx, 128                ; advance destination address
        movaps  (-128)[rcx], xmm0       ; store first 16 byte chunk
        movaps  (-112)[rcx], xmm1       ; store 2nd 16 byte chunk
        movups  xmm0, (-96)[rcx + rdx]  ; load 3rd chunk
        movups  xmm1, (-80)[rcx + rdx]  ; load 4th chunk
        dec     r9                      ; dec block counter (set cc for jnz)
        movaps  (-96)[rcx], xmm0        ; store 3rd chunk
        movaps  (-80)[rcx], xmm1        ; store 4th chunk
        movups  xmm0, (-64)[rcx + rdx]  ; load 5th chunk
        movups  xmm1, (-48)[rcx + rdx]  ; load 6th chunk
        movaps  (-64)[rcx], xmm0        ; store 5th chunk
        movaps  (-48)[rcx], xmm1        ; store 6th chunk
        movups  xmm0, (-32)[rcx + rdx]  ; load 7th chunk
        movups  xmm1, (-16)[rcx + rdx]  ; load 8th chunk
        jnz     XmmCopyLargeOuter       ; loop if more blocks

XmmCopyFinish:                          ; non-temporal codepath rejoins here
        movaps  (-32)[rcx], xmm0        ; store 7th chunk from final iteration
        and     r8, 127                 ; compute remaining byte count
        movaps  xmm0, xmm1              ; 8th chunk becomes deferred bytes
        jmp     XmmCopySmallTest

XmmCopySmall:
        movups  xmm0, [rcx + rdx]       ; load deferred bytes
        add     rcx, 16
        sub     r8, 16
;
; See if we have any 16-byte blocks left to move
;
XmmCopySmallTest:
        mov     r9, r8                  ; copy count of bytes remaining
        shr     r9, 4                   ; compute number of 16-byte blocks
        jz      short XmmCopyTrail      ; on z, no 16-byte blocks, skip 2nd loop

        align   16

XmmCopySmallLoop:
        movups  (-16)[rcx], xmm0        ; the first time through this is the
                                        ; store of the deferred bytes from above
        movups  xmm0, [rcx + rdx]       ; load a block
        add     rcx, 16                 ; advance dest addr (store is deferred)
        dec     r9
        jnz     XmmCopySmallLoop

XmmCopyTrail:
        and     r8, 15                  ; compute remaining byte count
        jz      short XmmCopyReturn     ; if z, no remainder bytes to move
;
; Handle remainder bytes.
;
; As at the start, we are going to do an unaligned copy of 16 bytes which will double-write
; some bytes.  We must not touch rcx or xmm0 because they have what we need to store the
; deferred block. We use rax to point to the first byte after the end of the buffer and
; back up from there. Note rax is pointing to an address we must not read or write!
;
        lea     rax, [rcx+r8]           ; make rax point one past the end
        movups  xmm1, (-16)[rax + rdx]  ; load last 16 bytes of source buffer
        movups  (-16)[rax], xmm1        ; write last 16 bytes, including 16-r8 bytes
                                        ; from the last aligned block which we are about to
                                        ; overstore with identical values
XmmCopyReturn:
        movups  (-16)[rcx], xmm0        ; store the last deferred aligned block
        mov     rax, r11                ; we must return the original destination address
        ret                             ;

;
; Move 128-byte blocks non-temporal
;
        align   16
;
; non-temporal is exactly the same as the regular xmm loop above, except the movaps
; stores are movntps and we use prefetchnta. We are prefetching in two places, each
; prefetch gets 64 bytes about half an iteration ahead of time (about 10 instructions
; lead time). When we come to the end of the memcpy, we'll be prefetching bytes
; beyond the buffer we need to copy from, which may not be valid bytes. This is
; not illegal; if the memory address is invalid it does not trap, the hardware treats
; illegal prefetches as nops.
;

XmmCopyLargeOuterNT:
        movntps (-32)[rcx], xmm0        ; store 7th chunk from prior iteration
        movntps (-16)[rcx], xmm1        ; store 8th chunk from prior iteration
XmmCopyLargeInnerNT:                    ; enter loop here with xmm0 preloaded.
        prefetchnta [rcx + rdx + 512]   ; prefetch several cache lines ahead
        movups  xmm0, [rcx + rdx]       ; load first 16 byte chunk
        movups  xmm1, 16[rcx + rdx]     ; load 2nd 16 byte chunk
        add     rcx, 128                ; advance destination address
        movntps (-128)[rcx], xmm0       ; store first 16 byte chunk
        movntps (-112)[rcx], xmm1       ; store 2nd 16 byte chunk
        movups  xmm0, (-96)[rcx + rdx]  ; load 3rd chunk
        movups  xmm1, (-80)[rcx + rdx]  ; load 4th chunk
        dec     r9                      ; dec block counter (set cc for jnz)
        movntps (-96)[rcx], xmm0        ; store 3rd chunk
        movntps (-80)[rcx], xmm1        ; store 4th chunk
        movups  xmm0, (-64)[rcx + rdx]  ; load 5th chunk
        movups  xmm1, (-48)[rcx + rdx]  ; load 6th chunk
        prefetchnta [rcx + rdx + 576]   ; prefetch several cache lines ahead
        movntps (-64)[rcx], xmm0        ; store 5th chunk
        movntps (-48)[rcx], xmm1        ; store 6th chunk
        movups  xmm0, (-32)[rcx + rdx]  ; load 7th chunk
        movups  xmm1, (-16)[rcx + rdx]  ; load 8th chunk
        jnz     XmmCopyLargeOuterNT     ; loop if more blocks

        sfence
        jmp     XmmCopyFinish           ; rejoin regular memcpy codepath

;
; The source address is less than the destination address.
;

        align   16
;
; Move bytes down using SSE registers. The source address is less than
; the destination address and the buffers overlap. We will do everything back-to-front.
;
; Preconditions:
;       destination is r11 (must preserve for return value) and rcx
;       source in r10 (must preserve for remainder move)
;       length in r8, must have been verified to be greater than 16
;       offset from dest to src in rdx
;       source addr < dest addr and the buffers overlap
;
CopyDown:
        add     rcx, r8                 ; make rcx point one past the end of the dst buffer
        movups  xmm0, -16[rcx + rdx]    ; load deferred bytes
        sub     rcx, 16                 ; reduce dst addr
        sub     r8, 16                  ; r8 -= 16 in case aligned

;
; Aligned stores using movaps or movups are faster on AMD hardware than unaligned
; stores using movups. To achieve 16-byte dest alignment, we do an unaligned move
; of the last 16 bytes of the buffers, then reduce rcx only by the amount necessary
; to achieve alignment. This results in some bytes getting copied twice, unless we're
; already aligned.
;
; We know the src address is less than the dst, but not by exactly how much. In the
; case where the difference is less than 16 we must be careful about the bytes
; that will be stored twice. We must do both loads before either store, or the
; second load of those bytes will get the wrong values. We handle this by
; deferring the store of 16 aligned bytes to the remainder code, so it can load the
; remainder before storing the deferred bytes. Since either or both of the two
; loops can be skipped, the preconditions needed by the remainder  code must
; also apply to the loops. These conditions are:
;  - r8 is the count remaining, not including the deferred bytes
;  - [rcx] points one past the end of the remainder bytes
;  - rdx is the offset from the dst to the source
;  - xmm0 holds the 16 deferred bytes that need to be stored at [rcx]
;
        test    cl, 15                  ; test if dest aligned
        jz      XmmMovLargeTest         ; go try 128-byte blocks
;
; Move alignment bytes.
;
XmmMovAlign:
        mov     rax, rcx                ; save unaligned store address
        and     rcx, -16                ; rcx is deferred store address
        movups  xmm1, xmm0              ; copy unaligned last bytes to xmm1
        movups  xmm0, [rcx + rdx]       ; load deferred-store bytes
        movups  [rax], xmm1             ; now safe to do unaligned store
        mov     r8, rcx                 ; easier to recalc r8 using rcx-r11 ...
        sub     r8, r11                 ; ... than calc how much to subtract from r8

;
; See if we can move any 128-byte blocks.
;
XmmMovLargeTest:
        mov     r9, r8                  ; copy count of bytes remaining
        shr     r9, 7                   ; compute number of 128-byte blocks
        jz      short XmmMovSmallTest   ; if z jump around to 2nd loop
        movaps  [rcx], xmm0             ; going into 1st loop, ok to store deferred bytes
        jmp     short XmmMovLargeInner  ; jump into 1st loop
;
; Move 128-byte blocks
;
        align   16

XmmMovLargeOuter:
        movaps  (128-112)[rcx], xmm0    ; store 7th chunk from prior iteration
        movaps  (128-128)[rcx], xmm1    ; store 8th chunk from prior iteration
XmmMovLargeInner:
        movups  xmm0, (-16)[rcx + rdx]      ; load first 16 byte chunk
        movups  xmm1, (-32)[rcx + rdx]      ; load 2nd 16 byte chunk
        sub     rcx, 128                    ; reduce destination address
        movaps  (128-16)[rcx], xmm0         ; store first 16 byte chunk
        movaps  (128-32)[rcx], xmm1         ; store 2nd 16 byte chunk
        movups  xmm0, (128-48)[rcx + rdx]   ; load 3rd chunk
        movups  xmm1, (128-64)[rcx + rdx]   ; load 4th chunk
        dec     r9                          ; dec block counter (set cc for jnz)
        movaps  (128-48)[rcx], xmm0         ; store 3rd chunk
        movaps  (128-64)[rcx], xmm1         ; store 4th chunk
        movups  xmm0, (128-80)[rcx + rdx]   ; load 5th chunk
        movups  xmm1, (128-96)[rcx + rdx]   ; load 6th chunk
        movaps  (128-80)[rcx], xmm0         ; store 5th chunk
        movaps  (128-96)[rcx], xmm1         ; store 6th chunk
        movups  xmm0, (128-112)[rcx + rdx]  ; load 7th chunk
        movups  xmm1, (128-128)[rcx + rdx]  ; load 8th chunk
        jnz     short XmmMovLargeOuter      ; loop if more blocks

        movaps  (128-112)[rcx], xmm0    ; store 7th chunk from final iteration
        and     r8, 127                 ; compute remaining byte count
        movaps  xmm0, xmm1              ; 8th chunk becomes deferred bytes
;
; See if we have any 16-byte blocks left to move
;
XmmMovSmallTest:
        mov     r9, r8                  ; copy count of bytes remaining
        shr     r9, 4                   ; compute number of 16-byte blocks
        jz      short XmmMovTrailing    ; if z, no 16-byte blocks

        align   16

XmmMovSmallLoop:
        movups  [rcx], xmm0             ; the first time through this is the
                                        ; store of the deferred bytes from above
        sub     rcx, 16                 ; reduce dest addr
        movups  xmm0, [rcx + rdx]       ; load a block
        dec     r9
        jnz     XmmMovSmallLoop

XmmMovTrailing:
        and     r8, 15                  ; compute remaining byte count
        jz      short XmmMovReturn      ; if z, no residual bytes to move

;
; Handle remainder bytes.
;
; As at the start, we are going to do an unaligned copy of 16 bytes which will double-write
; some bytes.  We must not touch rcx or xmm0 because they have what we need to store the
; deferred block. But unlike for mcpyxmm code above, we have r10 and r11 we can just use
; to copy the lowest 16 bytes.
;
        movups  xmm1, [r10]             ; load lowest 16 bytes, which includes remainder
        movups  [r11], xmm1             ; store lowest 16 bytes, which includes remainder

XmmMovReturn:
        movups  [rcx], xmm0             ; store deferred bytes
        mov     rax, r11                ; we must return destination address
        ret

        LEAF_END memcpy, _TEXT

        end

25

主题

86

帖子

1157

积分

用户组: 版主

UID
1821
精华
6
威望
57 点
宅币
891 个
贡献
36 次
宅之契约
0 份
在线时间
204 小时
注册时间
2016-7-12
发表于 2017-5-30 23:36:28 | 显示全部楼层
[C] 纯文本查看 复制代码
/***
*memcpy.c - contains memcpy routine
*
*       Copyright (c) Microsoft Corporation. All rights reserved.
*
*Purpose:
*       memcpy() copies a source memory buffer to a destination buffer.
*       Overlapping buffers are not treated specially, so propogation may occur.
*
*******************************************************************************/

#include <cruntime.h>
#include <string.h>

#pragma function(memcpy)

/***
*memcpy - Copy source buffer to destination buffer
*
*Purpose:
*       memcpy() copies a source memory buffer to a destination memory buffer.
*       This routine does NOT recognize overlapping buffers, and thus can lead
*       to propogation.
*
*       For cases where propogation must be avoided, memmove() must be used.
*
*Entry:
*       void *dst = pointer to destination buffer
*       const void *src = pointer to source buffer
*       size_t count = number of bytes to copy
*
*Exit:
*       Returns a pointer to the destination buffer
*
*Exceptions:
*******************************************************************************/

void * __cdecl memcpy (
        void * dst,
        const void * src,
        size_t count
        )
{
        void * ret = dst;

        /*
         * copy from lower addresses to higher addresses
         */
        while (count--) {
                *(char *)dst = *(char *)src;
                dst = (char *)dst + 1;
                src = (char *)src + 1;
        }

        return(ret);
}

1008

主题

2235

帖子

5万

积分

用户组: 管理员

一只技术宅

UID
1
精华
200
威望
265 点
宅币
16762 个
贡献
33386 次
宅之契约
0 份
在线时间
1598 小时
注册时间
2014-1-26
 楼主| 发表于 2017-6-13 03:00:07 | 显示全部楼层
其实在远古时代,DOS的年代,有人玩内存到内存DMA呢,不过据说都不是很成功。

26

主题

68

帖子

1943

积分

用户组: 管理员

UID
1043
精华
10
威望
43 点
宅币
1656 个
贡献
83 次
宅之契约
0 份
在线时间
288 小时
注册时间
2015-8-15
发表于 2018-7-27 10:05:42 | 显示全部楼层
不判断内存重叠的话还不如用这货:
https://docs.microsoft.com/en-us ... hta9830(v%3dvs.100)
flowers for Broken spirits - a woman turned into stake will hold the world in the basin of fire.

1008

主题

2235

帖子

5万

积分

用户组: 管理员

一只技术宅

UID
1
精华
200
威望
265 点
宅币
16762 个
贡献
33386 次
宅之契约
0 份
在线时间
1598 小时
注册时间
2014-1-26
 楼主| 发表于 2018-7-27 22:35:03 | 显示全部楼层
tangptr@126.com 发表于 2018-7-27 10:05
不判断内存重叠的话还不如用这货:
https://docs.microsoft.com/en-us/previous-versions/visualstudio/vis ...

然而非atom架构的机器上这货烂得一匹

26

主题

68

帖子

1943

积分

用户组: 管理员

UID
1043
精华
10
威望
43 点
宅币
1656 个
贡献
83 次
宅之契约
0 份
在线时间
288 小时
注册时间
2015-8-15
发表于 2018-7-28 00:12:09 | 显示全部楼层
0xAA55 发表于 2018-7-27 22:35
然而非atom架构的机器上这货烂得一匹

[Asm] 纯文本查看 复制代码
mov_char:
        ... ...
        mov edi, [ebp + 0x08]
        mov esi, [ebp + 0x0c]
        mov ecx, [ebp + 0x10]
        rep movsb
        ... ...
        ret

总比
[Asm] 纯文本查看 复制代码
move_char:
    push ebp
    mov ebp, esp 
    sub esp, 0x0c 
    mov eax, [ebp+8] 
    mov edi, eax 
    mov esi, [ebp+0x0c] 
    mov ecx, dword ptr [ebp+0x10]

move_loop:
    mov bl, byte ptr [esi] 
    mov byte ptr [edi], bl 
    inc esi 
    inc edi 
    dec ecx 
    jnz move_loop 
    
    mov esp, ebp 
    pop ebp 
    ret

要好。
flowers for Broken spirits - a woman turned into stake will hold the world in the basin of fire.

4

主题

20

帖子

50

积分

用户组: 小·技术宅

UID
4127
精华
0
威望
0 点
宅币
30 个
贡献
0 次
宅之契约
0 份
在线时间
1 小时
注册时间
2018-8-6
发表于 2018-8-6 09:21:22 | 显示全部楼层
emm这一堆代码真的长以后潜伏在这个论坛了

11

主题

100

帖子

742

积分

用户组: 大·技术宅

UID
3808
精华
1
威望
16 点
宅币
561 个
贡献
44 次
宅之契约
0 份
在线时间
95 小时
注册时间
2018-5-6
发表于 2018-9-1 10:50:09 | 显示全部楼层
小弟目前还在学一些简单的汇编,有些指令看得懂,有些指令看不懂(大部分),但是无疑发现memcpy有700多行的asm程序是多么兴奋的事情。
菜鸟一枚,直接指正,不必留情

本版积分规则

QQ|申请友链|Archiver|手机版|小黑屋|技术宅的结界 ( 滇ICP备16008837号|网站地图

GMT+8, 2018-11-21 16:42 , Processed in 0.127405 second(s), 19 queries , Gzip On, Memcache On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表