鱼C论坛

 找回密码
 立即注册
查看: 2575|回复: 4

[已解决]一个选择题

[复制链接]
发表于 2019-4-3 18:54:38 | 显示全部楼层 |阅读模式
5鱼币
数组data最终的数据是哪个()。
  1. #define MAX_DATA_SIZE (10)

  2. int main()
  3. {
  4.         unsigned int i = 0;
  5.         unsigned char data[MAX_DATA_SIZE] = { '1','2','3','4','5','6','7','8','9','0' };
  6.         memcpy(&data[2], data, MAX_DATA_SIZE / 2);

  7.         return 0;
  8. }
复制代码


1234567890

1212121890

1212345890

其他结果都不对
KEY:C???

不应该是B、1212121890吗??
拷贝过来data里的数据就应该变了呀??
最佳答案
2019-4-3 18:54:39
我们以1212345890为例,具体看一看memcpy内部是怎么做的(在vs2017中)

通过分析memcpy的源代码,我发现vs是先复制后4个字节,然后再复制最前面那1个字节

先把[1] [2] [3] [4] 复制到[3] [4] [5] [6] (一次性复制4个字节)
最后把[0]复制到[2]

如果你有能力研究memcpy的源代码,那么请看下面的memcpy源代码,如果没有能力研究,那么目前你只是记住“不同的编译器有不同的方法,甚至同一个编译器的不同编译选项都有不同的结果”就行了,等你有了这个能力以后,自己去看源代码
  1.        page    ,132
  2.         title   memcpy - Copy source memory bytes to destination
  3. ;***
  4. ;memcpy.asm - contains memcpy and memmove routines
  5. ;
  6. ;       Copyright (c) Microsoft Corporation. All rights reserved.
  7. ;
  8. ;Purpose:
  9. ;       memcpy() copies a source memory buffer to a destination buffer.
  10. ;       Overlapping buffers are not treated specially, so propogation may occur.
  11. ;       memmove() copies a source memory buffer to a destination buffer.
  12. ;       Overlapping buffers are treated specially, to avoid propogation.
  13. ;
  14. ;*******************************************************************************

  15.         .xlist
  16.         include vcruntime.inc
  17.         .list
  18.         .xmm

  19. M_EXIT  macro
  20.         ret                     ; _cdecl return
  21.         endm    ; M_EXIT

  22. PALIGN_memcpy macro d
  23. MovPalign&d&:
  24.         movdqa  xmm1,xmmword ptr [esi-d]
  25.         lea     esi, byte ptr [esi-d]

  26.         align   @WordSize

  27. PalignLoop&d&:
  28.         movdqa  xmm3,xmmword ptr [esi+10h]
  29.         sub     ecx,30h
  30.         movdqa  xmm0,xmmword ptr [esi+20h]
  31.         movdqa  xmm5,xmmword ptr [esi+30h]
  32.         lea     esi, xmmword ptr [esi+30h]
  33.         cmp     ecx,30h
  34.         movdqa  xmm2,xmm3

  35.         palignr xmm3,xmm1,d

  36.         movdqa  xmmword ptr [edi],xmm3
  37.         movdqa  xmm4,xmm0

  38.         palignr xmm0,xmm2,d

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

  41.         palignr xmm5,xmm4,d

  42.         movdqa  xmmword ptr [edi+20h],xmm5
  43.         lea     edi, xmmword ptr [edi+30h]
  44.         jae     PalignLoop&d&
  45.         lea     esi, xmmword ptr [esi+d]

  46.         endm    ; PALIGN_memcpy

  47.         CODESEG

  48.     extrn   __isa_available:dword
  49.     extrn   __isa_enabled:dword
  50.     extrn   __favor:dword

  51. page
  52. ;***
  53. ;memcpy - Copy source buffer to destination buffer
  54. ;
  55. ;Purpose:
  56. ;       memcpy() copies a source memory buffer to a destination memory buffer.
  57. ;       This routine does NOT recognize overlapping buffers, and thus can lead
  58. ;       to propogation.
  59. ;       For cases where propogation must be avoided, memmove() must be used.
  60. ;
  61. ;       Algorithm:
  62. ;
  63. ;           Same as memmove. See Below
  64. ;
  65. ;
  66. ;memmove - Copy source buffer to destination buffer
  67. ;
  68. ;Purpose:
  69. ;       memmove() copies a source memory buffer to a destination memory buffer.
  70. ;       This routine recognize overlapping buffers to avoid propogation.
  71. ;       For cases where propogation is not a problem, memcpy() can be used.
  72. ;
  73. ;   Algorithm:
  74. ;
  75. ;       void * memmove(void * dst, void * src, size_t count)
  76. ;       {
  77. ;               void * ret = dst;
  78. ;
  79. ;               if (dst <= src || dst >= (src + count)) {
  80. ;                       /*
  81. ;                        * Non-Overlapping Buffers
  82. ;                        * copy from lower addresses to higher addresses
  83. ;                        */
  84. ;                       while (count--)
  85. ;                               *dst++ = *src++;
  86. ;                       }
  87. ;               else {
  88. ;                       /*
  89. ;                        * Overlapping Buffers
  90. ;                        * copy from higher addresses to lower addresses
  91. ;                        */
  92. ;                       dst += count - 1;
  93. ;                       src += count - 1;
  94. ;
  95. ;                       while (count--)
  96. ;                               *dst-- = *src--;
  97. ;                       }
  98. ;
  99. ;               return(ret);
  100. ;       }
  101. ;
  102. ;
  103. ;Entry:
  104. ;       void *dst = pointer to destination buffer
  105. ;       const void *src = pointer to source buffer
  106. ;       size_t count = number of bytes to copy
  107. ;
  108. ;Exit:
  109. ;       Returns a pointer to the destination buffer in AX/DX:AX
  110. ;
  111. ;Uses:
  112. ;       CX, DX
  113. ;
  114. ;Exceptions:
  115. ;*******************************************************************************

  116. ifdef MEM_MOVE
  117.         _MEM_     equ <memmove>
  118. else  ; MEM_MOVE
  119.         _MEM_     equ <memcpy>
  120. endif  ; MEM_MOVE

  121. %       public  _MEM_
  122. _MEM_   proc \
  123.         dst:ptr byte, \
  124.         src:ptr byte, \
  125.         count:IWORD

  126.         ; destination pointer
  127.         ; source pointer
  128.         ; number of bytes to copy

  129.         OPTION PROLOGUE:NONE, EPILOGUE:NONE

  130.         push    edi                             ; save edi
  131.         push    esi                             ; save esi

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

  134.         mov     esi,[esp + 010h]                ; esi = source
  135.         mov     ecx,[esp + 014h]                ; ecx = number of bytes to move
  136.         mov     edi,[esp + 0Ch]                 ; edi = dest

  137. ;
  138. ; Check for overlapping buffers:
  139. ;       If (dst <= src) Or (dst >= src + Count) Then
  140. ;               Do normal (Upwards) Copy
  141. ;       Else
  142. ;               Do Downwards Copy to avoid propagation
  143. ;

  144.         mov     eax,ecx                         ; eax = byte count

  145.         mov     edx,ecx                         ; edx = byte count
  146.         add     eax,esi                         ; eax = point past source end

  147.         cmp     edi,esi                         ; dst <= src ?
  148.         jbe     short CopyUp                    ; no overlap: copy toward higher addresses

  149.         cmp     edi,eax                         ; dst < (src + count) ?
  150.         jb      CopyDown                        ; overlap: copy toward lower addresses

  151. ;
  152. ; Buffers do not overlap, copy toward higher addresses.
  153. ;
  154. CopyUp:
  155.         cmp     ecx, 020h
  156.         jb      CopyUpDwordMov                  ; size smaller than 32 bytes, use dwords
  157.         cmp     ecx, 080h
  158.         jae     CopyUpLargeMov                  ; if greater than or equal to 128 bytes, use Enhanced fast Strings
  159.         bt      __isa_enabled, __ISA_AVAILABLE_SSE2
  160.         jc      XmmCopySmallTest
  161.         jmp     Dword_align

  162. CopyUpLargeMov:
  163.         bt      __favor, __FAVOR_ENFSTRG        ; check if Enhanced Fast Strings is supported
  164.         jnc     CopyUpSSE2Check                 ; if not, check for SSE2 support
  165.         rep     movsb
  166.         mov     eax,[esp + 0Ch]                 ; return original destination pointer
  167.         pop     esi
  168.         pop     edi
  169.         M_EXIT

  170. ;
  171. ;      Check if source and destination are equally aligned.
  172. ;
  173. CopyUpSSE2Check:
  174.         mov     eax,edi
  175.         xor     eax,esi
  176.         test    eax,15
  177.         jne     AtomChk   ; Not aligned go check Atom
  178.         bt      __isa_enabled, __ISA_AVAILABLE_SSE2
  179.         jc      XmmCopy ; yes, go SSE2 copy (params already set)
  180. AtomChk:
  181.         ; Is Atom supported?
  182.         bt      __favor, __FAVOR_ATOM
  183.         jnc     Dword_align ; no,jump

  184.         ; check if dst is 4 byte aligned
  185.         test    edi, 3
  186.         jne     Dword_align

  187.         ; check if src is 4 byte aligned
  188.         test    esi, 3
  189.         jne     Dword_align_Ok

  190. ; A software pipelining vectorized memcpy loop using PALIGN instructions

  191. ; (1) copy the first bytes to align dst up to the nearest 16-byte boundary
  192. ; 4 byte align -> 12 byte copy, 8 byte align -> 8 byte copy, 12 byte align -> 4 byte copy
  193. PalignHead4:
  194.         bt      edi, 2
  195.         jae     PalignHead8
  196.         mov     eax, dword ptr [esi]
  197.         sub     ecx, 4
  198.         lea     esi, byte ptr [esi+4]
  199.         mov     dword ptr [edi], eax
  200.         lea     edi, byte ptr [edi+4]

  201. PalignHead8:
  202.         bt      edi, 3
  203.         jae     PalignLoop
  204.         movq    xmm1, qword ptr [esi]
  205.         sub     ecx, 8
  206.         lea     esi, byte ptr [esi+8]
  207.         movq    qword ptr [edi], xmm1
  208.         lea     edi, byte ptr [edi+8]

  209. ;(2) Use SSE palign loop
  210. PalignLoop:
  211.         test    esi, 7
  212.         je      MovPalign8
  213.         bt      esi, 3
  214.         jae     MovPalign4

  215. PALIGN_memcpy 12
  216.         jmp     PalignTail

  217. PALIGN_memcpy 8
  218.         jmp     PalignTail

  219. PALIGN_memcpy 4

  220. ;(3) Copy the tailing bytes.
  221. PalignTail:
  222.         cmp    ecx,10h
  223.         jb     PalignTail4
  224.         movdqu xmm1,xmmword ptr [esi]
  225.         sub    ecx, 10h
  226.         lea    esi, xmmword ptr [esi+10h]
  227.         movdqa xmmword ptr [edi],xmm1
  228.         lea    edi, xmmword ptr [edi+10h]
  229.         jmp    PalignTail

  230. PalignTail4:
  231.         bt      ecx, 2
  232.         jae     PalignTail8
  233.         mov     eax, dword ptr [esi]
  234.         sub     ecx,4
  235.         lea     esi, byte ptr [esi+4]
  236.         mov     dword ptr [edi], eax
  237.         lea     edi, byte ptr [edi+4]

  238. PalignTail8:
  239.         bt      ecx, 3
  240.         jae     PalignTailLE3
  241.         movq    xmm1, qword ptr [esi]
  242.         sub     ecx,8
  243.         lea     esi, byte ptr [esi+8]
  244.         movq    qword ptr [edi], xmm1
  245.         lea     edi, byte ptr [edi+8]

  246. PalignTailLE3:
  247.         mov     eax, dword ptr TrailingUpVec[ecx*4]
  248.         jmp     eax

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

  257. Dword_align:
  258.         test   edi,11b                          ; check if destination is dword aligned
  259.         jz     short Dword_align_Ok             ; if destination not dword aligned already, it should be aligned

  260. Dword_up_align_loop:
  261.         mov     al, byte ptr [esi]
  262.         mov     byte ptr [edi], al
  263.         dec     ecx
  264.         add     esi, 1
  265.         add     edi, 1
  266.         test    edi, 11b
  267.         jnz     Dword_up_align_loop
  268. Dword_align_Ok:
  269.         mov     edx, ecx
  270.         cmp     ecx, 32
  271.         jb      CopyUpDwordMov
  272.         shr     ecx,2
  273.         rep     movsd                           ; move all of our dwords
  274.         and     edx,11b                         ; trailing byte count
  275.         jmp     dword ptr TrailingUpVec[edx*4]  ; process trailing bytes

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

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


  287.         align   @WordSize
  288. ByteCopyUp:
  289.         jmp     dword ptr TrailingUpVec[ecx*4+16]  ; process just bytes


  290. ;-----------------------------------------------------------------------------

  291.         align   @WordSize
  292. TrailingUpVec      dd      TrailingUp0, TrailingUp1, TrailingUp2, TrailingUp3

  293.         align   @WordSize
  294. TrailingUp0:
  295.         mov     eax,[esp + 0Ch]                 ; return original destination pointer
  296.         pop     esi                             ; restore esi
  297.         pop     edi                             ; restore edi
  298.                                                 ; spare
  299.         M_EXIT

  300.         align   @WordSize
  301. TrailingUp1:
  302.         mov     al,[esi]                        ; get byte from source
  303.                                                 ; spare
  304.         mov     [edi],al                        ; put byte in destination
  305.         mov     eax,[esp + 0Ch]                 ; return original destination pointer
  306.         pop     esi                             ; restore esi
  307.         pop     edi                             ; restore edi
  308.         M_EXIT

  309.         align   @WordSize
  310. TrailingUp2:
  311.         mov     al,[esi]                        ; get first byte from source
  312.                                                 ; spare
  313.         mov     [edi],al                        ; put first byte into destination
  314.         mov     al,[esi+1]                      ; get second byte from source
  315.         mov     [edi+1],al                      ; put second byte into destination
  316.         mov     eax,[esp + 0Ch]                 ; return original destination pointer
  317.         pop     esi                             ; restore esi
  318.         pop     edi                             ; restore edi
  319.         M_EXIT

  320.         align   @WordSize
  321. TrailingUp3:
  322.         mov     al,[esi]                        ; get first byte from source
  323.                                                 ; spare
  324.         mov     [edi],al                        ; put first byte into destination
  325.         mov     al,[esi+1]                      ; get second byte from source
  326.         mov     [edi+1],al                      ; put second byte into destination
  327.         mov     al,[esi+2]                      ; get third byte from source
  328.         mov     [edi+2],al                      ; put third byte into destination
  329.         mov     eax,[esp + 0Ch]                 ; return original destination pointer
  330.         pop     esi                             ; restore esi
  331.         pop     edi                             ; restore edi
  332.         M_EXIT

  333. ;-----------------------------------------------------------------------------
  334. ;-----------------------------------------------------------------------------
  335. ;-----------------------------------------------------------------------------

  336. ; Copy down to avoid propogation in overlapping buffers.
  337.         align   @WordSize
  338. CopyDown:
  339. ; inserting check for size. For < 16 bytes, use dwords without checkign for alignment

  340.         lea     esi, [esi+ecx] ; esi, edi pointing to the end of the buffer
  341.         lea     edi,  [edi+ecx]
  342.         cmp     ecx, 32
  343.         jb      CopyDownSmall
  344.         bt      __isa_enabled, __ISA_AVAILABLE_SSE2
  345.         jc      XmmMovLargeAlignTest
  346. ; See if the destination start is dword aligned

  347.         test    edi,11b                         ; Test if dword aligned
  348.         jz      CopyDownAligned                 ; If not, jump

  349. CopyDownNotAligned:
  350.         mov     edx,edi                         ; get destination offset
  351.         and     edx, 11b
  352.         sub     ecx, edx
  353. CopyDownAlignLoop:
  354.         mov     al, byte ptr [esi-1]
  355.         mov     byte ptr[edi-1], al
  356.         dec     esi
  357.         dec     edi
  358.         sub     edx, 1
  359.         jnz     CopyDownAlignLoop

  360. CopyDownAligned:
  361.         cmp     ecx,32                          ; test if small enough for unwind copy
  362.         jb      CopyDownSmall                   ; if so, then jump
  363.         mov     edx, ecx
  364.         shr     ecx,2                           ; shift down to dword count
  365.         and     edx,11b                         ; trailing byte count
  366.         sub     esi, 4
  367.         sub     edi, 4                          ; settign up src, dest registers
  368.         std                                     ; set direction flag
  369.         rep     movsd                           ; move all of dwords at once
  370.         cld                                     ; clear direction flag back

  371.         jmp     dword ptr TrailingDownVec[edx*4]; process trailing bytes


  372. ;-----------------------------------------------------------------------------

  373.         align   @WordSize
  374. TrailingDownVec    dd      TrailingDown0, TrailingDown1, TrailingDown2, TrailingDown3

  375.         align   @WordSize
  376. TrailingDown0:
  377.         mov     eax,[esp + 0Ch]                 ; return original destination pointer
  378.                                                 ; spare
  379.         pop     esi                             ; restore esi
  380.         pop     edi                             ; restore edi
  381.         M_EXIT

  382.         align   @WordSize
  383. TrailingDown1:
  384.         mov     al,[esi+3]                      ; get byte from source
  385.                                                 ; spare
  386.         mov     [edi+3],al                      ; put byte in destination
  387.         mov     eax,[esp + 0Ch]                 ; return original destination pointer
  388.         pop     esi                             ; restore esi
  389.         pop     edi                             ; restore edi
  390.         M_EXIT

  391.         align   @WordSize
  392. TrailingDown2:
  393.         mov     al,[esi+3]                      ; get first byte from source
  394.                                                 ; spare
  395.         mov     [edi+3],al                      ; put first byte into destination
  396.         mov     al,[esi+2]                      ; get second byte from source
  397.         mov     [edi+2],al                      ; put second byte into destination
  398.         mov     eax,[esp + 0Ch]                 ; return original destination pointer
  399.         pop     esi                             ; restore esi
  400.         pop     edi                             ; restore edi
  401.         M_EXIT

  402.         align   @WordSize
  403. TrailingDown3:
  404.         mov     al,[esi+3]                      ; get first byte from source
  405.                                                 ; spare
  406.         mov     [edi+3],al                      ; put first byte into destination
  407.         mov     al,[esi+2]                      ; get second byte from source
  408.         mov     [edi+2],al                      ; put second byte into destination
  409.         mov     al,[esi+1]                      ; get third byte from source
  410.         mov     [edi+1],al                      ; put third byte into destination
  411.         mov     eax,[esp + 0Ch]                 ; return original destination pointer
  412.         pop     esi                             ; restore esi
  413.         pop     edi                             ; restore edi
  414.         M_EXIT

  415. ; Copy overlapping buffers using XMM registers
  416. XmmMovLargeAlignTest:
  417.         test    edi, 0Fh                        ; check if it's 16-byte aligned
  418.         jz     XmmMovLargeLoop
  419. XmmMovAlignLoop:
  420.         dec     ecx
  421.         dec     esi
  422.         dec     edi
  423.         mov     al, [esi]
  424.         mov     [edi], al
  425.         test    edi, 0Fh
  426.         jnz     XmmMovAlignLoop

  427. XmmMovLargeLoop:
  428.         cmp     ecx, 128
  429.         jb      XmmMovSmallTest
  430.         sub         esi, 128
  431.         sub         edi, 128
  432.         movdqu     xmm0, xmmword ptr[esi]
  433.         movdqu     xmm1, xmmword ptr[esi+16]
  434.         movdqu     xmm2, xmmword ptr[esi+32]
  435.         movdqu     xmm3, xmmword ptr[esi+48]
  436.         movdqu     xmm4, xmmword ptr[esi+64]
  437.         movdqu     xmm5, xmmword ptr[esi+80]
  438.         movdqu     xmm6, xmmword ptr[esi+96]
  439.         movdqu     xmm7, xmmword ptr[esi+112]
  440.         movdqu     xmmword ptr[edi], xmm0
  441.         movdqu     xmmword ptr[edi+16], xmm1
  442.         movdqu     xmmword ptr[edi+32], xmm2
  443.         movdqu     xmmword ptr[edi+48], xmm3
  444.         movdqu     xmmword ptr[edi+64], xmm4
  445.         movdqu     xmmword ptr[edi+80], xmm5
  446.         movdqu     xmmword ptr[edi+96], xmm6
  447.         movdqu     xmmword ptr[edi+112], xmm7
  448.         sub     ecx, 128
  449.         test    ecx, 0FFFFFF80h
  450.         jnz     XmmMovLargeLoop


  451. XmmMovSmallTest:
  452.         cmp     ecx, 32                         ; if lesser than 32, use dwords
  453.         jb     CopyDownSmall

  454. XmmMovSmallLoop:
  455.         sub        esi, 32
  456.         sub        edi, 32
  457.         movdqu     xmm0, xmmword ptr[esi]
  458.         movdqu     xmm1, xmmword ptr[esi+16]
  459.         movdqu     xmmword ptr[edi], xmm0
  460.         movdqu     xmmword ptr[edi+16], xmm1
  461.         sub        ecx, 32
  462.         test       ecx, 0FFFFFFE0h
  463.         jnz        XmmMovSmallLoop

  464. CopyDownSmall:
  465.         test    ecx, 0FFFFFFFCh                 ; mask the bytes
  466.         jz      CopyDownByteTest
  467. CopyDownDwordLoop:
  468.         sub     edi, 4
  469.         sub     esi, 4
  470.         mov     eax, [esi]
  471.         mov     [edi], eax
  472.         sub     ecx, 4
  473.         test    ecx, 0FFFFFFFCh
  474.         jnz     CopyDownDwordLoop
  475. CopyDownByteTest:
  476.         test    ecx, ecx
  477.         jz      CopyDownReturn
  478. CopyDownByteLoop:
  479.         sub     edi, 1
  480.         sub     esi, 1
  481.         mov     al, [esi]
  482.         mov     [edi], al
  483.         sub     ecx, 1
  484.         jnz     CopyDownByteLoop
  485. CopyDownReturn:
  486.         mov     eax,[esp + 0Ch]                 ; return original destination pointer
  487.                                                 ; spare
  488.         pop     esi                             ; restore esi
  489.         pop     edi                             ; restore edi
  490.         M_EXIT


  491. ; Using XMM registers for non-overlapping buffers

  492. align       16
  493. XmmCopy:
  494.         mov         eax, esi
  495.         and         eax, 0Fh
  496.         ; eax = src and dst alignment (src mod 16)
  497.         test        eax, eax
  498.         jne         XmmCopyUnaligned

  499.         ; in:
  500.         ; edi = dst (16 byte aligned)
  501.         ; esi = src (16 byte aligned)
  502.         ; ecx = len is >= (128 - head alignment bytes)
  503.         ; do block copy using SSE2 stores
  504. XmmCopyAligned:
  505.         mov         edx, ecx
  506.         and         ecx, 7Fh
  507.         shr         edx, 7
  508.         je          XmmCopySmallTest
  509.         ; ecx = loop count
  510.         ; edx = remaining copy length

  511. ; Copy greater than or equal to 128 bytes using XMM registers
  512. align       16
  513. XmmCopyLargeLoop:
  514.         movdqa      xmm0,xmmword ptr [esi]
  515.         movdqa      xmm1,xmmword ptr [esi + 10h]
  516.         movdqa      xmm2,xmmword ptr [esi + 20h]
  517.         movdqa      xmm3,xmmword ptr [esi + 30h]
  518.         movdqa      xmmword ptr [edi],xmm0
  519.         movdqa      xmmword ptr [edi + 10h],xmm1
  520.         movdqa      xmmword ptr [edi + 20h],xmm2
  521.         movdqa      xmmword ptr [edi + 30h],xmm3
  522.         movdqa      xmm4,xmmword ptr [esi + 40h]
  523.         movdqa      xmm5,xmmword ptr [esi + 50h]
  524.         movdqa      xmm6,xmmword ptr [esi + 60h]
  525.         movdqa      xmm7,xmmword ptr [esi + 70h]
  526.         movdqa      xmmword ptr [edi + 40h],xmm4
  527.         movdqa      xmmword ptr [edi + 50h],xmm5
  528.         movdqa      xmmword ptr [edi + 60h],xmm6
  529.         movdqa      xmmword ptr [edi + 70h],xmm7
  530.         lea         esi,[esi + 80h]
  531.         lea         edi,[edi + 80h]
  532.         dec         edx
  533.         jne         XmmCopyLargeLoop

  534. ; Copy lesser than 128 bytes
  535. XmmCopySmallTest:
  536.         test        ecx, ecx
  537.         je          CopyUpReturn

  538.         ; ecx = length (< 128 bytes)
  539.         mov         edx, ecx
  540.         shr         edx, 5                      ; check if there are 32 bytes that can be set
  541.         test        edx, edx
  542.         je          CopyUpDwordMov
  543.         ; if > 16 bytes do a loop (16 bytes at a time)
  544.         ; edx - loop count
  545.         ; edi = dst
  546.         ; esi = src

  547. align 16
  548. XmmCopySmallLoop:
  549.         movdqu      xmm0, xmmword ptr [esi]
  550.         movdqu      xmm1, xmmword ptr [esi + 10h]
  551.         movdqu      xmmword ptr [edi], xmm0
  552.         movdqu      xmmword ptr [edi + 10h], xmm1
  553.         lea         esi, [esi + 20h]
  554.         lea         edi, [edi + 20h]
  555.         dec         edx
  556.         jne         XmmCopySmallLoop

  557. CopyUpDwordMov:

  558.         ; last 1-32 bytes: step back according to dst and src alignment and do a 16-byte copy
  559.         ; esi = src
  560.         ; eax = src alignment  (set at the start of the procedure and preserved up to here)
  561.         ; edi = dst
  562.         ; ecx = remaining len
  563.         and         ecx, 1Fh
  564.         je          CopyUpReturn
  565. CopyUpDwordTest:
  566.         mov     eax, ecx  ; save remaining len and calc number of dwords
  567.         shr     ecx, 2
  568.         je      CopyUpByteTest ; if none try bytes
  569. CopyUpDwordLoop:
  570.         mov     edx, dword ptr [esi]
  571.         mov     dword ptr [edi], edx
  572.         add     edi, 4
  573.         add     esi, 4
  574.         sub     ecx, 1
  575.         jne     CopyUpDwordLoop
  576. CopyUpByteTest:
  577.         mov     ecx, eax
  578.         and     ecx, 03h
  579.         je      CopyUpReturn ; if none return
  580. CopyUpByteLoop:
  581.         mov     al, byte ptr [esi]
  582.         mov     byte ptr [edi], al
  583.         inc     esi
  584.         inc     edi
  585.         dec     ecx
  586.         jne     CopyUpByteLoop
  587. align 16
  588. CopyUpReturn:
  589.         ; return dst
  590.         mov     eax,[esp + 0Ch]                 ; return original destination pointer
  591.         pop     esi
  592.         pop     edi
  593.         M_EXIT


  594. ; dst addr is not 16 byte aligned
  595. align 16
  596. XmmCopyUnaligned:

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

  598. ; in
  599. ; esi = src
  600. ; edi = dst
  601. ; eax = src and dst alignment
  602. ; ecx = length

  603.         mov     edx, 010h
  604.         sub     edx, eax                        ; calculate number of bytes to get it aligned
  605.         sub     ecx, edx                        ; calc new length and save it
  606.         push    ecx
  607.         mov     eax, edx                        ; save alignment byte count for dwords
  608.         mov     ecx, eax                        ; set ecx to rep count
  609.         and     ecx, 03h
  610.         je      XmmAlignDwordTest               ; if no bytes go do dwords
  611. XmmAlignByte:
  612.         mov     dl, byte ptr [esi]              ; move the bytes
  613.         mov     byte ptr [edi], dl
  614.         inc     esi                             ; increment  the addresses
  615.         inc     edi
  616.         dec     ecx                             ; decrement the counter
  617.         jne     XmmAlignByte
  618. XmmAlignDwordTest:
  619.         shr     eax, 2                          ; get dword count
  620.         je      XmmAlignAdjustCnt               ; if none go to main loop
  621. XmmAlignDwordLoop:
  622.         mov     edx, dword ptr [esi]            ; move the dwords
  623.         mov     dword ptr [edi], edx
  624.         lea     esi, [esi+4]                    ; increment the addresses
  625.         lea     edi, [edi+4]
  626.         dec     eax                             ; decrement the counter
  627.         jne     XmmAlignDwordLoop
  628. XmmAlignAdjustCnt:
  629.         pop     ecx                             ; retrieve the adjusted length
  630.         jmp     XmmCopyAligned


  631. _MEM_   endp
  632.         end


