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

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 10920|回复: 10

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

[复制链接]

1112

主题

1653

回帖

7万

积分

用户组: 管理员

一只技术宅

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

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

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

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

  5.         ; destination pointer
  6.         ; source pointer
  7.         ; number of bytes to copy

  8.         OPTION PROLOGUE:NONE, EPILOGUE:NONE

  9.         push    edi             ;U - save edi
  10. 0012B090 57                   push        edi  
  11.         push    esi             ;V - save esi
  12. 0012B091 56                   push        esi  

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

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

  21. ;
  22. ; Check for overlapping buffers:
  23. ;       If (dst <= src) Or (dst >= src + Count) Then
  24. ;               Do normal (Upwards) Copy
  25. ;       Else
  26. ;               Do Downwards Copy to avoid propagation
  27. ;

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

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

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

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

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

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

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

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

  97. ; (1) copy the first bytes to align dst up to the nearest 16-byte boundary
  98. ; 4 byte align -> 12 byte copy, 8 byte align -> 8 byte copy, 12 byte align -> 4 byte copy
  99. PalignHead4:
  100.         bt      edi, 2
  101. 0012B10C 0F BA E7 02          bt          edi,2  
  102.         jae     PalignHead8
  103. 0012B110 73 0D                jae         CopyUp+6Fh (012B11Fh)  
  104.         mov     eax, dword ptr [esi]
  105. 0012B112 8B 06                mov         eax,dword ptr [esi]  
  106.         sub     ecx, 4
  107. 0012B114 83 E9 04             sub         ecx,4  
  108.         lea     esi, byte ptr [esi+4]
  109. 0012B117 8D 76 04             lea         esi,[esi+4]  
  110.         mov     dword ptr [edi], eax
  111. 0012B11A 89 07                mov         dword ptr [edi],eax  
  112.         lea     edi, byte ptr [edi+4]
  113. 0012B11C 8D 7F 04             lea         edi,[edi+4]  

  114. PalignHead8:
  115.         bt      edi, 3
  116. 0012B11F 0F BA E7 03          bt          edi,3  
  117.         jae     PalignLoop
  118. 0012B123 73 11                jae         CopyUp+86h (012B136h)  
  119.         movq    xmm1, qword ptr [esi]
  120. 0012B125 F3 0F 7E 0E          movq        xmm1,mmword ptr [esi]  
  121.         sub     ecx, 8
  122. 0012B129 83 E9 08             sub         ecx,8  
  123.         lea     esi, byte ptr [esi+8]
  124. 0012B12C 8D 76 08             lea         esi,[esi+8]  
  125.         movq    qword ptr [edi], xmm1
  126. 0012B12F 66 0F D6 0F          movq        mmword ptr [edi],xmm1  
  127.         lea     edi, byte ptr [edi+8]
  128. 0012B133 8D 7F 08             lea         edi,[edi+8]  

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

  139. PALIGN_memcpy 12
  140. 0012B148 66 0F 6F 4E F4       movdqa      xmm1,xmmword ptr [esi-0Ch]  
  141. 0012B14D 8D 76 F4             lea         esi,[esi-0Ch]  
  142. PalignLoop12:
  143. 0012B150 66 0F 6F 5E 10       movdqa      xmm3,xmmword ptr [esi+10h]  
  144. 0012B155 83 E9 30             sub         ecx,30h  
  145. 0012B158 66 0F 6F 46 20       movdqa      xmm0,xmmword ptr [esi+20h]  
  146. 0012B15D 66 0F 6F 6E 30       movdqa      xmm5,xmmword ptr [esi+30h]  
  147. 0012B162 8D 76 30             lea         esi,[esi+30h]  
  148. 0012B165 83 F9 30             cmp         ecx,30h  
  149. 0012B168 66 0F 6F D3          movdqa      xmm2,xmm3  
  150. 0012B16C 66 0F 3A 0F D9 0C    palignr     xmm3,xmm1,0Ch  
  151. 0012B172 66 0F 7F 1F          movdqa      xmmword ptr [edi],xmm3  
  152. 0012B176 66 0F 6F E0          movdqa      xmm4,xmm0  
  153. 0012B17A 66 0F 3A 0F C2 0C    palignr     xmm0,xmm2,0Ch  
  154. 0012B180 66 0F 7F 47 10       movdqa      xmmword ptr [edi+10h],xmm0  
  155. 0012B185 66 0F 6F CD          movdqa      xmm1,xmm5  
  156. 0012B189 66 0F 3A 0F EC 0C    palignr     xmm5,xmm4,0Ch  
  157. 0012B18F 66 0F 7F 6F 20       movdqa      xmmword ptr [edi+20h],xmm5  
  158. 0012B194 8D 7F 30             lea         edi,[edi+30h]  
  159. 0012B197 7D B7                jge         CopyUp+0A0h (012B150h)  
  160. 0012B199 8D 76 0C             lea         esi,[esi+0Ch]  
  161.         jmp     PalignTail
  162. 0012B19C E9 AF 00 00 00       jmp         CopyUp+1A0h (012B250h)  

  163. PALIGN_memcpy 8
  164. 0012B1A1 66 0F 6F 4E F8       movdqa      xmm1,xmmword ptr [esi-8]  
  165. 0012B1A6 8D 76 F8             lea         esi,[esi-8]  
  166. 0012B1A9 8D 49 00             lea         ecx,[ecx]  
  167. PalignLoop8:
  168. 0012B1AC 66 0F 6F 5E 10       movdqa      xmm3,xmmword ptr [esi+10h]  
  169. 0012B1B1 83 E9 30             sub         ecx,30h  
  170. 0012B1B4 66 0F 6F 46 20       movdqa      xmm0,xmmword ptr [esi+20h]  
  171. 0012B1B9 66 0F 6F 6E 30       movdqa      xmm5,xmmword ptr [esi+30h]  
  172. 0012B1BE 8D 76 30             lea         esi,[esi+30h]  
  173. 0012B1C1 83 F9 30             cmp         ecx,30h  
  174. 0012B1C4 66 0F 6F D3          movdqa      xmm2,xmm3  
  175. 0012B1C8 66 0F 3A 0F D9 08    palignr     xmm3,xmm1,8  
  176. 0012B1CE 66 0F 7F 1F          movdqa      xmmword ptr [edi],xmm3  
  177. 0012B1D2 66 0F 6F E0          movdqa      xmm4,xmm0  
  178. 0012B1D6 66 0F 3A 0F C2 08    palignr     xmm0,xmm2,8  
  179. 0012B1DC 66 0F 7F 47 10       movdqa      xmmword ptr [edi+10h],xmm0  
  180. 0012B1E1 66 0F 6F CD          movdqa      xmm1,xmm5  
  181. 0012B1E5 66 0F 3A 0F EC 08    palignr     xmm5,xmm4,8  
  182. 0012B1EB 66 0F 7F 6F 20       movdqa      xmmword ptr [edi+20h],xmm5  
  183. 0012B1F0 8D 7F 30             lea         edi,[edi+30h]  
  184. 0012B1F3 7D B7                jge         CopyUp+0FCh (012B1ACh)  
  185. 0012B1F5 8D 76 08             lea         esi,[esi+8]  
  186.         jmp     PalignTail
  187. 0012B1F8 EB 56                jmp         CopyUp+1A0h (012B250h)  

  188. PALIGN_memcpy 4
  189. 0012B1FA 66 0F 6F 4E FC       movdqa      xmm1,xmmword ptr [esi-4]  
  190. 0012B1FF 8D 76 FC             lea         esi,[esi-4]  
  191. 0012B202 8B FF                mov         edi,edi  
  192. PalignLoop4:
  193. 0012B204 66 0F 6F 5E 10       movdqa      xmm3,xmmword ptr [esi+10h]  
  194. 0012B209 83 E9 30             sub         ecx,30h  
  195. 0012B20C 66 0F 6F 46 20       movdqa      xmm0,xmmword ptr [esi+20h]  
  196. 0012B211 66 0F 6F 6E 30       movdqa      xmm5,xmmword ptr [esi+30h]  
  197. 0012B216 8D 76 30             lea         esi,[esi+30h]  
  198. 0012B219 83 F9 30             cmp         ecx,30h  
  199. 0012B21C 66 0F 6F D3          movdqa      xmm2,xmm3  
  200. 0012B220 66 0F 3A 0F D9 04    palignr     xmm3,xmm1,4  
  201. 0012B226 66 0F 7F 1F          movdqa      xmmword ptr [edi],xmm3  
  202. 0012B22A 66 0F 6F E0          movdqa      xmm4,xmm0  
  203. 0012B22E 66 0F 3A 0F C2 04    palignr     xmm0,xmm2,4  
  204. 0012B234 66 0F 7F 47 10       movdqa      xmmword ptr [edi+10h],xmm0  
  205. 0012B239 66 0F 6F CD          movdqa      xmm1,xmm5  
  206. 0012B23D 66 0F 3A 0F EC 04    palignr     xmm5,xmm4,4  
  207. 0012B243 66 0F 7F 6F 20       movdqa      xmmword ptr [edi+20h],xmm5  
  208. 0012B248 8D 7F 30             lea         edi,[edi+30h]  
  209. 0012B24B 7D B7                jge         CopyUp+154h (012B204h)  
  210. 0012B24D 8D 76 04             lea         esi,[esi+4]  

  211. ;(3) Copy the tailing bytes.
  212. PalignTail:
  213.         cmp    ecx,10h
  214. 0012B250 83 F9 10             cmp         ecx,10h  
  215.         jl     PalignTail4
  216. 0012B253 7C 13                jl          CopyUp+1B8h (012B268h)  
  217.         movdqu xmm1,xmmword ptr [esi]
  218. 0012B255 F3 0F 6F 0E          movdqu      xmm1,xmmword ptr [esi]  
  219.         sub    ecx, 10h
  220. 0012B259 83 E9 10             sub         ecx,10h  
  221.         lea    esi, xmmword ptr [esi+10h]
  222. 0012B25C 8D 76 10             lea         esi,[esi+10h]  
  223.         movdqa xmmword ptr [edi],xmm1
  224. 0012B25F 66 0F 7F 0F          movdqa      xmmword ptr [edi],xmm1  
  225.         lea    edi, xmmword ptr [edi+10h]
  226. 0012B263 8D 7F 10             lea         edi,[edi+10h]  
  227.         jmp    PalignTail
  228. 0012B266 EB E8                jmp         CopyUp+1A0h (012B250h)  

  229. PalignTail4:
  230.         bt      ecx, 2
  231. 0012B268 0F BA E1 02          bt          ecx,2  
  232.         jae     PalignTail8
  233. 0012B26C 73 0D                jae         CopyUp+1CBh (012B27Bh)  
  234.         mov     eax, dword ptr [esi]
  235. 0012B26E 8B 06                mov         eax,dword ptr [esi]  
  236.         sub     ecx,4
  237. 0012B270 83 E9 04             sub         ecx,4  
  238.         lea     esi, byte ptr [esi+4]
  239. 0012B273 8D 76 04             lea         esi,[esi+4]  
  240.         mov     dword ptr [edi], eax
  241. 0012B276 89 07                mov         dword ptr [edi],eax  
  242.         lea     edi, byte ptr [edi+4]
  243. 0012B278 8D 7F 04             lea         edi,[edi+4]  

  244. PalignTail8:
  245.         bt      ecx, 3
  246. 0012B27B 0F BA E1 03          bt          ecx,3  
  247.         jae     PalignTailLE3
  248. 0012B27F 73 11                jae         CopyUp+1E2h (012B292h)  
  249.         movq    xmm1, qword ptr [esi]
  250. 0012B281 F3 0F 7E 0E          movq        xmm1,mmword ptr [esi]  
  251.         sub     ecx,8
  252. 0012B285 83 E9 08             sub         ecx,8  
  253.         lea     esi, byte ptr [esi+8]
  254. 0012B288 8D 76 08             lea         esi,[esi+8]  
  255.         movq    qword ptr [edi], xmm1
  256. 0012B28B 66 0F D6 0F          movq        mmword ptr [edi],xmm1  
  257.         lea     edi, byte ptr [edi+8]
  258. 0012B28F 8D 7F 08             lea         edi,[edi+8]  

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

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

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

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

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

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

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

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

  302.         align   @WordSize
  303. CopyLeadUp:

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

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

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

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

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

  323.         align   @WordSize
  324. CopyUnwindUp:
  325.         jmp     dword ptr UnwindUpVec[ecx*4] ;N - unwind dword copy
  326. 0012B2D8 FF 24 8D 5C B3 12 00 jmp         dword ptr [ecx*4+12B35Ch]  
  327. 0012B2DF 90                   nop
  328. --- 无源文件 -----------------------------------------------------------------------
  329. 0012B2E0 EC                   in          al,dx  
  330. 0012B2E1 B2 12                mov         dl,12h  
  331. 0012B2E3 00 18                add         byte ptr [eax],bl  
  332. 0012B2E5 B3 12                mov         bl,12h  
  333. 0012B2E7 00 3C B3             add         byte ptr [ebx+esi*4],bh  
  334. 0012B2EA 12 00                adc         al,byte ptr [eax]  
  335. LeadUp1:
  336. 0012B2EC 23 D1                and         edx,ecx  
  337. 0012B2EE 8A 06                mov         al,byte ptr [esi]  
  338. 0012B2F0 88 07                mov         byte ptr [edi],al  
  339. 0012B2F2 8A 46 01             mov         al,byte ptr [esi+1]  
  340. 0012B2F5 88 47 01             mov         byte ptr [edi+1],al  
  341. 0012B2F8 8A 46 02             mov         al,byte ptr [esi+2]  
  342. 0012B2FB C1 E9 02             shr         ecx,2  
  343. 0012B2FE 88 47 02             mov         byte ptr [edi+2],al  
  344. 0012B301 83 C6 03             add         esi,3  
  345. 0012B304 83 C7 03             add         edi,3  
  346. 0012B307 83 F9 08             cmp         ecx,8  
  347. 0012B30A 72 CC                jb          CopyUp+228h (012B2D8h)  
  348. 0012B30C F3 A5                rep movs    dword ptr es:[edi],dword ptr [esi]  
  349. 0012B30E FF 24 95 C8 B3 12 00 jmp         dword ptr [edx*4+12B3C8h]  
  350. 0012B315 8D 49 00             lea         ecx,[ecx]  
  351. LeadUp2:
  352. 0012B318 23 D1                and         edx,ecx  
  353. 0012B31A 8A 06                mov         al,byte ptr [esi]  
  354. 0012B31C 88 07                mov         byte ptr [edi],al  
  355. 0012B31E 8A 46 01             mov         al,byte ptr [esi+1]  
  356. 0012B321 C1 E9 02             shr         ecx,2  
  357. 0012B324 88 47 01             mov         byte ptr [edi+1],al  
  358. 0012B327 83 C6 02             add         esi,2  
  359. 0012B32A 83 C7 02             add         edi,2  
  360. 0012B32D 83 F9 08             cmp         ecx,8  
  361. 0012B330 72 A6                jb          CopyUp+228h (012B2D8h)  
  362. 0012B332 F3 A5                rep movs    dword ptr es:[edi],dword ptr [esi]  
  363. 0012B334 FF 24 95 C8 B3 12 00 jmp         dword ptr [edx*4+12B3C8h]  
  364. 0012B33B 90                   nop  
  365. LeadUp3:
  366. 0012B33C 23 D1                and         edx,ecx  
  367. 0012B33E 8A 06                mov         al,byte ptr [esi]  
  368. 0012B340 88 07                mov         byte ptr [edi],al  
  369. 0012B342 83 C6 01             add         esi,1  
  370. 0012B345 C1 E9 02             shr         ecx,2  
  371. 0012B348 83 C7 01             add         edi,1  
  372. 0012B34B 83 F9 08             cmp         ecx,8  
  373. 0012B34E 72 88                jb          CopyUp+228h (012B2D8h)  
  374. 0012B350 F3 A5                rep movs    dword ptr es:[edi],dword ptr [esi]  
  375. 0012B352 FF 24 95 C8 B3 12 00 jmp         dword ptr [edx*4+12B3C8h]  
  376. 0012B359 8D 49 00             lea         ecx,[ecx]  
  377. 0012B35C BF B3 12 00 AC       mov         edi,0AC0012B3h  
  378. 0012B361 B3 12                mov         bl,12h  
  379. 0012B363 00 A4 B3 12 00 9C B3 add         byte ptr [ebx+esi*4-4C63FFEEh],ah  
  380. 0012B36A 12 00                adc         al,byte ptr [eax]  
  381. 0012B36C 94                   xchg        eax,esp  
  382. 0012B36D B3 12                mov         bl,12h  
  383. 0012B36F 00 8C B3 12 00 84 B3 add         byte ptr [ebx+esi*4-4C7BFFEEh],cl  
  384. 0012B376 12 00                adc         al,byte ptr [eax]  
  385. 0012B378 7C B3                jl          LeadUpVec+4Dh (012B32Dh)  
  386. 0012B37A 12 00                adc         al,byte ptr [eax]  
  387. UnwindUp7:
  388. 0012B37C 8B 44 8E E4          mov         eax,dword ptr [esi+ecx*4-1Ch]  
  389. 0012B380 89 44 8F E4          mov         dword ptr [edi+ecx*4-1Ch],eax  
  390. UnwindUp6:
  391. 0012B384 8B 44 8E E8          mov         eax,dword ptr [esi+ecx*4-18h]  
  392. 0012B388 89 44 8F E8          mov         dword ptr [edi+ecx*4-18h],eax  
  393. UnwindUp5:
  394. 0012B38C 8B 44 8E EC          mov         eax,dword ptr [esi+ecx*4-14h]  
  395. 0012B390 89 44 8F EC          mov         dword ptr [edi+ecx*4-14h],eax  
  396. UnwindUp4:
  397. 0012B394 8B 44 8E F0          mov         eax,dword ptr [esi+ecx*4-10h]  
  398. 0012B398 89 44 8F F0          mov         dword ptr [edi+ecx*4-10h],eax  
  399. UnwindUp3:
  400. 0012B39C 8B 44 8E F4          mov         eax,dword ptr [esi+ecx*4-0Ch]  
  401. 0012B3A0 89 44 8F F4          mov         dword ptr [edi+ecx*4-0Ch],eax  
  402. UnwindUp2:
  403. 0012B3A4 8B 44 8E F8          mov         eax,dword ptr [esi+ecx*4-8]  
  404. 0012B3A8 89 44 8F F8          mov         dword ptr [edi+ecx*4-8],eax  
  405. UnwindUp1:
  406. 0012B3AC 8B 44 8E FC          mov         eax,dword ptr [esi+ecx*4-4]  
  407. 0012B3B0 89 44 8F FC          mov         dword ptr [edi+ecx*4-4],eax  
  408. 0012B3B4 8D 04 8D 00 00 00 00 lea         eax,[ecx*4]  
  409. 0012B3BB 03 F0                add         esi,eax  
  410. 0012B3BD 03 F8                add         edi,eax  
  411. UnwindUp0:
  412. 0012B3BF FF 24 95 C8 B3 12 00 jmp         dword ptr [edx*4+12B3C8h]  
  413. 0012B3C6 8B FF                mov         edi,edi  
  414. 0012B3C8 D8 B3 12 00 E0 B3    fdiv        dword ptr [ebx-4C1FFFEEh]  
  415. 0012B3CE 12 00                adc         al,byte ptr [eax]  
  416. 0012B3D0 EC                   in          al,dx  
  417. 0012B3D1 B3 12                mov         bl,12h  
  418. 0012B3D3 00 00                add         byte ptr [eax],al  
  419. 0012B3D5 B4 12                mov         ah,12h  
  420. 0012B3D7 00 8B 44 24 0C 5E    add         byte ptr [ebx+5E0C2444h],cl  
  421. 0012B3DD 5F                   pop         edi  
  422. 0012B3DE C3                   ret  
  423. 0012B3DF 90                   nop  
  424. TrailUp1:
  425. 0012B3E0 8A 06                mov         al,byte ptr [esi]  
  426. 0012B3E2 88 07                mov         byte ptr [edi],al  
  427. 0012B3E4 8B 44 24 0C          mov         eax,dword ptr [esp+0Ch]  
  428. 0012B3E8 5E                   pop         esi  
  429. 0012B3E9 5F                   pop         edi  
  430. 0012B3EA C3                   ret  
  431. 0012B3EB 90                   nop  
  432. TrailUp2:
  433. 0012B3EC 8A 06                mov         al,byte ptr [esi]  
  434. 0012B3EE 88 07                mov         byte ptr [edi],al  
  435. 0012B3F0 8A 46 01             mov         al,byte ptr [esi+1]  
  436. 0012B3F3 88 47 01             mov         byte ptr [edi+1],al  
  437. 0012B3F6 8B 44 24 0C          mov         eax,dword ptr [esp+0Ch]  
  438. 0012B3FA 5E                   pop         esi  
  439. 0012B3FB 5F                   pop         edi  
  440. 0012B3FC C3                   ret  
  441. 0012B3FD 8D 49 00             lea         ecx,[ecx]  
  442. TrailUp3:
  443. 0012B400 8A 06                mov         al,byte ptr [esi]  
  444. 0012B402 88 07                mov         byte ptr [edi],al  
  445. 0012B404 8A 46 01             mov         al,byte ptr [esi+1]  
  446. 0012B407 88 47 01             mov         byte ptr [edi+1],al  
  447. 0012B40A 8A 46 02             mov         al,byte ptr [esi+2]  
  448. 0012B40D 88 47 02             mov         byte ptr [edi+2],al  
  449. 0012B410 8B 44 24 0C          mov         eax,dword ptr [esp+0Ch]  
  450. 0012B414 5E                   pop         esi  
  451. 0012B415 5F                   pop         edi  
  452. 0012B416 C3                   ret  
  453. 0012B417 90                   nop  
  454. CopyDown:
  455. 0012B418 8D 74 31 FC          lea         esi,[ecx+esi-4]  
  456. 0012B41C 8D 7C 39 FC          lea         edi,[ecx+edi-4]  
  457. 0012B420 F7 C7 03 00 00 00    test        edi,3  
  458. 0012B426 75 24                jne         TrailUpVec+84h (012B44Ch)  
  459. 0012B428 C1 E9 02             shr         ecx,2  
  460. 0012B42B 83 E2 03             and         edx,3  
  461. 0012B42E 83 F9 08             cmp         ecx,8  
  462. 0012B431 72 0D                jb          TrailUpVec+78h (012B440h)  
  463. 0012B433 FD                   std  
  464. 0012B434 F3 A5                rep movs    dword ptr es:[edi],dword ptr [esi]  
  465. 0012B436 FC                   cld  
  466. 0012B437 FF 24 95 64 B5 12 00 jmp         dword ptr [edx*4+12B564h]  
  467. 0012B43E 8B FF                mov         edi,edi  
  468. CopyUnwindDown:
  469. 0012B440 F7 D9                neg         ecx  
  470. 0012B442 FF 24 8D 14 B5 12 00 jmp         dword ptr [ecx*4+12B514h]  
  471. 0012B449 8D 49 00             lea         ecx,[ecx]  
  472. CopyLeadDown:
  473. 0012B44C 8B C7                mov         eax,edi  
  474. 0012B44E BA 03 00 00 00       mov         edx,3  
  475. 0012B453 83 F9 04             cmp         ecx,4  
  476. 0012B456 72 0C                jb          TrailUpVec+9Ch (012B464h)  
  477. 0012B458 83 E0 03             and         eax,3  
  478. 0012B45B 2B C8                sub         ecx,eax  
  479. 0012B45D FF 24 85 68 B4 12 00 jmp         dword ptr [eax*4+12B468h]  
  480. ByteCopyDown:
  481. 0012B464 FF 24 8D 64 B5 12 00 jmp         dword ptr [ecx*4+12B564h]  
  482. 0012B46B 90                   nop  
  483. 0012B46C 78 B4                js          TrailUpVec+5Ah (012B422h)  
  484. 0012B46E 12 00                adc         al,byte ptr [eax]  
  485. 0012B470 9C                   pushfd  
  486. 0012B471 B4 12                mov         ah,12h  
  487. 0012B473 00 C4                add         ah,al  
  488. 0012B475 B4 12                mov         ah,12h  
  489. 0012B477 00 8A 46 03 23 D1    add         byte ptr [edx-2EDCFCBAh],cl  
  490. 0012B47D 88 47 03             mov         byte ptr [edi+3],al  
  491. 0012B480 83 EE 01             sub         esi,1  
  492. 0012B483 C1 E9 02             shr         ecx,2  
  493. 0012B486 83 EF 01             sub         edi,1  
  494. 0012B489 83 F9 08             cmp         ecx,8  
  495. 0012B48C 72 B2                jb          TrailUpVec+78h (012B440h)  
  496. 0012B48E FD                   std  
  497. 0012B48F F3 A5                rep movs    dword ptr es:[edi],dword ptr [esi]  
  498. 0012B491 FC                   cld  
  499. 0012B492 FF 24 95 64 B5 12 00 jmp         dword ptr [edx*4+12B564h]  
  500. 0012B499 8D 49 00             lea         ecx,[ecx]  
  501. LeadDown2:
  502. 0012B49C 8A 46 03             mov         al,byte ptr [esi+3]  
  503. 0012B49F 23 D1                and         edx,ecx  
  504. 0012B4A1 88 47 03             mov         byte ptr [edi+3],al  
  505. 0012B4A4 8A 46 02             mov         al,byte ptr [esi+2]  
  506. 0012B4A7 C1 E9 02             shr         ecx,2  
  507. 0012B4AA 88 47 02             mov         byte ptr [edi+2],al  
  508. 0012B4AD 83 EE 02             sub         esi,2  
  509. 0012B4B0 83 EF 02             sub         edi,2  
  510. 0012B4B3 83 F9 08             cmp         ecx,8  
  511. 0012B4B6 72 88                jb          TrailUpVec+78h (012B440h)  
  512. 0012B4B8 FD                   std  
  513. 0012B4B9 F3 A5                rep movs    dword ptr es:[edi],dword ptr [esi]  
  514. 0012B4BB FC                   cld  
  515. 0012B4BC FF 24 95 64 B5 12 00 jmp         dword ptr [edx*4+12B564h]  
  516. 0012B4C3 90                   nop  
  517. LeadDown3:
  518. 0012B4C4 8A 46 03             mov         al,byte ptr [esi+3]  
  519. 0012B4C7 23 D1                and         edx,ecx  
  520. 0012B4C9 88 47 03             mov         byte ptr [edi+3],al  
  521. 0012B4CC 8A 46 02             mov         al,byte ptr [esi+2]  
  522. 0012B4CF 88 47 02             mov         byte ptr [edi+2],al  
  523. 0012B4D2 8A 46 01             mov         al,byte ptr [esi+1]  
  524. 0012B4D5 C1 E9 02             shr         ecx,2  
  525. 0012B4D8 88 47 01             mov         byte ptr [edi+1],al  
  526. 0012B4DB 83 EE 03             sub         esi,3  
  527. 0012B4DE 83 EF 03             sub         edi,3  
  528. 0012B4E1 83 F9 08             cmp         ecx,8  
  529. 0012B4E4 0F 82 56 FF FF FF    jb          TrailUpVec+78h (012B440h)  
  530. 0012B4EA FD                   std  
  531. 0012B4EB F3 A5                rep movs    dword ptr es:[edi],dword ptr [esi]  
  532. 0012B4ED FC                   cld  
  533. 0012B4EE FF 24 95 64 B5 12 00 jmp         dword ptr [edx*4+12B564h]  
  534. 0012B4F5 8D 49 00             lea         ecx,[ecx]  
  535. 0012B4F8 18 B5 12 00 20 B5    sbb         byte ptr [ebp-4ADFFFEEh],dh  
  536. 0012B4FE 12 00                adc         al,byte ptr [eax]  
  537. 0012B500 28 B5 12 00 30 B5    sub         byte ptr [ebp-4ACFFFEEh],dh  
  538. 0012B506 12 00                adc         al,byte ptr [eax]  
  539. 0012B508 38 B5 12 00 40 B5    cmp         byte ptr [ebp-4ABFFFEEh],dh  
  540. 0012B50E 12 00                adc         al,byte ptr [eax]  
  541. 0012B510 48                   dec         eax  
  542. 0012B511 B5 12                mov         ch,12h  
  543. 0012B513 00 5B B5             add         byte ptr [ebx-4Bh],bl  
  544. 0012B516 12 00                adc         al,byte ptr [eax]  
  545. UnwindDown7:
  546. 0012B518 8B 44 8E 1C          mov         eax,dword ptr [esi+ecx*4+1Ch]  
  547. 0012B51C 89 44 8F 1C          mov         dword ptr [edi+ecx*4+1Ch],eax  
  548. UnwindDown6:
  549. 0012B520 8B 44 8E 18          mov         eax,dword ptr [esi+ecx*4+18h]  
  550. 0012B524 89 44 8F 18          mov         dword ptr [edi+ecx*4+18h],eax  
  551. UnwindDown5:
  552. 0012B528 8B 44 8E 14          mov         eax,dword ptr [esi+ecx*4+14h]  
  553. 0012B52C 89 44 8F 14          mov         dword ptr [edi+ecx*4+14h],eax  
  554. UnwindDown4:
  555. 0012B530 8B 44 8E 10          mov         eax,dword ptr [esi+ecx*4+10h]  
  556. 0012B534 89 44 8F 10          mov         dword ptr [edi+ecx*4+10h],eax  
  557. UnwindDown3:
  558. 0012B538 8B 44 8E 0C          mov         eax,dword ptr [esi+ecx*4+0Ch]  
  559. 0012B53C 89 44 8F 0C          mov         dword ptr [edi+ecx*4+0Ch],eax  
  560. UnwindDown2:
  561. 0012B540 8B 44 8E 08          mov         eax,dword ptr [esi+ecx*4+8]  
  562. 0012B544 89 44 8F 08          mov         dword ptr [edi+ecx*4+8],eax  
  563. UnwindDown1:
  564. 0012B548 8B 44 8E 04          mov         eax,dword ptr [esi+ecx*4+4]  
  565. 0012B54C 89 44 8F 04          mov         dword ptr [edi+ecx*4+4],eax  
  566. 0012B550 8D 04 8D 00 00 00 00 lea         eax,[ecx*4]  
  567. 0012B557 03 F0                add         esi,eax  
  568. 0012B559 03 F8                add         edi,eax  
  569. UnwindDown0:
  570. 0012B55B FF 24 95 64 B5 12 00 jmp         dword ptr [edx*4+12B564h]  
  571. 0012B562 8B FF                mov         edi,edi  
  572. 0012B564 74 B5                je          UnwindDownVec+23h (012B51Bh)  
  573. 0012B566 12 00                adc         al,byte ptr [eax]  
  574. 0012B568 7C B5                jl          UnwindDownVec+27h (012B51Fh)  
  575. 0012B56A 12 00                adc         al,byte ptr [eax]  
  576. 0012B56C 8C B5 12 00 A0 B5    mov         word ptr [ebp-4A5FFFEEh],st(-2)  
  577. 0012B572 12 00                adc         al,byte ptr [eax]  
  578. TrailDown0:
  579. 0012B574 8B 44 24 0C          mov         eax,dword ptr [esp+0Ch]  
  580. 0012B578 5E                   pop         esi  
  581. 0012B579 5F                   pop         edi  
  582. 0012B57A C3                   ret  
  583. 0012B57B 90                   nop  
  584. TrailDown1:
  585. 0012B57C 8A 46 03             mov         al,byte ptr [esi+3]  
  586. 0012B57F 88 47 03             mov         byte ptr [edi+3],al  
  587. 0012B582 8B 44 24 0C          mov         eax,dword ptr [esp+0Ch]  
  588. 0012B586 5E                   pop         esi  
  589. 0012B587 5F                   pop         edi  
  590. 0012B588 C3                   ret  
  591. 0012B589 8D 49 00             lea         ecx,[ecx]  
  592. TrailDown2:
  593. 0012B58C 8A 46 03             mov         al,byte ptr [esi+3]  
  594. 0012B58F 88 47 03             mov         byte ptr [edi+3],al  
  595. 0012B592 8A 46 02             mov         al,byte ptr [esi+2]  
  596. 0012B595 88 47 02             mov         byte ptr [edi+2],al  
  597. 0012B598 8B 44 24 0C          mov         eax,dword ptr [esp+0Ch]  
  598. 0012B59C 5E                   pop         esi  
  599. 0012B59D 5F                   pop         edi  
  600. 0012B59E C3                   ret  
  601. 0012B59F 90                   nop  
  602. TrailDown3:
  603. 0012B5A0 8A 46 03             mov         al,byte ptr [esi+3]  
  604. 0012B5A3 88 47 03             mov         byte ptr [edi+3],al  
  605. 0012B5A6 8A 46 02             mov         al,byte ptr [esi+2]  
  606. 0012B5A9 88 47 02             mov         byte ptr [edi+2],al  
  607. 0012B5AC 8A 46 01             mov         al,byte ptr [esi+1]  
  608. 0012B5AF 88 47 01             mov         byte ptr [edi+1],al  
  609. 0012B5B2 8B 44 24 0C          mov         eax,dword ptr [esp+0Ch]  
  610. 0012B5B6 5E                   pop         esi  
  611. 0012B5B7 5F                   pop         edi  
  612. 0012B5B8 C3                   ret  
  613. 0012B5B9 8D A4 24 00 00 00 00 lea         esp,[esp]  
  614. VEC_memcpy:
  615. 0012B5C0 57                   push        edi  
  616. 0012B5C1 8B C6                mov         eax,esi  
  617. 0012B5C3 83 E0 0F             and         eax,0Fh  
  618. 0012B5C6 85 C0                test        eax,eax  
  619. 0012B5C8 0F 85 D2 00 00 00    jne         TrailDownVec+13Ch (012B6A0h)  
  620. L_Aligned:
  621. 0012B5CE 8B D1                mov         edx,ecx  
  622. 0012B5D0 83 E1 7F             and         ecx,7Fh  
  623. 0012B5D3 C1 EA 07             shr         edx,7  
  624. 0012B5D6 74 65                je          TrailDownVec+0D9h (012B63Dh)  
  625. 0012B5D8 8D A4 24 00 00 00 00 lea         esp,[esp]  
  626. 0012B5DF 90                   nop  
  627. L_1:
  628. 0012B5E0 66 0F 6F 06          movdqa      xmm0,xmmword ptr [esi]  
  629. 0012B5E4 66 0F 6F 4E 10       movdqa      xmm1,xmmword ptr [esi+10h]  
  630. 0012B5E9 66 0F 6F 56 20       movdqa      xmm2,xmmword ptr [esi+20h]  
  631. 0012B5EE 66 0F 6F 5E 30       movdqa      xmm3,xmmword ptr [esi+30h]  
  632. 0012B5F3 66 0F 7F 07          movdqa      xmmword ptr [edi],xmm0  
  633. 0012B5F7 66 0F 7F 4F 10       movdqa      xmmword ptr [edi+10h],xmm1  
  634. 0012B5FC 66 0F 7F 57 20       movdqa      xmmword ptr [edi+20h],xmm2  
  635. 0012B601 66 0F 7F 5F 30       movdqa      xmmword ptr [edi+30h],xmm3  
  636. 0012B606 66 0F 6F 66 40       movdqa      xmm4,xmmword ptr [esi+40h]  
  637. 0012B60B 66 0F 6F 6E 50       movdqa      xmm5,xmmword ptr [esi+50h]  
  638. 0012B610 66 0F 6F 76 60       movdqa      xmm6,xmmword ptr [esi+60h]  
  639. 0012B615 66 0F 6F 7E 70       movdqa      xmm7,xmmword ptr [esi+70h]  
  640. 0012B61A 66 0F 7F 67 40       movdqa      xmmword ptr [edi+40h],xmm4  
  641. 0012B61F 66 0F 7F 6F 50       movdqa      xmmword ptr [edi+50h],xmm5  
  642. 0012B624 66 0F 7F 77 60       movdqa      xmmword ptr [edi+60h],xmm6  
  643. 0012B629 66 0F 7F 7F 70       movdqa      xmmword ptr [edi+70h],xmm7  
  644. 0012B62E 8D B6 80 00 00 00    lea         esi,[esi+80h]  
  645. 0012B634 8D BF 80 00 00 00    lea         edi,[edi+80h]  
  646. 0012B63A 4A                   dec         edx  
  647. 0012B63B 75 A3                jne         TrailDownVec+7Ch (012B5E0h)  
  648. L_1a:
  649. 0012B63D 85 C9                test        ecx,ecx  
  650. 0012B63F 74 4F                je          TrailDownVec+12Ch (012B690h)  
  651. 0012B641 8B D1                mov         edx,ecx  
  652. 0012B643 C1 EA 04             shr         edx,4  
  653. 0012B646 85 D2                test        edx,edx  
  654. 0012B648 74 17                je          TrailDownVec+0FDh (012B661h)  
  655. 0012B64A 8D 9B 00 00 00 00    lea         ebx,[ebx]  
  656. L_2:
  657. 0012B650 66 0F 6F 06          movdqa      xmm0,xmmword ptr [esi]  
  658. 0012B654 66 0F 7F 07          movdqa      xmmword ptr [edi],xmm0  
  659. 0012B658 8D 76 10             lea         esi,[esi+10h]  
  660. 0012B65B 8D 7F 10             lea         edi,[edi+10h]  
  661. 0012B65E 4A                   dec         edx  
  662. 0012B65F 75 EF                jne         TrailDownVec+0ECh (012B650h)  
  663. L_Trailing:
  664. 0012B661 83 E1 0F             and         ecx,0Fh  
  665. 0012B664 74 2A                je          TrailDownVec+12Ch (012B690h)  
  666. 0012B666 8B C1                mov         eax,ecx  
  667. 0012B668 C1 E9 02             shr         ecx,2  
  668. 0012B66B 74 0D                je          TrailDownVec+116h (012B67Ah)  
  669. L_TrailDword:
  670. 0012B66D 8B 16                mov         edx,dword ptr [esi]  
  671. 0012B66F 89 17                mov         dword ptr [edi],edx  
  672. 0012B671 8D 76 04             lea         esi,[esi+4]  
  673. 0012B674 8D 7F 04             lea         edi,[edi+4]  
  674. 0012B677 49                   dec         ecx  
  675. 0012B678 75 F3                jne         TrailDownVec+109h (012B66Dh)  
  676. L_TrailBytes:
  677. 0012B67A 8B C8                mov         ecx,eax  
  678. 0012B67C 83 E1 03             and         ecx,3  
  679. 0012B67F 74 0F                je          TrailDownVec+12Ch (012B690h)  
  680. L_TrailNextByte:
  681. 0012B681 8A 06                mov         al,byte ptr [esi]  
  682. 0012B683 88 07                mov         byte ptr [edi],al  
  683. 0012B685 46                   inc         esi  
  684. 0012B686 47                   inc         edi  
  685. 0012B687 49                   dec         ecx  
  686. 0012B688 75 F7                jne         TrailDownVec+11Dh (012B681h)  
  687. 0012B68A 8D 9B 00 00 00 00    lea         ebx,[ebx]  
  688. L_Return:
  689. 0012B690 58                   pop         eax  
  690. 0012B691 5E                   pop         esi  
  691. 0012B692 5F                   pop         edi  
  692. 0012B693 C3                   ret  
  693. 0012B694 8D A4 24 00 00 00 00 lea         esp,[esp]  
  694. 0012B69B EB 03                jmp         TrailDownVec+13Ch (012B6A0h)  
  695. 0012B69D CC                   int         3  
  696. 0012B69E CC                   int         3  
  697. 0012B69F CC                   int         3  
  698. L_Notaligned:
  699. 0012B6A0 BA 10 00 00 00       mov         edx,10h  
  700. 0012B6A5 2B D0                sub         edx,eax  
  701. 0012B6A7 2B CA                sub         ecx,edx  
  702. 0012B6A9 51                   push        ecx  
  703. 0012B6AA 8B C2                mov         eax,edx  
  704. 0012B6AC 8B C8                mov         ecx,eax  
  705. 0012B6AE 83 E1 03             and         ecx,3  
  706. 0012B6B1 74 09                je          TrailDownVec+158h (012B6BCh)  
  707. L_Byte:
  708. 0012B6B3 8A 16                mov         dl,byte ptr [esi]  
  709. 0012B6B5 88 17                mov         byte ptr [edi],dl  
  710. 0012B6B7 46                   inc         esi  
  711. 0012B6B8 47                   inc         edi  
  712. 0012B6B9 49                   dec         ecx  
  713. 0012B6BA 75 F7                jne         TrailDownVec+14Fh (012B6B3h)  
  714. L_MovDword:
  715. 0012B6BC C1 E8 02             shr         eax,2  
  716. 0012B6BF 74 0D                je          TrailDownVec+16Ah (012B6CEh)  
  717. L_Dword:
  718. 0012B6C1 8B 16                mov         edx,dword ptr [esi]  
  719. 0012B6C3 89 17                mov         dword ptr [edi],edx  
  720. 0012B6C5 8D 76 04             lea         esi,[esi+4]  
  721. 0012B6C8 8D 7F 04             lea         edi,[edi+4]  
  722. 0012B6CB 48                   dec         eax  
  723. 0012B6CC 75 F3                jne         TrailDownVec+15Dh (012B6C1h)  
  724. L_Adjustcnt:
  725. 0012B6CE 59                   pop         ecx  
  726. 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函数,根据数据的量的大小对齐的情况,对每一种情况都进行了优化处理,各方面证明了它是无可替代的。不是什么时候,自己造的轮子都比别人的好。

