Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

604 lines
22 KiB

  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) 1986-2001, 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. ;Revision History:
  15. ; 02-06-87 JCR Added memmove entry
  16. ; 04-08-87 JCR Conditionalized memmove/memcpy entries
  17. ; 06-30-87 SKS Rewritten for speed and size
  18. ; 08-21-87 SKS Fix return value for overlapping copies
  19. ; 05-17-88 SJM Add model-independent (large model) ifdef
  20. ; 08-04-88 SJM convert to cruntime/ add 32-bit support
  21. ; 08-19-88 JCR Minor 386 corrections/enhancements
  22. ; 10-25-88 JCR General cleanup for 386-only code
  23. ; 03-23-90 GJF Changed to _stdcall. Also, fixed the copyright.
  24. ; 05-10-91 GJF Back to _cdecl, sigh...
  25. ; 11-13-92 SRW Make it fast with unaligned arguments
  26. ; 09-26-96 RDK Total rewrite to optimize for Pentium execution.
  27. ;
  28. ;*******************************************************************************
  29. .xlist
  30. include cruntime.inc
  31. .list
  32. M_EXIT macro
  33. ifdef _STDCALL_
  34. ret 2*DPSIZE + ISIZE ; _stdcall return
  35. else
  36. ret ; _cdecl return
  37. endif
  38. endm ; M_EXIT
  39. CODESEG
  40. page
  41. ;***
  42. ;memcpy - Copy source buffer to destination buffer
  43. ;
  44. ;Purpose:
  45. ; memcpy() copies a source memory buffer to a destination memory buffer.
  46. ; This routine does NOT recognize overlapping buffers, and thus can lead
  47. ; to propogation.
  48. ; For cases where propogation must be avoided, memmove() must be used.
  49. ;
  50. ; Algorithm:
  51. ;
  52. ; void * memcpy(void * dst, void * src, size_t count)
  53. ; {
  54. ; void * ret = dst;
  55. ;
  56. ; /*
  57. ; * copy from lower addresses to higher addresses
  58. ; */
  59. ; while (count--)
  60. ; *dst++ = *src++;
  61. ;
  62. ; return(ret);
  63. ; }
  64. ;
  65. ;memmove - Copy source buffer to destination buffer
  66. ;
  67. ;Purpose:
  68. ; memmove() copies a source memory buffer to a destination memory buffer.
  69. ; This routine recognize overlapping buffers to avoid propogation.
  70. ; For cases where propogation is not a problem, memcpy() can be used.
  71. ;
  72. ; Algorithm:
  73. ;
  74. ; void * memmove(void * dst, void * src, size_t count)
  75. ; {
  76. ; void * ret = dst;
  77. ;
  78. ; if (dst <= src || dst >= (src + count)) {
  79. ; /*
  80. ; * Non-Overlapping Buffers
  81. ; * copy from lower addresses to higher addresses
  82. ; */
  83. ; while (count--)
  84. ; *dst++ = *src++;
  85. ; }
  86. ; else {
  87. ; /*
  88. ; * Overlapping Buffers
  89. ; * copy from higher addresses to lower addresses
  90. ; */
  91. ; dst += count - 1;
  92. ; src += count - 1;
  93. ;
  94. ; while (count--)
  95. ; *dst-- = *src--;
  96. ; }
  97. ;
  98. ; return(ret);
  99. ; }
  100. ;
  101. ;
  102. ;Entry:
  103. ; void *dst = pointer to destination buffer
  104. ; const void *src = pointer to source buffer
  105. ; size_t count = number of bytes to copy
  106. ;
  107. ;Exit:
  108. ; Returns a pointer to the destination buffer in AX/DX:AX
  109. ;
  110. ;Uses:
  111. ; CX, DX
  112. ;
  113. ;Exceptions:
  114. ;*******************************************************************************
  115. ifdef MEM_MOVE
  116. _MEM_ equ <memmove>
  117. else
  118. _MEM_ equ <memcpy>
  119. endif
  120. % public _MEM_
  121. _MEM_ proc \
  122. dst:ptr byte, \
  123. src:ptr byte, \
  124. count:IWORD
  125. ; destination pointer
  126. ; source pointer
  127. ; number of bytes to copy
  128. ; push ebp ;U - save old frame pointer
  129. ; mov ebp, esp ;V - set new frame pointer
  130. push edi ;U - save edi
  131. push esi ;V - save esi
  132. mov esi,[src] ;U - esi = source
  133. mov ecx,[count] ;V - ecx = number of bytes to move
  134. mov edi,[dst] ;U - edi = dest
  135. ;
  136. ; Check for overlapping buffers:
  137. ; If (dst <= src) Or (dst >= src + Count) Then
  138. ; Do normal (Upwards) Copy
  139. ; Else
  140. ; Do Downwards Copy to avoid propagation
  141. ;
  142. mov eax,ecx ;V - eax = byte count...
  143. mov edx,ecx ;U - edx = byte count...
  144. add eax,esi ;V - eax = point past source end
  145. cmp edi,esi ;U - dst <= src ?
  146. jbe short CopyUp ;V - yes, copy toward higher addresses
  147. cmp edi,eax ;U - dst < (src + count) ?
  148. jb CopyDown ;V - yes, copy toward lower addresses
  149. ;
  150. ; Copy toward higher addresses.
  151. ;
  152. ;
  153. ; The algorithm for forward moves is to align the destination to a dword
  154. ; boundary and so we can move dwords with an aligned destination. This
  155. ; occurs in 3 steps.
  156. ;
  157. ; - move x = ((4 - Dest & 3) & 3) bytes
  158. ; - move y = ((L-x) >> 2) dwords
  159. ; - move (L - x - y*4) bytes
  160. ;
  161. CopyUp:
  162. test edi,11b ;U - destination dword aligned?
  163. jnz short CopyLeadUp ;V - if we are not dword aligned already, align
  164. shr ecx,2 ;U - shift down to dword count
  165. and edx,11b ;V - trailing byte count
  166. cmp ecx,8 ;U - test if small enough for unwind copy
  167. jb short CopyUnwindUp ;V - if so, then jump
  168. rep movsd ;N - move all of our dwords
  169. jmp dword ptr TrailUpVec[edx*4] ;N - process trailing bytes
  170. ;
  171. ; Code to do optimal memory copies for non-dword-aligned destinations.
  172. ;
  173. ; The following length check is done for two reasons:
  174. ;
  175. ; 1. to ensure that the actual move length is greater than any possiale
  176. ; alignment move, and
  177. ;
  178. ; 2. to skip the multiple move logic for small moves where it would
  179. ; be faster to move the bytes with one instruction.
  180. ;
  181. align @WordSize
  182. CopyLeadUp:
  183. mov eax,edi ;U - get destination offset
  184. mov edx,11b ;V - prepare for mask
  185. sub ecx,4 ;U - check for really short string - sub for adjust
  186. jb short ByteCopyUp ;V - branch to just copy bytes
  187. and eax,11b ;U - get offset within first dword
  188. add ecx,eax ;V - update size after leading bytes copied
  189. jmp dword ptr LeadUpVec[eax*4-4] ;N - process leading bytes
  190. align @WordSize
  191. ByteCopyUp:
  192. jmp dword ptr TrailUpVec[ecx*4+16] ;N - process just bytes
  193. align @WordSize
  194. CopyUnwindUp:
  195. jmp dword ptr UnwindUpVec[ecx*4] ;N - unwind dword copy
  196. align @WordSize
  197. LeadUpVec dd LeadUp1, LeadUp2, LeadUp3
  198. align @WordSize
  199. LeadUp1:
  200. and edx,ecx ;U - trailing byte count
  201. mov al,[esi] ;V - get first byte from source
  202. mov [edi],al ;U - write second byte to destination
  203. mov al,[esi+1] ;V - get second byte from source
  204. mov [edi+1],al ;U - write second byte to destination
  205. mov al,[esi+2] ;V - get third byte from source
  206. shr ecx,2 ;U - shift down to dword count
  207. mov [edi+2],al ;V - write third byte to destination
  208. add esi,3 ;U - advance source pointer
  209. add edi,3 ;V - advance destination pointer
  210. cmp ecx,8 ;U - test if small enough for unwind copy
  211. jb short CopyUnwindUp ;V - if so, then jump
  212. rep movsd ;N - move all of our dwords
  213. jmp dword ptr TrailUpVec[edx*4] ;N - process trailing bytes
  214. align @WordSize
  215. LeadUp2:
  216. and edx,ecx ;U - trailing byte count
  217. mov al,[esi] ;V - get first byte from source
  218. mov [edi],al ;U - write second byte to destination
  219. mov al,[esi+1] ;V - get second byte from source
  220. shr ecx,2 ;U - shift down to dword count
  221. mov [edi+1],al ;V - write second byte to destination
  222. add esi,2 ;U - advance source pointer
  223. add edi,2 ;V - advance destination pointer
  224. cmp ecx,8 ;U - test if small enough for unwind copy
  225. jb short CopyUnwindUp ;V - if so, then jump
  226. rep movsd ;N - move all of our dwords
  227. jmp dword ptr TrailUpVec[edx*4] ;N - process trailing bytes
  228. align @WordSize
  229. LeadUp3:
  230. and edx,ecx ;U - trailing byte count
  231. mov al,[esi] ;V - get first byte from source
  232. mov [edi],al ;U - write second byte to destination
  233. inc esi ;V - advance source pointer
  234. shr ecx,2 ;U - shift down to dword count
  235. inc edi ;V - advance destination pointer
  236. cmp ecx,8 ;U - test if small enough for unwind copy
  237. jb short CopyUnwindUp ;V - if so, then jump
  238. rep movsd ;N - move all of our dwords
  239. jmp dword ptr TrailUpVec[edx*4] ;N - process trailing bytes
  240. align @WordSize
  241. UnwindUpVec dd UnwindUp0, UnwindUp1, UnwindUp2, UnwindUp3
  242. dd UnwindUp4, UnwindUp5, UnwindUp6, UnwindUp7
  243. UnwindUp7:
  244. mov eax,[esi+ecx*4-28] ;U - get dword from source
  245. ;V - spare
  246. mov [edi+ecx*4-28],eax ;U - put dword into destination
  247. UnwindUp6:
  248. mov eax,[esi+ecx*4-24] ;U(entry)/V(not) - get dword from source
  249. ;V(entry) - spare
  250. mov [edi+ecx*4-24],eax ;U - put dword into destination
  251. UnwindUp5:
  252. mov eax,[esi+ecx*4-20] ;U(entry)/V(not) - get dword from source
  253. ;V(entry) - spare
  254. mov [edi+ecx*4-20],eax ;U - put dword into destination
  255. UnwindUp4:
  256. mov eax,[esi+ecx*4-16] ;U(entry)/V(not) - get dword from source
  257. ;V(entry) - spare
  258. mov [edi+ecx*4-16],eax ;U - put dword into destination
  259. UnwindUp3:
  260. mov eax,[esi+ecx*4-12] ;U(entry)/V(not) - get dword from source
  261. ;V(entry) - spare
  262. mov [edi+ecx*4-12],eax ;U - put dword into destination
  263. UnwindUp2:
  264. mov eax,[esi+ecx*4-8] ;U(entry)/V(not) - get dword from source
  265. ;V(entry) - spare
  266. mov [edi+ecx*4-8],eax ;U - put dword into destination
  267. UnwindUp1:
  268. mov eax,[esi+ecx*4-4] ;U(entry)/V(not) - get dword from source
  269. ;V(entry) - spare
  270. mov [edi+ecx*4-4],eax ;U - put dword into destination
  271. lea eax,[ecx*4] ;V - compute update for pointer
  272. add esi,eax ;U - update source pointer
  273. add edi,eax ;V - update destination pointer
  274. UnwindUp0:
  275. jmp dword ptr TrailUpVec[edx*4] ;N - process trailing bytes
  276. ;-----------------------------------------------------------------------------
  277. align @WordSize
  278. TrailUpVec dd TrailUp0, TrailUp1, TrailUp2, TrailUp3
  279. align @WordSize
  280. TrailUp0:
  281. mov eax,[dst] ;U - return pointer to destination
  282. pop esi ;V - restore esi
  283. pop edi ;U - restore edi
  284. ;V - spare
  285. M_EXIT
  286. align @WordSize
  287. TrailUp1:
  288. mov al,[esi] ;U - get byte from source
  289. ;V - spare
  290. mov [edi],al ;U - put byte in destination
  291. mov eax,[dst] ;V - return pointer to destination
  292. pop esi ;U - restore esi
  293. pop edi ;V - restore edi
  294. M_EXIT
  295. align @WordSize
  296. TrailUp2:
  297. mov al,[esi] ;U - get first byte from source
  298. ;V - spare
  299. mov [edi],al ;U - put first byte into destination
  300. mov al,[esi+1] ;V - get second byte from source
  301. mov [edi+1],al ;U - put second byte into destination
  302. mov eax,[dst] ;V - return pointer to destination
  303. pop esi ;U - restore esi
  304. pop edi ;V - restore edi
  305. M_EXIT
  306. align @WordSize
  307. TrailUp3:
  308. mov al,[esi] ;U - get first byte from source
  309. ;V - spare
  310. mov [edi],al ;U - put first byte into destination
  311. mov al,[esi+1] ;V - get second byte from source
  312. mov [edi+1],al ;U - put second byte into destination
  313. mov al,[esi+2] ;V - get third byte from source
  314. mov [edi+2],al ;U - put third byte into destination
  315. mov eax,[dst] ;V - return pointer to destination
  316. pop esi ;U - restore esi
  317. pop edi ;V - restore edi
  318. M_EXIT
  319. ;-----------------------------------------------------------------------------
  320. ;-----------------------------------------------------------------------------
  321. ;-----------------------------------------------------------------------------
  322. ;
  323. ; Copy down to avoid propogation in overlapping buffers.
  324. ;
  325. align @WordSize
  326. CopyDown:
  327. lea esi,[esi+ecx-4] ;U - point to 4 bytes before src buffer end
  328. lea edi,[edi+ecx-4] ;V - point to 4 bytes before dest buffer end
  329. ;
  330. ; See if the destination start is dword aligned
  331. ;
  332. test edi,11b ;U - test if dword aligned
  333. jnz short CopyLeadDown ;V - if not, jump
  334. shr ecx,2 ;U - shift down to dword count
  335. and edx,11b ;V - trailing byte count
  336. cmp ecx,8 ;U - test if small enough for unwind copy
  337. jb short CopyUnwindDown ;V - if so, then jump
  338. std ;N - set direction flag
  339. rep movsd ;N - move all of our dwords
  340. cld ;N - clear direction flag back
  341. jmp dword ptr TrailDownVec[edx*4] ;N - process trailing bytes
  342. align @WordSize
  343. CopyUnwindDown:
  344. neg ecx ;U - negate dword count for table merging
  345. ;V - spare
  346. jmp dword ptr UnwindDownVec[ecx*4+28] ;N - unwind copy
  347. align @WordSize
  348. CopyLeadDown:
  349. mov eax,edi ;U - get destination offset
  350. mov edx,11b ;V - prepare for mask
  351. cmp ecx,4 ;U - check for really short string
  352. jb short ByteCopyDown ;V - branch to just copy bytes
  353. and eax,11b ;U - get offset within first dword
  354. sub ecx,eax ;U - to update size after lead copied
  355. jmp dword ptr LeadDownVec[eax*4-4] ;N - process leading bytes
  356. align @WordSize
  357. ByteCopyDown:
  358. jmp dword ptr TrailDownVec[ecx*4] ;N - process just bytes
  359. align @WordSize
  360. LeadDownVec dd LeadDown1, LeadDown2, LeadDown3
  361. align @WordSize
  362. LeadDown1:
  363. mov al,[esi+3] ;U - load first byte
  364. and edx,ecx ;V - trailing byte count
  365. mov [edi+3],al ;U - write out first byte
  366. dec esi ;V - point to last src dword
  367. shr ecx,2 ;U - shift down to dword count
  368. dec edi ;V - point to last dest dword
  369. cmp ecx,8 ;U - test if small enough for unwind copy
  370. jb short CopyUnwindDown ;V - if so, then jump
  371. std ;N - set direction flag
  372. rep movsd ;N - move all of our dwords
  373. cld ;N - clear direction flag
  374. jmp dword ptr TrailDownVec[edx*4] ;N - process trailing bytes
  375. align @WordSize
  376. LeadDown2:
  377. mov al,[esi+3] ;U - load first byte
  378. and edx,ecx ;V - trailing byte count
  379. mov [edi+3],al ;U - write out first byte
  380. mov al,[esi+2] ;V - get second byte from source
  381. shr ecx,2 ;U - shift down to dword count
  382. mov [edi+2],al ;V - write second byte to destination
  383. sub esi,2 ;U - point to last src dword
  384. sub edi,2 ;V - point to last dest dword
  385. cmp ecx,8 ;U - test if small enough for unwind copy
  386. jb short CopyUnwindDown ;V - if so, then jump
  387. std ;N - set direction flag
  388. rep movsd ;N - move all of our dwords
  389. cld ;N - clear direction flag
  390. jmp dword ptr TrailDownVec[edx*4] ;N - process trailing bytes
  391. align @WordSize
  392. LeadDown3:
  393. mov al,[esi+3] ;U - load first byte
  394. and edx,ecx ;V - trailing byte count
  395. mov [edi+3],al ;U - write out first byte
  396. mov al,[esi+2] ;V - get second byte from source
  397. mov [edi+2],al ;U - write second byte to destination
  398. mov al,[esi+1] ;V - get third byte from source
  399. shr ecx,2 ;U - shift down to dword count
  400. mov [edi+1],al ;V - write third byte to destination
  401. sub esi,3 ;U - point to last src dword
  402. sub edi,3 ;V - point to last dest dword
  403. cmp ecx,8 ;U - test if small enough for unwind copy
  404. jb CopyUnwindDown ;V - if so, then jump
  405. std ;N - set direction flag
  406. rep movsd ;N - move all of our dwords
  407. cld ;N - clear direction flag
  408. jmp dword ptr TrailDownVec[edx*4] ;N - process trailing bytes
  409. ;------------------------------------------------------------------
  410. align @WordSize
  411. UnwindDownVec dd UnwindDown7, UnwindDown6, UnwindDown5, UnwindDown4
  412. dd UnwindDown3, UnwindDown2, UnwindDown1, UnwindDown0
  413. UnwindDown7:
  414. mov eax,[esi+ecx*4+28] ;U - get dword from source
  415. ;V - spare
  416. mov [edi+ecx*4+28],eax ;U - put dword into destination
  417. UnwindDown6:
  418. mov eax,[esi+ecx*4+24] ;U(entry)/V(not) - get dword from source
  419. ;V(entry) - spare
  420. mov [edi+ecx*4+24],eax ;U - put dword into destination
  421. UnwindDown5:
  422. mov eax,[esi+ecx*4+20] ;U(entry)/V(not) - get dword from source
  423. ;V(entry) - spare
  424. mov [edi+ecx*4+20],eax ;U - put dword into destination
  425. UnwindDown4:
  426. mov eax,[esi+ecx*4+16] ;U(entry)/V(not) - get dword from source
  427. ;V(entry) - spare
  428. mov [edi+ecx*4+16],eax ;U - put dword into destination
  429. UnwindDown3:
  430. mov eax,[esi+ecx*4+12] ;U(entry)/V(not) - get dword from source
  431. ;V(entry) - spare
  432. mov [edi+ecx*4+12],eax ;U - put dword into destination
  433. UnwindDown2:
  434. mov eax,[esi+ecx*4+8] ;U(entry)/V(not) - get dword from source
  435. ;V(entry) - spare
  436. mov [edi+ecx*4+8],eax ;U - put dword into destination
  437. UnwindDown1:
  438. mov eax,[esi+ecx*4+4] ;U(entry)/V(not) - get dword from source
  439. ;V(entry) - spare
  440. mov [edi+ecx*4+4],eax ;U - put dword into destination
  441. lea eax,[ecx*4] ;V - compute update for pointer
  442. add esi,eax ;U - update source pointer
  443. add edi,eax ;V - update destination pointer
  444. UnwindDown0:
  445. jmp dword ptr TrailDownVec[edx*4] ;N - process trailing bytes
  446. ;-----------------------------------------------------------------------------
  447. align @WordSize
  448. TrailDownVec dd TrailDown0, TrailDown1, TrailDown2, TrailDown3
  449. align @WordSize
  450. TrailDown0:
  451. mov eax,[dst] ;U - return pointer to destination
  452. ;V - spare
  453. pop esi ;U - restore esi
  454. pop edi ;V - restore edi
  455. M_EXIT
  456. align @WordSize
  457. TrailDown1:
  458. mov al,[esi+3] ;U - get byte from source
  459. ;V - spare
  460. mov [edi+3],al ;U - put byte in destination
  461. mov eax,[dst] ;V - return pointer to destination
  462. pop esi ;U - restore esi
  463. pop edi ;V - restore edi
  464. M_EXIT
  465. align @WordSize
  466. TrailDown2:
  467. mov al,[esi+3] ;U - get first byte from source
  468. ;V - spare
  469. mov [edi+3],al ;U - put first byte into destination
  470. mov al,[esi+2] ;V - get second byte from source
  471. mov [edi+2],al ;U - put second byte into destination
  472. mov eax,[dst] ;V - return pointer to destination
  473. pop esi ;U - restore esi
  474. pop edi ;V - restore edi
  475. M_EXIT
  476. align @WordSize
  477. TrailDown3:
  478. mov al,[esi+3] ;U - get first byte from source
  479. ;V - spare
  480. mov [edi+3],al ;U - put first byte into destination
  481. mov al,[esi+2] ;V - get second byte from source
  482. mov [edi+2],al ;U - put second byte into destination
  483. mov al,[esi+1] ;V - get third byte from source
  484. mov [edi+1],al ;U - put third byte into destination
  485. mov eax,[dst] ;V - return pointer to destination
  486. pop esi ;U - restore esi
  487. pop edi ;V - restore edi
  488. M_EXIT
  489. _MEM_ endp
  490. end