复制代码

最佳答案

查看完整内容

我们以1212345890为例,具体看一看memcpy内部是怎么做的(在vs2017中) 通过分析memcpy的源代码,我发现vs是先复制后4个字节,然后再复制最前面那1个字节 先把[1] [2] [3] [4] 复制到[3] [4] [5] [6] (一次性复制4个字节) 最后把[0]复制到[2] 如果你有能力研究memcpy的源代码,那么请看下面的memcpy源代码,如果没有能力研究,那么目前你只是记住“不同的编译器有不同的方法,甚至同一个编译器的不同编译选项都有不同 ...
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2019-4-3 18:54:39 | 显示全部楼层    本楼为最佳答案   
我们以1212345890为例,具体看一看memcpy内部是怎么做的(在vs2017中)

通过分析memcpy的源代码,我发现vs是先复制后4个字节,然后再复制最前面那1个字节

先把[1] [2] [3] [4] 复制到[3] [4] [5] [6] (一次性复制4个字节)
最后把[0]复制到[2]

如果你有能力研究memcpy的源代码,那么请看下面的memcpy源代码,如果没有能力研究,那么目前你只是记住“不同的编译器有不同的方法,甚至同一个编译器的不同编译选项都有不同的结果”就行了,等你有了这个能力以后,自己去看源代码
  1.        page    ,132
  2.         title   memcpy - Copy source memory bytes to destination
  3. ;***
  4. ;memcpy.asm - contains memcpy and memmove routines
  5. ;
  6. ;       Copyright (c) Microsoft Corporation. All rights reserved.
  7. ;
  8. ;Purpose:
  9. ;       memcpy() copies a source memory buffer to a destination buffer.
  10. ;       Overlapping buffers are not treated specially, so propogation may occur.
  11. ;       memmove() copies a source memory buffer to a destination buffer.
  12. ;       Overlapping buffers are treated specially, to avoid propogation.
  13. ;
  14. ;*******************************************************************************

  15.         .xlist
  16.         include vcruntime.inc
  17.         .list
  18.         .xmm

  19. M_EXIT  macro
  20.         ret                     ; _cdecl return
  21.         endm    ; M_EXIT

  22. PALIGN_memcpy macro d
  23. MovPalign&d&:
  24.         movdqa  xmm1,xmmword ptr [esi-d]
  25.         lea     esi, byte ptr [esi-d]

  26.         align   @WordSize

  27. PalignLoop&d&:
  28.         movdqa  xmm3,xmmword ptr [esi+10h]
  29.         sub     ecx,30h
  30.         movdqa  xmm0,xmmword ptr [esi+20h]
  31.         movdqa  xmm5,xmmword ptr [esi+30h]
  32.         lea     esi, xmmword ptr [esi+30h]
  33.         cmp     ecx,30h
  34.         movdqa  xmm2,xmm3

  35.         palignr xmm3,xmm1,d

  36.         movdqa  xmmword ptr [edi],xmm3
  37.         movdqa  xmm4,xmm0

  38.         palignr xmm0,xmm2,d

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

  41.         palignr xmm5,xmm4,d

  42.         movdqa  xmmword ptr [edi+20h],xmm5
  43.         lea     edi, xmmword ptr [edi+30h]
  44.         jae     PalignLoop&d&
  45.         lea     esi, xmmword ptr [esi+d]

  46.         endm    ; PALIGN_memcpy

  47.         CODESEG

  48.     extrn   __isa_available:dword
  49.     extrn   __isa_enabled:dword
  50.     extrn   __favor:dword

  51. page
  52. ;***
  53. ;memcpy - Copy source buffer to destination buffer
  54. ;
  55. ;Purpose:
  56. ;       memcpy() copies a source memory buffer to a destination memory buffer.
  57. ;       This routine does NOT recognize overlapping buffers, and thus can lead
  58. ;       to propogation.
  59. ;       For cases where propogation must be avoided, memmove() must be used.
  60. ;
  61. ;       Algorithm:
  62. ;
  63. ;           Same as memmove. See Below
  64. ;
  65. ;
  66. ;memmove - Copy source buffer to destination buffer
  67. ;
  68. ;Purpose:
  69. ;       memmove() copies a source memory buffer to a destination memory buffer.
  70. ;       This routine recognize overlapping buffers to avoid propogation.
  71. ;       For cases where propogation is not a problem, memcpy() can be used.
  72. ;
  73. ;   Algorithm:
  74. ;
  75. ;       void * memmove(void * dst, void * src, size_t count)
  76. ;       {
  77. ;               void * ret = dst;
  78. ;
  79. ;               if (dst <= src || dst >= (src + count)) {
  80. ;                       /*
  81. ;                        * Non-Overlapping Buffers
  82. ;                        * copy from lower addresses to higher addresses
  83. ;                        */
  84. ;                       while (count--)
  85. ;                               *dst++ = *src++;
  86. ;                       }
  87. ;               else {
  88. ;                       /*
  89. ;                        * Overlapping Buffers
  90. ;                        * copy from higher addresses to lower addresses
  91. ;                        */
  92. ;                       dst += count - 1;
  93. ;                       src += count - 1;
  94. ;
  95. ;                       while (count--)
  96. ;                               *dst-- = *src--;
  97. ;                       }
  98. ;
  99. ;               return(ret);
  100. ;       }
  101. ;
  102. ;
  103. ;Entry:
  104. ;       void *dst = pointer to destination buffer
  105. ;       const void *src = pointer to source buffer
  106. ;       size_t count = number of bytes to copy
  107. ;
  108. ;Exit:
  109. ;       Returns a pointer to the destination buffer in AX/DX:AX
  110. ;
  111. ;Uses:
  112. ;       CX, DX
  113. ;
  114. ;Exceptions:
  115. ;*******************************************************************************

  116. ifdef MEM_MOVE
  117.         _MEM_     equ <memmove>
  118. else  ; MEM_MOVE
  119.         _MEM_     equ <memcpy>
  120. endif  ; MEM_MOVE

  121. %       public  _MEM_
  122. _MEM_   proc \
  123.         dst:ptr byte, \
  124.         src:ptr byte, \
  125.         count:IWORD

  126.         ; destination pointer
  127.         ; source pointer
  128.         ; number of bytes to copy

  129.         OPTION PROLOGUE:NONE, EPILOGUE:NONE

  130.         push    edi                             ; save edi
  131.         push    esi                             ; save esi

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

  134.         mov     esi,[esp + 010h]                ; esi = source
  135.         mov     ecx,[esp + 014h]                ; ecx = number of bytes to move
  136.         mov     edi,[esp + 0Ch]                 ; edi = dest

  137. ;
  138. ; Check for overlapping buffers:
  139. ;       If (dst <= src) Or (dst >= src + Count) Then
  140. ;               Do normal (Upwards) Copy
  141. ;       Else
  142. ;               Do Downwards Copy to avoid propagation
  143. ;

  144.         mov     eax,ecx                         ; eax = byte count

  145.         mov     edx,ecx                         ; edx = byte count
  146.         add     eax,esi                         ; eax = point past source end

  147.         cmp     edi,esi                         ; dst <= src ?
  148.         jbe     short CopyUp                    ; no overlap: copy toward higher addresses

  149.         cmp     edi,eax                         ; dst < (src + count) ?
  150.         jb      CopyDown                        ; overlap: copy toward lower addresses

  151. ;
  152. ; Buffers do not overlap, copy toward higher addresses.
  153. ;
  154. CopyUp:
  155.         cmp     ecx, 020h
  156.         jb      CopyUpDwordMov                  ; size smaller than 32 bytes, use dwords
  157.         cmp     ecx, 080h
  158.         jae     CopyUpLargeMov                  ; if greater than or equal to 128 bytes, use Enhanced fast Strings
  159.         bt      __isa_enabled, __ISA_AVAILABLE_SSE2
  160.         jc      XmmCopySmallTest
  161.         jmp     Dword_align

  162. CopyUpLargeMov:
  163.         bt      __favor, __FAVOR_ENFSTRG        ; check if Enhanced Fast Strings is supported
  164.         jnc     CopyUpSSE2Check                 ; if not, check for SSE2 support
  165.         rep     movsb
  166.         mov     eax,[esp + 0Ch]                 ; return original destination pointer
  167.         pop     esi
  168.         pop     edi
  169.         M_EXIT

  170. ;
  171. ;      Check if source and destination are equally aligned.
  172. ;
  173. CopyUpSSE2Check:
  174.         mov     eax,edi
  175.         xor     eax,esi
  176.         test    eax,15
  177.         jne     AtomChk   ; Not aligned go check Atom
  178.         bt      __isa_enabled, __ISA_AVAILABLE_SSE2
  179.         jc      XmmCopy ; yes, go SSE2 copy (params already set)
  180. AtomChk:
  181.         ; Is Atom supported?
  182.         bt      __favor, __FAVOR_ATOM
  183.         jnc     Dword_align ; no,jump

  184.         ; check if dst is 4 byte aligned
  185.         test    edi, 3
  186.         jne     Dword_align

  187.         ; check if src is 4 byte aligned
  188.         test    esi, 3
  189.         jne     Dword_align_Ok

  190. ; A software pipelining vectorized memcpy loop using PALIGN instructions

  191. ; (1) copy the first bytes to align dst up to the nearest 16-byte boundary
  192. ; 4 byte align -> 12 byte copy, 8 byte align -> 8 byte copy, 12 byte align -> 4 byte copy
  193. PalignHead4:
  194.         bt      edi, 2
  195.         jae     PalignHead8
  196.         mov     eax, dword ptr [esi]
  197.         sub     ecx, 4
  198.         lea     esi, byte ptr [esi+4]
  199.         mov     dword ptr [edi], eax
  200.         lea     edi, byte ptr [edi+4]

  201. PalignHead8:
  202.         bt      edi, 3
  203.         jae     PalignLoop
  204.         movq    xmm1, qword ptr [esi]
  205.         sub     ecx, 8
  206.         lea     esi, byte ptr [esi+8]
  207.         movq    qword ptr [edi], xmm1
  208.         lea     edi, byte ptr [edi+8]

  209. ;(2) Use SSE palign loop
  210. PalignLoop:
  211.         test    esi, 7
  212.         je      MovPalign8
  213.         bt      esi, 3
  214.         jae     MovPalign4

  215. PALIGN_memcpy 12
  216.         jmp     PalignTail

  217. PALIGN_memcpy 8
  218.         jmp     PalignTail

  219. PALIGN_memcpy 4

  220. ;(3) Copy the tailing bytes.
  221. PalignTail:
  222.         cmp    ecx,10h
  223.         jb     PalignTail4
  224.         movdqu xmm1,xmmword ptr [esi]
  225.         sub    ecx, 10h
  226.         lea    esi, xmmword ptr [esi+10h]
  227.         movdqa xmmword ptr [edi],xmm1
  228.         lea    edi, xmmword ptr [edi+10h]
  229.         jmp    PalignTail

  230. PalignTail4:
  231.         bt      ecx, 2
  232.         jae     PalignTail8
  233.         mov     eax, dword ptr [esi]
  234.         sub     ecx,4
  235.         lea     esi, byte ptr [esi+4]
  236.         mov     dword ptr [edi], eax
  237.         lea     edi, byte ptr [edi+4]

  238. PalignTail8:
  239.         bt      ecx, 3
  240.         jae     PalignTailLE3
  241.         movq    xmm1, qword ptr [esi]
  242.         sub     ecx,8
  243.         lea     esi, byte ptr [esi+8]
  244.         movq    qword ptr [edi], xmm1
  245.         lea     edi, byte ptr [edi+8]

  246. PalignTailLE3:
  247.         mov     eax, dword ptr TrailingUpVec[ecx*4]
  248.         jmp     eax

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

  257. Dword_align:
  258.         test   edi,11b                          ; check if destination is dword aligned
  259.         jz     short Dword_align_Ok             ; if destination not dword aligned already, it should be aligned

  260. Dword_up_align_loop:
  261.         mov     al, byte ptr [esi]
  262.         mov     byte ptr [edi], al
  263.         dec     ecx
  264.         add     esi, 1
  265.         add     edi, 1
  266.         test    edi, 11b
  267.         jnz     Dword_up_align_loop
  268. Dword_align_Ok:
  269.         mov     edx, ecx
  270.         cmp     ecx, 32
  271.         jb      CopyUpDwordMov
  272.         shr     ecx,2
  273.         rep     movsd                           ; move all of our dwords
  274.         and     edx,11b                         ; trailing byte count
  275.         jmp     dword ptr TrailingUpVec[edx*4]  ; process trailing bytes

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

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


  287.         align   @WordSize
  288. ByteCopyUp:
  289.         jmp     dword ptr TrailingUpVec[ecx*4+16]  ; process just bytes


  290. ;-----------------------------------------------------------------------------

  291.         align   @WordSize
  292. TrailingUpVec      dd      TrailingUp0, TrailingUp1, TrailingUp2, TrailingUp3

  293.         align   @WordSize
  294. TrailingUp0:
  295.         mov     eax,[esp + 0Ch]                 ; return original destination pointer
  296.         pop     esi                             ; restore esi
  297.         pop     edi                             ; restore edi
  298.                                                 ; spare
  299.         M_EXIT

  300.         align   @WordSize
  301. TrailingUp1:
  302.         mov     al,[esi]                        ; get byte from source
  303.                                                 ; spare
  304.         mov     [edi],al                        ; put byte in destination
  305.         mov     eax,[esp + 0Ch]                 ; return original destination pointer
  306.         pop     esi                             ; restore esi
  307.         pop     edi                             ; restore edi
  308.         M_EXIT

  309.         align   @WordSize
  310. TrailingUp2:
  311.         mov     al,[esi]                        ; get first byte from source
  312.                                                 ; spare
  313.         mov     [edi],al                        ; put first byte into destination
  314.         mov     al,[esi+1]                      ; get second byte from source
  315.         mov     [edi+1],al                      ; put second byte into destination
  316.         mov     eax,[esp + 0Ch]                 ; return original destination pointer
  317.         pop     esi                             ; restore esi
  318.         pop     edi                             ; restore edi
  319.         M_EXIT

  320.         align   @WordSize
  321. TrailingUp3:
  322.         mov     al,[esi]                        ; get first byte from source
  323.                                                 ; spare
  324.         mov     [edi],al                        ; put first byte into destination
  325.         mov     al,[esi+1]                      ; get second byte from source
  326.         mov     [edi+1],al                      ; put second byte into destination
  327.         mov     al,[esi+2]                      ; get third byte from source
  328.         mov     [edi+2],al                      ; put third byte into destination
  329.         mov     eax,[esp + 0Ch]                 ; return original destination pointer
  330.         pop     esi                             ; restore esi
  331.         pop     edi                             ; restore edi
  332.         M_EXIT

  333. ;-----------------------------------------------------------------------------
  334. ;-----------------------------------------------------------------------------
  335. ;-----------------------------------------------------------------------------

  336. ; Copy down to avoid propogation in overlapping buffers.
  337.         align   @WordSize
  338. CopyDown:
  339. ; inserting check for size. For < 16 bytes, use dwords without checkign for alignment

  340.         lea     esi, [esi+ecx] ; esi, edi pointing to the end of the buffer
  341.         lea     edi,  [edi+ecx]
  342.         cmp     ecx, 32
  343.         jb      CopyDownSmall
  344.         bt      __isa_enabled, __ISA_AVAILABLE_SSE2
  345.         jc      XmmMovLargeAlignTest
  346. ; See if the destination start is dword aligned

  347.         test    edi,11b                         ; Test if dword aligned
  348.         jz      CopyDownAligned                 ; If not, jump

  349. CopyDownNotAligned:
  350.         mov     edx,edi                         ; get destination offset
  351.         and     edx, 11b
  352.         sub     ecx, edx
  353. CopyDownAlignLoop:
  354.         mov     al, byte ptr [esi-1]
  355.         mov     byte ptr[edi-1], al
  356.         dec     esi
  357.         dec     edi
  358.         sub     edx, 1
  359.         jnz     CopyDownAlignLoop

  360. CopyDownAligned:
  361.         cmp     ecx,32                          ; test if small enough for unwind copy
  362.         jb      CopyDownSmall                   ; if so, then jump
  363.         mov     edx, ecx
  364.         shr     ecx,2                           ; shift down to dword count
  365.         and     edx,11b                         ; trailing byte count
  366.         sub     esi, 4
  367.         sub     edi, 4                          ; settign up src, dest registers
  368.         std                                     ; set direction flag
  369.         rep     movsd                           ; move all of dwords at once
  370.         cld                                     ; clear direction flag back

  371.         jmp     dword ptr TrailingDownVec[edx*4]; process trailing bytes


  372. ;-----------------------------------------------------------------------------

  373.         align   @WordSize
  374. TrailingDownVec    dd      TrailingDown0, TrailingDown1, TrailingDown2, TrailingDown3

  375.         align   @WordSize
  376. TrailingDown0:
  377.         mov     eax,[esp + 0Ch]                 ; return original destination pointer
  378.                                                 ; spare
  379.         pop     esi                             ; restore esi
  380.         pop     edi                             ; restore edi
  381.         M_EXIT

  382.         align   @WordSize
  383. TrailingDown1:
  384.         mov     al,[esi+3]                      ; get byte from source
  385.                                                 ; spare
  386.         mov     [edi+3],al                      ; put byte in destination
  387.         mov     eax,[esp + 0Ch]                 ; return original destination pointer
  388.         pop     esi                             ; restore esi
  389.         pop     edi                             ; restore edi
  390.         M_EXIT

  391.         align   @WordSize
  392. TrailingDown2:
  393.         mov     al,[esi+3]                      ; get first byte from source
  394.                                                 ; spare
  395.         mov     [edi+3],al                      ; put first byte into destination
  396.         mov     al,[esi+2]                      ; get second byte from source
  397.         mov     [edi+2],al                      ; put second byte into destination
  398.         mov     eax,[esp + 0Ch]                 ; return original destination pointer
  399.         pop     esi                             ; restore esi
  400.         pop     edi                             ; restore edi
  401.         M_EXIT

  402.         align   @WordSize
  403. TrailingDown3:
  404.         mov     al,[esi+3]                      ; get first byte from source
  405.                                                 ; spare
  406.         mov     [edi+3],al                      ; put first byte into destination
  407.         mov     al,[esi+2]                      ; get second byte from source
  408.         mov     [edi+2],al                      ; put second byte into destination
  409.         mov     al,[esi+1]                      ; get third byte from source
  410.         mov     [edi+1],al                      ; put third byte into destination
  411.         mov     eax,[esp + 0Ch]                 ; return original destination pointer
  412.         pop     esi                             ; restore esi
  413.         pop     edi                             ; restore edi
  414.         M_EXIT

  415. ; Copy overlapping buffers using XMM registers
  416. XmmMovLargeAlignTest:
  417.         test    edi, 0Fh                        ; check if it's 16-byte aligned
  418.         jz     XmmMovLargeLoop
  419. XmmMovAlignLoop:
  420.         dec     ecx
  421.         dec     esi
  422.         dec     edi
  423.         mov     al, [esi]
  424.         mov     [edi], al
  425.         test    edi, 0Fh
  426.         jnz     XmmMovAlignLoop

  427. XmmMovLargeLoop:
  428.         cmp     ecx, 128
  429.         jb      XmmMovSmallTest
  430.         sub         esi, 128
  431.         sub         edi, 128
  432.         movdqu     xmm0, xmmword ptr[esi]
  433.         movdqu     xmm1, xmmword ptr[esi+16]
  434.         movdqu     xmm2, xmmword ptr[esi+32]
  435.         movdqu     xmm3, xmmword ptr[esi+48]
  436.         movdqu     xmm4, xmmword ptr[esi+64]
  437.         movdqu     xmm5, xmmword ptr[esi+80]
  438.         movdqu     xmm6, xmmword ptr[esi+96]
  439.         movdqu     xmm7, xmmword ptr[esi+112]
  440.         movdqu     xmmword ptr[edi], xmm0
  441.         movdqu     xmmword ptr[edi+16], xmm1
  442.         movdqu     xmmword ptr[edi+32], xmm2
  443.         movdqu     xmmword ptr[edi+48], xmm3
  444.         movdqu     xmmword ptr[edi+64], xmm4
  445.         movdqu     xmmword ptr[edi+80], xmm5
  446.         movdqu     xmmword ptr[edi+96], xmm6
  447.         movdqu     xmmword ptr[edi+112], xmm7
  448.         sub     ecx, 128
  449.         test    ecx, 0FFFFFF80h
  450.         jnz     XmmMovLargeLoop


  451. XmmMovSmallTest:
  452.         cmp     ecx, 32                         ; if lesser than 32, use dwords
  453.         jb     CopyDownSmall

  454. XmmMovSmallLoop:
  455.         sub        esi, 32
  456.         sub        edi, 32
  457.         movdqu     xmm0, xmmword ptr[esi]
  458.         movdqu     xmm1, xmmword ptr[esi+16]
  459.         movdqu     xmmword ptr[edi], xmm0
  460.         movdqu     xmmword ptr[edi+16], xmm1
  461.         sub        ecx, 32
  462.         test       ecx, 0FFFFFFE0h
  463.         jnz        XmmMovSmallLoop

  464. CopyDownSmall:
  465.         test    ecx, 0FFFFFFFCh                 ; mask the bytes
  466.         jz      CopyDownByteTest
  467. CopyDownDwordLoop:
  468.         sub     edi, 4
  469.         sub     esi, 4
  470.         mov     eax, [esi]
  471.         mov     [edi], eax
  472.         sub     ecx, 4
  473.         test    ecx, 0FFFFFFFCh
  474.         jnz     CopyDownDwordLoop
  475. CopyDownByteTest:
  476.         test    ecx, ecx
  477.         jz      CopyDownReturn
  478. CopyDownByteLoop:
  479.         sub     edi, 1
  480.         sub     esi, 1
  481.         mov     al, [esi]
  482.         mov     [edi], al
  483.         sub     ecx, 1
  484.         jnz     CopyDownByteLoop
  485. CopyDownReturn:
  486.         mov     eax,[esp + 0Ch]                 ; return original destination pointer
  487.                                                 ; spare
  488.         pop     esi                             ; restore esi
  489.         pop     edi                             ; restore edi
  490.         M_EXIT


  491. ; Using XMM registers for non-overlapping buffers

  492. align       16
  493. XmmCopy:
  494.         mov         eax, esi
  495.         and         eax, 0Fh
  496.         ; eax = src and dst alignment (src mod 16)
  497.         test        eax, eax
  498.         jne         XmmCopyUnaligned

  499.         ; in:
  500.         ; edi = dst (16 byte aligned)
  501.         ; esi = src (16 byte aligned)
  502.         ; ecx = len is >= (128 - head alignment bytes)
  503.         ; do block copy using SSE2 stores
  504. XmmCopyAligned:
  505.         mov         edx, ecx
  506.         and         ecx, 7Fh
  507.         shr         edx, 7
  508.         je          XmmCopySmallTest
  509.         ; ecx = loop count
  510.         ; edx = remaining copy length

  511. ; Copy greater than or equal to 128 bytes using XMM registers
  512. align       16
  513. XmmCopyLargeLoop:
  514.         movdqa      xmm0,xmmword ptr [esi]
  515.         movdqa      xmm1,xmmword ptr [esi + 10h]
  516.         movdqa      xmm2,xmmword ptr [esi + 20h]
  517.         movdqa      xmm3,xmmword ptr [esi + 30h]
  518.         movdqa      xmmword ptr [edi],xmm0
  519.         movdqa      xmmword ptr [edi + 10h],xmm1
  520.         movdqa      xmmword ptr [edi + 20h],xmm2
  521.         movdqa      xmmword ptr [edi + 30h],xmm3
  522.         movdqa      xmm4,xmmword ptr [esi + 40h]
  523.         movdqa      xmm5,xmmword ptr [esi + 50h]
  524.         movdqa      xmm6,xmmword ptr [esi + 60h]
  525.         movdqa      xmm7,xmmword ptr [esi + 70h]
  526.         movdqa      xmmword ptr [edi + 40h],xmm4
  527.         movdqa      xmmword ptr [edi + 50h],xmm5
  528.         movdqa      xmmword ptr [edi + 60h],xmm6
  529.         movdqa      xmmword ptr [edi + 70h],xmm7
  530.         lea         esi,[esi + 80h]
  531.         lea         edi,[edi + 80h]
  532.         dec         edx
  533.         jne         XmmCopyLargeLoop

  534. ; Copy lesser than 128 bytes
  535. XmmCopySmallTest:
  536.         test        ecx, ecx
  537.         je          CopyUpReturn

  538.         ; ecx = length (< 128 bytes)
  539.         mov         edx, ecx
  540.         shr         edx, 5                      ; check if there are 32 bytes that can be set
  541.         test        edx, edx
  542.         je          CopyUpDwordMov
  543.         ; if > 16 bytes do a loop (16 bytes at a time)
  544.         ; edx - loop count
  545.         ; edi = dst
  546.         ; esi = src

  547. align 16
  548. XmmCopySmallLoop:
  549.         movdqu      xmm0, xmmword ptr [esi]
  550.         movdqu      xmm1, xmmword ptr [esi + 10h]
  551.         movdqu      xmmword ptr [edi], xmm0
  552.         movdqu      xmmword ptr [edi + 10h], xmm1
  553.         lea         esi, [esi + 20h]
  554.         lea         edi, [edi + 20h]
  555.         dec         edx
  556.         jne         XmmCopySmallLoop

  557. CopyUpDwordMov:

  558.         ; last 1-32 bytes: step back according to dst and src alignment and do a 16-byte copy
  559.         ; esi = src
  560.         ; eax = src alignment  (set at the start of the procedure and preserved up to here)
  561.         ; edi = dst
  562.         ; ecx = remaining len
  563.         and         ecx, 1Fh
  564.         je          CopyUpReturn
  565. CopyUpDwordTest:
  566.         mov     eax, ecx  ; save remaining len and calc number of dwords
  567.         shr     ecx, 2
  568.         je      CopyUpByteTest ; if none try bytes
  569. CopyUpDwordLoop:
  570.         mov     edx, dword ptr [esi]
  571.         mov     dword ptr [edi], edx
  572.         add     edi, 4
  573.         add     esi, 4
  574.         sub     ecx, 1
  575.         jne     CopyUpDwordLoop
  576. CopyUpByteTest:
  577.         mov     ecx, eax
  578.         and     ecx, 03h
  579.         je      CopyUpReturn ; if none return
  580. CopyUpByteLoop:
  581.         mov     al, byte ptr [esi]
  582.         mov     byte ptr [edi], al
  583.         inc     esi
  584.         inc     edi
  585.         dec     ecx
  586.         jne     CopyUpByteLoop
  587. align 16
  588. CopyUpReturn:
  589.         ; return dst
  590.         mov     eax,[esp + 0Ch]                 ; return original destination pointer
  591.         pop     esi
  592.         pop     edi
  593.         M_EXIT


  594. ; dst addr is not 16 byte aligned
  595. align 16
  596. XmmCopyUnaligned:

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

  598. ; in
  599. ; esi = src
  600. ; edi = dst
  601. ; eax = src and dst alignment
  602. ; ecx = length

  603.         mov     edx, 010h
  604.         sub     edx, eax                        ; calculate number of bytes to get it aligned
  605.         sub     ecx, edx                        ; calc new length and save it
  606.         push    ecx
  607.         mov     eax, edx                        ; save alignment byte count for dwords
  608.         mov     ecx, eax                        ; set ecx to rep count
  609.         and     ecx, 03h
  610.         je      XmmAlignDwordTest               ; if no bytes go do dwords
  611. XmmAlignByte:
  612.         mov     dl, byte ptr [esi]              ; move the bytes
  613.         mov     byte ptr [edi], dl
  614.         inc     esi                             ; increment  the addresses
  615.         inc     edi
  616.         dec     ecx                             ; decrement the counter
  617.         jne     XmmAlignByte
  618. XmmAlignDwordTest:
  619.         shr     eax, 2                          ; get dword count
  620.         je      XmmAlignAdjustCnt               ; if none go to main loop
  621. XmmAlignDwordLoop:
  622.         mov     edx, dword ptr [esi]            ; move the dwords
  623.         mov     dword ptr [edi], edx
  624.         lea     esi, [esi+4]                    ; increment the addresses
  625.         lea     edi, [edi+4]
  626.         dec     eax                             ; decrement the counter
  627.         jne     XmmAlignDwordLoop
  628. XmmAlignAdjustCnt:
  629.         pop     ecx                             ; retrieve the adjusted length
  630.         jmp     XmmCopyAligned


  631. _MEM_   endp
  632.         end