本帖被以下淘专辑推荐:

回复

使用道具 举报

85

主题

175

回帖

3990

积分

用户组: 超级版主

No. 418

UID
418
精华
14
威望
53 点
宅币
1974 个
贡献
1582 次
宅之契约
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.
回复 赞! 靠!

使用道具 举报

30

主题

211

回帖

2792

积分

用户组: 版主

UID
1821
精华
7
威望
69 点
宅币
2172 个
贡献
206 次
宅之契约
0 份
在线时间
482 小时
注册时间
2016-7-12
发表于 2017-5-30 23:30:45 | 显示全部楼层
  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 cruntime.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.         jge     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             ;U - save edi
  131.         push    esi             ;V - save esi

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

  134.         mov     esi,[esp + 010h]     ;U - esi = source
  135.         mov     ecx,[esp + 014h]     ;V - ecx = number of bytes to move
  136.         mov     edi,[esp + 0Ch]      ;U - 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         ;V - eax = byte count...

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

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

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

  151. ;
  152. ; Copy toward higher addresses.
  153. ;
  154. CopyUp:
  155. ;
  156.         ; See if Enhanced Fast Strings is supported.
  157.         ; ENFSTRG supported?
  158.         bt      __favor, __FAVOR_ENFSTRG
  159.         jnc     CopyUpSSE2Check                 ; no jump
  160.         ;
  161.         ; use Enhanced Fast Strings
  162.         rep     movsb
  163.         jmp     TrailUp0         ; Done
  164. CopyUpSSE2Check:
  165. ;
  166. ; Next, see if we can use a "fast" copy SSE2 routine
  167.         ; block size greater than min threshold?
  168.         cmp     ecx,080h
  169.         jb      Dword_align  ; length too small go use dwords
  170.         ; alignments equal?
  171.         mov     eax,edi
  172.         xor     eax,esi
  173.         test    eax,15
  174.         jne     AtomChk   ; Not aligned go check Atom
  175.         bt      __isa_enabled, __ISA_AVAILABLE_SSE2
  176.         jc      VEC_memcpy ; yes, go SSE2 copy (params already set)
  177. AtomChk:
  178.         ; Is Atom supported?
  179.         bt      __favor, __FAVOR_ATOM
  180.         jnc     Dword_align ; no,jump

  181.         ; check if dst is 4 byte aligned
  182.         test    edi, 3
  183.         jne     CopyLeadUp

  184.         ; check if src is 4 byte aligned
  185.         test    esi, 3
  186.         jne     Dword_align_Ok

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

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

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

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

  212. PALIGN_memcpy 12
  213.         jmp     PalignTail

  214. PALIGN_memcpy 8
  215.         jmp     PalignTail

  216. PALIGN_memcpy 4

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

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

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

  243. PalignTailLE3:
  244.         mov     eax, dword ptr TrailUpVec[ecx*4]
  245.         jmp     eax

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

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

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

  262.         rep     movsd           ;N - move all of our dwords

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

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

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

  275.         align   @WordSize
  276. CopyLeadUp:

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

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

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

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

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

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

  290.         align   @WordSize
  291. LeadUpVec       dd      LeadUp1, LeadUp2, LeadUp3

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

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

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

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

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

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

  306.         rep     movsd           ;N - move all of our dwords

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

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

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

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

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

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

  320.         rep     movsd           ;N - move all of our dwords

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

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

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

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

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

  332.         rep     movsd           ;N - move all of our dwords

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

  334.         align   @WordSize
  335. UnwindUpVec     dd      UnwindUp0, UnwindUp1, UnwindUp2, UnwindUp3
  336.                 dd      UnwindUp4, UnwindUp5, UnwindUp6, UnwindUp7

  337. UnwindUp7:
  338.         mov     eax,[esi+ecx*4-28] ;U - get dword from source
  339.                                    ;V - spare
  340.         mov     [edi+ecx*4-28],eax ;U - put dword into destination
  341. UnwindUp6:
  342.         mov     eax,[esi+ecx*4-24] ;U(entry)/V(not) - get dword from source
  343.                                    ;V(entry) - spare
  344.         mov     [edi+ecx*4-24],eax ;U - put dword into destination
  345. UnwindUp5:
  346.         mov     eax,[esi+ecx*4-20] ;U(entry)/V(not) - get dword from source
  347.                                    ;V(entry) - spare
  348.         mov     [edi+ecx*4-20],eax ;U - put dword into destination
  349. UnwindUp4:
  350.         mov     eax,[esi+ecx*4-16] ;U(entry)/V(not) - get dword from source
  351.                                    ;V(entry) - spare
  352.         mov     [edi+ecx*4-16],eax ;U - put dword into destination
  353. UnwindUp3:
  354.         mov     eax,[esi+ecx*4-12] ;U(entry)/V(not) - get dword from source
  355.                                    ;V(entry) - spare
  356.         mov     [edi+ecx*4-12],eax ;U - put dword into destination
  357. UnwindUp2:
  358.         mov     eax,[esi+ecx*4-8] ;U(entry)/V(not) - get dword from source
  359.                                   ;V(entry) - spare
  360.         mov     [edi+ecx*4-8],eax ;U - put dword into destination
  361. UnwindUp1:
  362.         mov     eax,[esi+ecx*4-4] ;U(entry)/V(not) - get dword from source
  363.                                   ;V(entry) - spare
  364.         mov     [edi+ecx*4-4],eax ;U - put dword into destination

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

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

  370. ;-----------------------------------------------------------------------------

  371.         align   @WordSize
  372. TrailUpVec      dd      TrailUp0, TrailUp1, TrailUp2, TrailUp3

  373.         align   @WordSize
  374. TrailUp0:
  375.         mov     eax,[esp + 0Ch] ;U - return pointer to destination
  376.         pop     esi             ;V - restore esi
  377.         pop     edi             ;U - restore edi
  378.                                 ;V - spare
  379.         M_EXIT

  380.         align   @WordSize
  381. TrailUp1:
  382.         mov     al,[esi]        ;U - get byte from source
  383.                                 ;V - spare
  384.         mov     [edi],al        ;U - put byte in destination
  385.         mov     eax,[esp + 0Ch] ;V - return pointer to destination
  386.         pop     esi             ;U - restore esi
  387.         pop     edi             ;V - restore edi
  388.         M_EXIT

  389.         align   @WordSize
  390. TrailUp2:
  391.         mov     al,[esi]        ;U - get first byte from source
  392.                                 ;V - spare
  393.         mov     [edi],al        ;U - put first byte into destination
  394.         mov     al,[esi+1]      ;V - get second byte from source
  395.         mov     [edi+1],al      ;U - put second byte into destination
  396.         mov     eax,[esp + 0Ch] ;V - return pointer to destination
  397.         pop     esi             ;U - restore esi
  398.         pop     edi             ;V - restore edi
  399.         M_EXIT

  400.         align   @WordSize
  401. TrailUp3:
  402.         mov     al,[esi]        ;U - get first byte from source
  403.                                 ;V - spare
  404.         mov     [edi],al        ;U - put first byte into destination
  405.         mov     al,[esi+1]      ;V - get second byte from source
  406.         mov     [edi+1],al      ;U - put second byte into destination
  407.         mov     al,[esi+2]      ;V - get third byte from source
  408.         mov     [edi+2],al      ;U - put third byte into destination
  409.         mov     eax,[esp + 0Ch] ;V - return pointer to destination
  410.         pop     esi             ;U - restore esi
  411.         pop     edi             ;V - restore edi
  412.         M_EXIT

  413. ;-----------------------------------------------------------------------------
  414. ;-----------------------------------------------------------------------------
  415. ;-----------------------------------------------------------------------------

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

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

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

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

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

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

  436.         align   @WordSize
  437. CopyUnwindDown:
  438.         neg     ecx             ;U - negate dword count for table merging
  439.                                 ;V - spare

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

  441.         align   @WordSize
  442. CopyLeadDown:

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

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

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

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

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

  453.         align   @WordSize
  454. LeadDownVec     dd      LeadDown1, LeadDown2, LeadDown3

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  503. ;------------------------------------------------------------------

  504.         align   @WordSize
  505. UnwindDownVec   dd      UnwindDown7, UnwindDown6, UnwindDown5, UnwindDown4
  506.                 dd      UnwindDown3, UnwindDown2, UnwindDown1, UnwindDown0

  507. UnwindDown7:
  508.         mov     eax,[esi+ecx*4+28] ;U - get dword from source
  509.                                    ;V - spare
  510.         mov     [edi+ecx*4+28],eax ;U - put dword into destination
  511. UnwindDown6:
  512.         mov     eax,[esi+ecx*4+24] ;U(entry)/V(not) - get dword from source
  513.                                    ;V(entry) - spare
  514.         mov     [edi+ecx*4+24],eax ;U - put dword into destination
  515. UnwindDown5:
  516.         mov     eax,[esi+ecx*4+20] ;U(entry)/V(not) - get dword from source
  517.                                    ;V(entry) - spare
  518.         mov     [edi+ecx*4+20],eax ;U - put dword into destination
  519. UnwindDown4:
  520.         mov     eax,[esi+ecx*4+16] ;U(entry)/V(not) - get dword from source
  521.                                    ;V(entry) - spare
  522.         mov     [edi+ecx*4+16],eax ;U - put dword into destination
  523. UnwindDown3:
  524.         mov     eax,[esi+ecx*4+12] ;U(entry)/V(not) - get dword from source
  525.                                    ;V(entry) - spare
  526.         mov     [edi+ecx*4+12],eax ;U - put dword into destination
  527. UnwindDown2:
  528.         mov     eax,[esi+ecx*4+8] ;U(entry)/V(not) - get dword from source
  529.                                    ;V(entry) - spare
  530.         mov     [edi+ecx*4+8],eax ;U - put dword into destination
  531. UnwindDown1:
  532.         mov     eax,[esi+ecx*4+4] ;U(entry)/V(not) - get dword from source
  533.                                   ;V(entry) - spare
  534.         mov     [edi+ecx*4+4],eax ;U - put dword into destination

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

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

  540. ;-----------------------------------------------------------------------------

  541.         align   @WordSize
  542. TrailDownVec    dd      TrailDown0, TrailDown1, TrailDown2, TrailDown3

  543.         align   @WordSize
  544. TrailDown0:
  545.         mov     eax,[esp + 0Ch] ;U - return pointer to destination
  546.                                 ;V - spare
  547.         pop     esi             ;U - restore esi
  548.         pop     edi             ;V - restore edi
  549.         M_EXIT

  550.         align   @WordSize
  551. TrailDown1:
  552.         mov     al,[esi+3]      ;U - get byte from source
  553.                                 ;V - spare
  554.         mov     [edi+3],al      ;U - put byte in destination
  555.         mov     eax,[esp + 0Ch] ;V - return pointer to destination
  556.         pop     esi             ;U - restore esi
  557.         pop     edi             ;V - restore edi
  558.         M_EXIT

  559.         align   @WordSize
  560. TrailDown2:
  561.         mov     al,[esi+3]      ;U - get first byte from source
  562.                                 ;V - spare
  563.         mov     [edi+3],al      ;U - put first byte into destination
  564.         mov     al,[esi+2]      ;V - get second byte from source
  565.         mov     [edi+2],al      ;U - put second byte into destination
  566.         mov     eax,[esp + 0Ch] ;V - return pointer to destination
  567.         pop     esi             ;U - restore esi
  568.         pop     edi             ;V - restore edi
  569.         M_EXIT

  570.         align   @WordSize
  571. TrailDown3:
  572.         mov     al,[esi+3]      ;U - get first byte from source
  573.                                 ;V - spare
  574.         mov     [edi+3],al      ;U - put first byte into destination
  575.         mov     al,[esi+2]      ;V - get second byte from source
  576.         mov     [edi+2],al      ;U - put second byte into destination
  577.         mov     al,[esi+1]      ;V - get third byte from source
  578.         mov     [edi+1],al      ;U - put third byte into destination
  579.         mov     eax,[esp + 0Ch] ;V - return pointer to destination
  580.         pop     esi             ;U - restore esi
  581.         pop     edi             ;V - restore edi
  582.         M_EXIT


  583. align       16
  584. VEC_memcpy:
  585.         push        edi         ; save dst for returning
  586.         mov         eax, esi
  587.         and         eax, 0Fh
  588.         ; eax = src and dst alignment (src mod 16)
  589.         test        eax, eax
  590.         jne         L_Notaligned

  591.         ; in:
  592.         ;  edi = dst (16 byte aligned)
  593.         ;  esi = src (16 byte aligned)
  594.         ;  ecx = len is >= (128 - head alignment bytes)
  595.         ; do block copy using SSE2 stores
  596. L_Aligned:
  597.         mov         edx, ecx
  598.         and         ecx, 7Fh
  599.         shr         edx, 7
  600.         je          L_1a
  601.         ; ecx = loop count
  602.         ; edx = remaining copy length
  603. align       16
  604. L_1:
  605.         movdqa      xmm0,xmmword ptr [esi]
  606.         movdqa      xmm1,xmmword ptr [esi + 10h]
  607.         movdqa      xmm2,xmmword ptr [esi + 20h]
  608.         movdqa      xmm3,xmmword ptr [esi + 30h]
  609.         movdqa      xmmword ptr [edi],xmm0
  610.         movdqa      xmmword ptr [edi + 10h],xmm1
  611.         movdqa      xmmword ptr [edi + 20h],xmm2
  612.         movdqa      xmmword ptr [edi + 30h],xmm3
  613.         movdqa      xmm4,xmmword ptr [esi + 40h]
  614.         movdqa      xmm5,xmmword ptr [esi + 50h]
  615.         movdqa      xmm6,xmmword ptr [esi + 60h]
  616.         movdqa      xmm7,xmmword ptr [esi + 70h]
  617.         movdqa      xmmword ptr [edi + 40h],xmm4
  618.         movdqa      xmmword ptr [edi + 50h],xmm5
  619.         movdqa      xmmword ptr [edi + 60h],xmm6
  620.         movdqa      xmmword ptr [edi + 70h],xmm7
  621.         lea         esi,[esi + 80h]
  622.         lea         edi,[edi + 80h]
  623.         dec         edx
  624.         jne         L_1
  625. L_1a:
  626.         test        ecx, ecx
  627.         je          L_Return

  628.         ; ecx = length (< 128 bytes)
  629.         mov         edx, ecx
  630.         shr         edx, 4
  631.         test        edx, edx
  632.         je          L_Trailing
  633.         ; if > 16 bytes do a loop (16 bytes at a time)
  634.         ; edx - loop count
  635.         ; edi = dst
  636.         ; esi = src
  637. align 16
  638. L_2:
  639.         movdqa      xmm0, xmmword ptr [esi]
  640.         movdqa      xmmword ptr [edi], xmm0
  641.         lea         esi, [esi + 10h]
  642.         lea         edi, [edi + 10h]
  643.         dec         edx
  644.         jne         L_2

  645. L_Trailing:

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

  653.         ; get dword aligned
  654.         mov     eax, ecx  ; save remaining len and calc number of dwords
  655.         shr     ecx, 2
  656.         je      L_TrailBytes ; if none try bytes
  657. L_TrailDword:
  658.         mov     edx, dword ptr [esi]
  659.         mov     dword ptr [edi], edx
  660.         lea     esi, [esi+4]
  661.         lea     edi, [edi+4]
  662.         dec     ecx
  663.         jne     L_TrailDword
  664. L_TrailBytes:
  665.         mov     ecx, eax
  666.         and     ecx, 03h
  667.         je      L_Return ; if none return
  668. L_TrailNextByte:
  669.         mov     al, byte ptr [esi]
  670.         mov     byte ptr [edi], al
  671.         inc     esi
  672.         inc     edi
  673.         dec     ecx
  674.         jne     L_TrailNextByte
  675. align 16
  676. L_Return:
  677.         ; return dst
  678.         pop     eax      ; Get destination for return
  679.         pop     esi
  680.         pop     edi
  681.         M_EXIT

  682. ; dst addr is not 16 byte aligned
  683. align 16
  684. L_Notaligned:

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

  686. ; in
  687. ; esi = src
  688. ; edi = dst
  689. ; eax = src and dst alignment
  690. ; ecx = length

  691.         mov     edx, 010h
  692.         sub     edx, eax   ; calc num bytes to get it aligned
  693.         sub     ecx, edx   ; calc new length and save it
  694.         push    ecx
  695.         mov     eax, edx   ; save alignment byte count for dwords
  696.         mov     ecx, eax   ; set exc to rep count
  697.         and     ecx, 03h
  698.         je      L_MovDword ; if no bytes go do dwords
  699. L_Byte:
  700.         mov     dl, byte ptr [esi]  ; move the bytes
  701.         mov     byte ptr [edi], dl
  702.         inc     esi       ; inc the adrs
  703.         inc     edi
  704.         dec     ecx       ; dec the counter
  705.         jne     L_Byte
  706. L_MovDword:
  707.         shr     eax, 2     ; get dword count
  708.         je      L_Adjustcnt ; if none go to main loop
  709. L_Dword:
  710.         mov     edx, dword ptr [esi] ; move the dwords
  711.         mov     dword ptr [edi], edx
  712.         lea     esi, [esi+4] ; inc the adrs
  713.         lea     edi, [edi+4]
  714.         dec     eax          ; dec the counter
  715.         jne     L_Dword
  716. L_Adjustcnt:
  717.         pop     ecx       ; retrive the adjusted length
  718.         jmp     L_Aligned


  719. _MEM_   endp
  720.         end

复制代码
回复 赞! 靠!

使用道具 举报

30

主题

211

回帖

2792

积分

用户组: 版主

UID
1821
精华
7
威望
69 点
宅币
2172 个
贡献
206 次
宅之契约
0 份
在线时间
482 小时
注册时间
2016-7-12
发表于 2017-5-30 23:35:16 | 显示全部楼层
本帖最后由 Ayala 于 2017-5-30 23:57 编辑
  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. include ksamd64.inc
  16.         subttl  "memcpy"

  17. ;***
  18. ;memcpy - Copy source buffer to destination buffer
  19. ;
  20. ;Purpose:
  21. ;       memcpy() copies a source memory buffer to a destination memory buffer.
  22. ;       This routine does NOT recognize overlapping buffers, and thus can lead
  23. ;       to propogation.
  24. ;       For cases where propogation must be avoided, memmove() must be used.
  25. ;
  26. ;       Algorithm:
  27. ;
  28. ;       void * memcpy(void * dst, void * src, size_t count)
  29. ;       {
  30. ;               void * ret = dst;
  31. ;
  32. ;               /*
  33. ;                * copy from lower addresses to higher addresses
  34. ;                */
  35. ;               while (count--)
  36. ;                       *dst++ = *src++;
  37. ;
  38. ;               return(ret);
  39. ;       }
  40. ;
  41. ;memmove - Copy source buffer to destination buffer
  42. ;
  43. ;Purpose:
  44. ;       memmove() copies a source memory buffer to a destination memory buffer.
  45. ;       This routine recognize overlapping buffers to avoid propogation.
  46. ;       For cases where propogation is not a problem, memcpy() can be used.
  47. ;
  48. ;   Algorithm:
  49. ;
  50. ;       void * memmove(void * dst, void * src, size_t count)
  51. ;       {
  52. ;               void * ret = dst;
  53. ;
  54. ;               if (dst <= src || dst >= (src + count)) {
  55. ;                       /*
  56. ;                        * Non-Overlapping Buffers
  57. ;                        * copy from lower addresses to higher addresses
  58. ;                        */
  59. ;                       while (count--)
  60. ;                               *dst++ = *src++;
  61. ;                       }
  62. ;               else {
  63. ;                       /*
  64. ;                        * Overlapping Buffers
  65. ;                        * copy from higher addresses to lower addresses
  66. ;                        */
  67. ;                       dst += count - 1;
  68. ;                       src += count - 1;
  69. ;
  70. ;                       while (count--)
  71. ;                               *dst-- = *src--;
  72. ;                       }
  73. ;
  74. ;               return(ret);
  75. ;       }
  76. ;
  77. ;
  78. ;Entry:
  79. ;       void *dst = pointer to destination buffer
  80. ;       const void *src = pointer to source buffer
  81. ;       size_t count = number of bytes to copy
  82. ;
  83. ;Exit:
  84. ;       Returns a pointer to the destination buffer in AX/DX:AX
  85. ;
  86. ;Uses:
  87. ;       CX, DX
  88. ;
  89. ;Exceptions:
  90. ;*******************************************************************************
  91.         extrn   __favor:dword
  92.         extrn   __ImageBase:byte
  93.         extrn   __memcpy_nt_iters:qword     ; defined in cpu_disp.c

  94. __FAVOR_ENFSTRG equ 1

  95.         public memmove

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

  97.         OPTION PROLOGUE:NONE, EPILOGUE:NONE

  98.         memmove = memcpy

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

  111. CopyUp:
  112.         cmp     r8, 128
  113.         jbe     XmmCopySmall

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

  116.         ; use Enhanced Fast Strings
  117.         ; but first align the destination dst to 16 byte alignment
  118.         mov     rax, r11                ; return original destination pointer
  119.         mov     r11, rdi                ; save rdi in r11
  120.         mov     rdi, rcx                ; move destination pointer to rdi
  121.         mov     rcx, r8                 ; move length to rcx
  122.         mov     r8, rsi                 ; save rsi in r8
  123.         mov     rsi, r10                ; move source pointer to rsi
  124.         rep     movsb                   ; copy source to destination buffer
  125.         mov     rsi, r8                 ; restore rsi
  126.         mov     rdi, r11                ; restore rdi
  127.         ret

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

  149. Move17to32:
  150.         movups  xmm0, [rdx]             ; load first 16 bytes of src
  151.         movups  xmm1, (-16)[rdx + r8]   ; load last 16 bytes of src
  152.         movups  [rcx], xmm0             ; store first 16 bytes of dst
  153.         movups  (-16)[rcx + r8], xmm1   ; store last 16 bytes of dst
  154.         mov     rax, rcx                ; set destination address
  155.         ret

  156. ;
  157. ; Move residual bytes.
  158. ;

  159.         align   16

  160. MoveBytes16:
  161.          mov    rax, rcx                ; mov destination address to rax
  162.          lea    r9, OFFSET __ImageBase
  163.          mov    ecx, [(IMAGEREL  MoveSmall) + r9 +r8*4]
  164.          add    rcx, r9
  165.          jmp    rcx

  166. MoveSmall dd  IMAGEREL MoveSmall0
  167.           dd  IMAGEREL MoveSmall1
  168.           dd  IMAGEREL MoveSmall2
  169.           dd  IMAGEREL MoveSmall3
  170.           dd  IMAGEREL MoveSmall4
  171.           dd  IMAGEREL MoveSmall5
  172.           dd  IMAGEREL MoveSmall6
  173.           dd  IMAGEREL MoveSmall7
  174.           dd  IMAGEREL MoveSmall8
  175.           dd  IMAGEREL MoveSmall9
  176.           dd  IMAGEREL MoveSmall10
  177.           dd  IMAGEREL MoveSmall11
  178.           dd  IMAGEREL MoveSmall12
  179.           dd  IMAGEREL MoveSmall13
  180.           dd  IMAGEREL MoveSmall14
  181.           dd  IMAGEREL MoveSmall15
  182.           dd  IMAGEREL MoveSmall16

  183.         align   16

  184. MoveSmall0::
  185.         ret

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

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

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

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

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

  208.         align   16
  209. MoveSmall11::
  210.         mov     r8, qword ptr [rdx]     ; get eight bytes from source
  211.         movzx   ecx, word ptr 8[rdx]    ; get two bytes from source
  212.         movzx   r9d, byte ptr 10[rdx]   ; get last byte from source
  213.         mov     [rax], r8               ; write eight bytes to destination
  214.         mov     8[rax], cx              ; write two bytes to destination
  215.         mov     10[rax], r9b            ; write last byte to destination
  216.         mov     rcx, r11                ; set destination address
  217.         ret

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

  222.         align   16
  223. MoveSmall5::
  224.         mov     ecx, dword ptr [rdx]    ; get four bytes from source
  225.         movzx   r8d, byte ptr 4[rdx]    ; get last byte from source
  226.         mov     [rax], ecx              ; write four bytes to destination
  227.         mov     4[rax], r8b             ; write last byte to destination
  228.         ret

  229.         align   16
  230. MoveSmall6::
  231.         mov     ecx, dword ptr [rdx]    ; get four bytes from source
  232.         movzx   r8d, word ptr 4[rdx]    ; get two bytes from source
  233.         mov     [rax], ecx              ; write four bytes to destination
  234.         mov     4[rax], r8w             ; write two bytes to destination
  235.         ret

  236.         align   16
  237. MoveSmall7::
  238.         mov     ecx, dword ptr [rdx]    ; get four bytes from source
  239.         movzx   r8d, word ptr 4[rdx]    ; get two bytes from source
  240.         movzx   r9d, byte ptr 6[rdx]    ; get last byte from source
  241.         mov     [rax], ecx              ; write four bytes to destination
  242.         mov     4[rax], r8w             ; write two bytes to destination
  243.         mov     6[rax], r9b             ; write last byte to destination
  244.         ret

  245. MoveSmall13::
  246.         mov     r8, qword ptr [rdx]     ; get eight bytes from source
  247.         mov     ecx, dword ptr 8[rdx]   ; get four bytes from source
  248.         movzx   r9d, byte ptr 12[rdx]   ; get last bytes from source
  249.         mov     [rax], r8               ; write eight bytes to destination
  250.         mov     8[rax], ecx             ; write four bytes  to destination
  251.         mov     12[rax], r9b            ; write last byte to destination
  252.         ret

  253.         align   16
  254. MoveSmall9::
  255.         mov     r8, qword ptr [rdx]     ; get eight bytes from source
  256.         movzx   ecx, byte ptr 8[rdx]    ; get last byte from source
  257.         mov     [rax], r8               ; write eight bytes to destination
  258.         mov     8[rax], cl              ; write last byte to destination
  259.         ret

  260.         align   16
  261. MoveSmall10::
  262.         mov     r8, qword ptr [rdx]     ; get eight bytes from source
  263.         movzx   ecx, word ptr 8[rdx]    ; get two bytes from source
  264.         mov     [rax], r8               ; write eight bytes to destination
  265.         mov     8[rax], cx              ; write two bytes to destination
  266.         ret

  267.         align   16
  268. MoveSmall12::
  269.         mov     r8, qword ptr [rdx]     ; get eight bytes from source
  270.         mov     ecx, dword ptr 8[rdx]   ; get four bytes from source
  271.         mov     [rax], r8               ; write eight bytes to destination
  272.         mov     8[rax], ecx             ; write four bytes to destination
  273.         ret

  274.         align   16
  275. MoveSmall14::
  276.         mov     r8, qword ptr [rdx]     ; get eight bytes from source
  277.         mov     ecx, dword ptr 8[rdx]   ; get four bytes from source
  278.         movzx   r9d, word ptr 12[rdx]   ; get two bytes from source
  279.         mov     [rax], r8               ; write eight bytes to destination
  280.         mov     8[rax], ecx             ; write four bytes to destination
  281.         mov     12[rax], r9w            ; write two bytes to destination
  282.         ret

  283.         align   16
  284. MoveSmall15::
  285.         mov     r8, qword ptr [rdx]     ; get eight bytes from source
  286.         mov     ecx, dword ptr 8[rdx]   ; get four bytes from source
  287.         movzx   r9d, word ptr 12[rdx]   ; get two bytes from source
  288.         movzx   r10d, byte ptr 14[rdx]  ; get last byte from source
  289.         mov     [rax], r8               ; write eight bytes to destination
  290.         mov     8[rax], ecx             ; write four bytes to destination
  291.         mov     12[rax], r9w            ; write two bytes to destination
  292.         mov     14[rax], r10b           ; write last byte to destination
  293.         ret

  294. ;
  295. ; Memcpy up using SSE instructions.
  296. ;
  297. ; Preconditions:
  298. ;       destination in rcx (destructable) and r11 (must preserve for return value)
  299. ;       source in r10
  300. ;       length in r8, must be greater than 16
  301. ;       offset from dest to src in rdx
  302. ;       source addr > dest addr or else buffers don't overlap
  303. ;
  304. ; Aligned stores are much faster on AMD hardware, so start by moving however many
  305. ; bytes must be moved so updated dst is 16-byte aligned. We need to copy
  306. ; (16 - (dest mod 16)) bytes, but it's faster to just do an unaligned copy of 16
  307. ; bytes and then start the aligned loop as usual at ((dest - (dest mod 16)) + 16).
  308. ; This results in (dest mod 16) bytes being copied twice. This is a lot faster
  309. ; than a bunch of code to copy maybe 1 then maybe 2 then maybe 4 then maybe 8
  310. ; bytes to achieve dst alignement.
  311. ;
  312. ; We know the src address is greater than the dst, but not by how much. In the
  313. ; case where the difference is less than 16 we must be careful about the bytes
  314. ; that will be stored twice. We must do both loads before either store, or the
  315. ; second load of those bytes will get the wrong values. We handle this by
  316. ; loading the last 16 bytes that can be stored at an aligned address, but
  317. ; deferring the store of those bytes to the remainder code, so it can load the
  318. ; remainder before storing the deferred bytes. Since either or both of the two
  319. ; loops can be skipped, the preconditions needed by the remainder  code must
  320. ; also apply to the loops. These conditions are:
  321. ;  - r8 is the count remaining, not including the deferred bytes
  322. ;  - [rcx + rdx] and [rcx] as usual point to the src and dst where the number
  323. ;    number of bytes given by r8 should be copied from and to.
  324. ;  - xmm0 holds the 16 deferred bytes that need to be stored at (-16)[rcx]
  325. ;
  326.         align   16
  327. XmmCopyUp:
  328.         movups  xmm0, [rcx + rdx]       ; load deferred bytes
  329.         add     r8, rcx                 ; r8 points 1 byte past end
  330.         add     rcx, 16                 ; update to next block.
  331.         test    r11b, 15                ; test if destination aligned
  332.         jz      XmmCopyLargeTest        ; go try 128-byte blocks
  333. ;
  334. ; Move alignment bytes.
  335. ;
  336. XmmCopyAlign:
  337.         movaps  xmm1, xmm0              ; save initial bytes in xmm1
  338.         and     rcx, -16                ; rcx is 16 bytes past first 16-byte align point
  339.         movups  xmm0, [rcx + rdx]       ; load aligned deferred-store bytes
  340.         add     rcx, 16                 ; update to next block
  341.         movups  [r11], xmm1             ; now safe to store 16 unaligned at start
  342. ;
  343. ; See if we can move any 128-byte blocks.
  344. ;
  345. XmmCopyLargeTest:
  346.         sub     r8, rcx                 ; r8 restored to count remaining
  347.         mov     r9, r8                  ; copy count of bytes remaining
  348.         shr     r9, 7                   ; compute number of 128-byte blocks
  349.         jz      XmmCopySmallTest        ; if z jump around to 2nd loop
  350.         movaps  (-16)[rcx], xmm0        ; going into 1st loop, ok to store deferred bytes
  351.         cmp     r9, __memcpy_nt_iters   ; threshold defined by cpu_disp.c
  352.         jna     short XmmCopyLargeInner ; jump into 1st loop
  353.         jmp     XmmCopyLargeInnerNT     ; long enough so non-temporal worth it, jump into nt loop

  354. ;
  355. ; Move 128-byte blocks
  356. ;
  357.         align   16
  358. ;
  359. ; When possible, non-mov instructions are put between a load and store
  360. ; so their execution can overlap the store.
  361. ; The jnz is likewise moved earlier to come before the last store pair.
  362. ; Pairs of loads/stores are used to overlap cache latencies.
  363. ; movups and movaps are equally fast on aligned storage, we use movaps
  364. ; to document movs that we *know* are going to be aligned, movups otherwise.
  365. ; xmm0 must be preloaded before jumping into this loop, and the last
  366. ; store must be deferred (and the bytes to store left in xmm0) for the
  367. ; following loop and/or the remainder code.
  368. ;
  369. XmmCopyLargeOuter:
  370.         movaps  (-32)[rcx], xmm0        ; store 7th chunk from prior iteration
  371.         movaps  (-16)[rcx], xmm1        ; store 8th chunk from prior iteration
  372. XmmCopyLargeInner:                      ; enter loop here with xmm0 preloaded.
  373.         movups  xmm0, [rcx + rdx]       ; load first 16 byte chunk
  374.         movups  xmm1, 16[rcx + rdx]     ; load 2nd 16 byte chunk
  375.         add     rcx, 128                ; advance destination address
  376.         movaps  (-128)[rcx], xmm0       ; store first 16 byte chunk
  377.         movaps  (-112)[rcx], xmm1       ; store 2nd 16 byte chunk
  378.         movups  xmm0, (-96)[rcx + rdx]  ; load 3rd chunk
  379.         movups  xmm1, (-80)[rcx + rdx]  ; load 4th chunk
  380.         dec     r9                      ; dec block counter (set cc for jnz)
  381.         movaps  (-96)[rcx], xmm0        ; store 3rd chunk
  382.         movaps  (-80)[rcx], xmm1        ; store 4th chunk
  383.         movups  xmm0, (-64)[rcx + rdx]  ; load 5th chunk
  384.         movups  xmm1, (-48)[rcx + rdx]  ; load 6th chunk
  385.         movaps  (-64)[rcx], xmm0        ; store 5th chunk
  386.         movaps  (-48)[rcx], xmm1        ; store 6th chunk
  387.         movups  xmm0, (-32)[rcx + rdx]  ; load 7th chunk
  388.         movups  xmm1, (-16)[rcx + rdx]  ; load 8th chunk
  389.         jnz     XmmCopyLargeOuter       ; loop if more blocks

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

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

  406.         align   16

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

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

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

  447. XmmCopyLargeOuterNT:
  448.         movntps (-32)[rcx], xmm0        ; store 7th chunk from prior iteration
  449.         movntps (-16)[rcx], xmm1        ; store 8th chunk from prior iteration
  450. XmmCopyLargeInnerNT:                    ; enter loop here with xmm0 preloaded.
  451.         prefetchnta [rcx + rdx + 512]   ; prefetch several cache lines ahead
  452.         movups  xmm0, [rcx + rdx]       ; load first 16 byte chunk
  453.         movups  xmm1, 16[rcx + rdx]     ; load 2nd 16 byte chunk
  454.         add     rcx, 128                ; advance destination address
  455.         movntps (-128)[rcx], xmm0       ; store first 16 byte chunk
  456.         movntps (-112)[rcx], xmm1       ; store 2nd 16 byte chunk
  457.         movups  xmm0, (-96)[rcx + rdx]  ; load 3rd chunk
  458.         movups  xmm1, (-80)[rcx + rdx]  ; load 4th chunk
  459.         dec     r9                      ; dec block counter (set cc for jnz)
  460.         movntps (-96)[rcx], xmm0        ; store 3rd chunk
  461.         movntps (-80)[rcx], xmm1        ; store 4th chunk
  462.         movups  xmm0, (-64)[rcx + rdx]  ; load 5th chunk
  463.         movups  xmm1, (-48)[rcx + rdx]  ; load 6th chunk
  464.         prefetchnta [rcx + rdx + 576]   ; prefetch several cache lines ahead
  465.         movntps (-64)[rcx], xmm0        ; store 5th chunk
  466.         movntps (-48)[rcx], xmm1        ; store 6th chunk
  467.         movups  xmm0, (-32)[rcx + rdx]  ; load 7th chunk
  468.         movups  xmm1, (-16)[rcx + rdx]  ; load 8th chunk
  469.         jnz     XmmCopyLargeOuterNT     ; loop if more blocks

  470.         sfence
  471.         jmp     XmmCopyFinish           ; rejoin regular memcpy codepath

  472. ;
  473. ; The source address is less than the destination address.
  474. ;

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

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

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

  538. XmmMovLargeOuter:
  539.         movaps  (128-112)[rcx], xmm0    ; store 7th chunk from prior iteration
  540.         movaps  (128-128)[rcx], xmm1    ; store 8th chunk from prior iteration
  541. XmmMovLargeInner:
  542.         movups  xmm0, (-16)[rcx + rdx]      ; load first 16 byte chunk
  543.         movups  xmm1, (-32)[rcx + rdx]      ; load 2nd 16 byte chunk
  544.         sub     rcx, 128                    ; reduce destination address
  545.         movaps  (128-16)[rcx], xmm0         ; store first 16 byte chunk
  546.         movaps  (128-32)[rcx], xmm1         ; store 2nd 16 byte chunk
  547.         movups  xmm0, (128-48)[rcx + rdx]   ; load 3rd chunk
  548.         movups  xmm1, (128-64)[rcx + rdx]   ; load 4th chunk
  549.         dec     r9                          ; dec block counter (set cc for jnz)
  550.         movaps  (128-48)[rcx], xmm0         ; store 3rd chunk
  551.         movaps  (128-64)[rcx], xmm1         ; store 4th chunk
  552.         movups  xmm0, (128-80)[rcx + rdx]   ; load 5th chunk
  553.         movups  xmm1, (128-96)[rcx + rdx]   ; load 6th chunk
  554.         movaps  (128-80)[rcx], xmm0         ; store 5th chunk
  555.         movaps  (128-96)[rcx], xmm1         ; store 6th chunk
  556.         movups  xmm0, (128-112)[rcx + rdx]  ; load 7th chunk
  557.         movups  xmm1, (128-128)[rcx + rdx]  ; load 8th chunk
  558.         jnz     short XmmMovLargeOuter      ; loop if more blocks

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

  569.         align   16

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

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

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

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

  594.         LEAF_END memcpy, _TEXT

  595.         end