复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2019-4-3 19:09:42 | 显示全部楼层
本帖最后由 82457097 于 2019-4-3 19:11 编辑

memcpy函数第一个参数是指向用来存储复制来的数据的地址的指针;第二个参数是指向赋值源的指针;第三个是复制数据的字节数;

如题:取原数组的第三个元素的地址为储存容器起始地址,取原数组第一个元素地址为复制数据源起始地址,尺寸为5个字节
综上,将3 4 5 6 7改为 1 2 3 4 5 所以得到1 2 1 2 3 4 5 8 9 0;
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2019-4-3 19:35:19 | 显示全部楼层
82457097 发表于 2019-4-3 19:09
memcpy函数第一个参数是指向用来存储复制来的数据的地址的指针;第二个参数是指向赋值源的指针;第三个是复 ...

是把后面5个字节的全部存储下来拷贝过去的吗??不是一个一个拷贝过去的吗??
data[2] = data[0];
data[3] = data[1]; //12 12 3456
data[4] = data[2];  //这里data[2]不是已经变成1了吗
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2019-4-3 23:13:52 | 显示全部楼层
因为src和dst所指的内存区域重叠了

标准好像并没有规定在这个情况下memcpy的行为
不同的编译器有不同的方法,甚至同一个编译器的不同编译选项都有不同的结果
  1. sh-5.0$ cat main.c
  2. #include <stdio.h>
  3. #include <string.h>

  4. #define MAX_DATA_SIZE (10)

  5. int main()
  6. {
  7.         unsigned int i = 0;
  8.         unsigned char data[MAX_DATA_SIZE] = { '1','2','3','4','5','6','7','8','9','0' };
  9.         memcpy(&data[2], data, MAX_DATA_SIZE / 2);

  10.         for(i = 0; i < 10; ++i)
  11.         {
  12.                 printf("%c ", data[i]);
  13.         }
  14.         printf("\n");

  15.         return 0;
  16. }
  17. sh-5.0$ gcc -o main main.c
  18. sh-5.0$ ./main
  19. 1 2 1 2 3 4 5 8 9 0
  20. sh-5.0$ gcc -O3 -o main main.c
  21. sh-5.0$ ./main
  22. 1 2 1 2 3 4 3 8 9 0
  23. sh-5.0$
复制代码

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-7-12 16:29

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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