复制代码
回复 赞! 靠!

使用道具 举报

30

主题

211

回帖

2792

积分

用户组: 版主

UID
1821
精华
7
威望
69 点
宅币
2172 个
贡献
206 次
宅之契约
0 份
在线时间
482 小时
注册时间
2016-7-12
发表于 2017-5-30 23:36:28 | 显示全部楼层
  1. /***
  2. *memcpy.c - contains memcpy routine
  3. *
  4. *       Copyright (c) Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *       memcpy() copies a source memory buffer to a destination buffer.
  8. *       Overlapping buffers are not treated specially, so propogation may occur.
  9. *
  10. *******************************************************************************/

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

  13. #pragma function(memcpy)

  14. /***
  15. *memcpy - Copy source buffer to destination buffer
  16. *
  17. *Purpose:
  18. *       memcpy() copies a source memory buffer to a destination memory buffer.
  19. *       This routine does NOT recognize overlapping buffers, and thus can lead
  20. *       to propogation.
  21. *
  22. *       For cases where propogation must be avoided, memmove() must be used.
  23. *
  24. *Entry:
  25. *       void *dst = pointer to destination buffer
  26. *       const void *src = pointer to source buffer
  27. *       size_t count = number of bytes to copy
  28. *
  29. *Exit:
  30. *       Returns a pointer to the destination buffer
  31. *
  32. *Exceptions:
  33. *******************************************************************************/

  34. void * __cdecl memcpy (
  35.         void * dst,
  36.         const void * src,
  37.         size_t count
  38.         )
  39. {
  40.         void * ret = dst;

  41.         /*
  42.          * copy from lower addresses to higher addresses
  43.          */
  44.         while (count--) {
  45.                 *(char *)dst = *(char *)src;
  46.                 dst = (char *)dst + 1;
  47.                 src = (char *)src + 1;
  48.         }

  49.         return(ret);
  50. }
复制代码
回复 赞! 靠!

使用道具 举报

1112

主题

1653

回帖

7万

积分

用户组: 管理员

一只技术宅

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

使用道具 举报

65

主题

117

回帖

1万

积分

用户组: 超级版主

OS与VM研究学者

UID
1043
精华
35
威望
789 点
宅币
8310 个
贡献
1094 次
宅之契约
0 份
在线时间
2072 小时
注册时间
2015-8-15
发表于 2018-7-27 10:05:42 | 显示全部楼层
不判断内存重叠的话还不如用这货:
https://docs.microsoft.com/en-us ... hta9830(v%3dvs.100)
回复 赞! 靠!

使用道具 举报

1112

主题

1653

回帖

7万

积分

用户组: 管理员

一只技术宅

UID
1
精华
245
威望
744 点
宅币
24254 个
贡献
46222 次
宅之契约
0 份
在线时间
2298 小时
注册时间
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架构的机器上这货烂得一匹
回复 赞! 靠!

使用道具 举报

65

主题

117

回帖

1万

积分

用户组: 超级版主

OS与VM研究学者

UID
1043
精华
35
威望
789 点
宅币
8310 个
贡献
1094 次
宅之契约
0 份
在线时间
2072 小时
注册时间
2015-8-15
发表于 2018-7-28 00:12:09 | 显示全部楼层
0xAA55 发表于 2018-7-27 22:35
然而非atom架构的机器上这货烂得一匹
  1. mov_char:
  2.         ... ...
  3.         mov edi, [ebp + 0x08]
  4.         mov esi, [ebp + 0x0c]
  5.         mov ecx, [ebp + 0x10]
  6.         rep movsb
  7.         ... ...
  8.         ret
复制代码

总比
  1. move_char:
  2.     push ebp
  3.     mov ebp, esp
  4.     sub esp, 0x0c
  5.     mov eax, [ebp+8]
  6.     mov edi, eax
  7.     mov esi, [ebp+0x0c]
  8.     mov ecx, dword ptr [ebp+0x10]

  9. move_loop:
  10.     mov bl, byte ptr [esi]
  11.     mov byte ptr [edi], bl
  12.     inc esi
  13.     inc edi
  14.     dec ecx
  15.     jnz move_loop
  16.     
  17.     mov esp, ebp
  18.     pop ebp
  19.     ret
复制代码

要好。
回复 赞! 靠!

使用道具 举报

4

主题

16

回帖

50

积分

用户组: 小·技术宅

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

使用道具 举报

29

主题

315

回帖

1561

积分

用户组: 上·技术宅

UID
3808
精华
11
威望
105 点
宅币
702 个
贡献
165 次
宅之契约
0 份
在线时间
404 小时
注册时间
2018-5-6
发表于 2018-9-1 10:50:09 | 显示全部楼层
小弟目前还在学一些简单的汇编,有些指令看得懂,有些指令看不懂(大部分),但是无疑发现memcpy有700多行的asm程序是多么兴奋的事情。
Passion Coding!
回复 赞! 靠!

使用道具 举报

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-4-27 11:42 , Processed in 0.058208 second(s), 38 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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