【C】memcpy真的就只是复制内存吗?然而并没有那么简单。
曾有人在QQ群里发了一个代码片段,自己实现memcpy的功能,然后内容大概如下:void COPY(void *dest, void *src, size_t len){
char *cdest = dest;
char *csrc = src;
size_t i;
for(i = 0; i < len; i++)
cdest = csrc;
}代码非常简单直白,通俗易懂,但我们真的有必要造个这样的轮子吗?先不说别的,memcpy真的就是这样实现的吗?
我们来看一下VS2012的memcpy的反汇编。这里我随便搞了个工程然后随便打了些代码,要的就是在执行memcpy的时候戳个断点进去看。
嗯可以看到VS2012的memcpy是拿汇编写的而且我们可以看到源码。我把它复制出来,详细的解释在后面,这里只做参考,可掠过。--- f:\dd\vctools\crt_bld\SELF_X86\crt\src\INTEL\memcpy.asm --------------------
dst:ptr byte, \
src:ptr byte, \
count:IWORD
; destination pointer
; source pointer
; number of bytes to copy
OPTION PROLOGUE:NONE, EPILOGUE:NONE
push edi ;U - save edi
0012B090 57 push edi
push esi ;V - save esi
0012B091 56 push esi
; size param/4 prolog byte#reg saved
.FPO ( 0, 3 , $-_MEM_ , 2, 0, 0 )
mov esi, ;U - esi = source
0012B092 8B 74 24 10 mov esi,dword ptr
mov ecx, ;V - ecx = number of bytes to move
0012B096 8B 4C 24 14 mov ecx,dword ptr
mov edi, ;U - edi = dest
0012B09A 8B 7C 24 0C mov edi,dword ptr
;
; Check for overlapping buffers:
; If (dst <= src) Or (dst >= src + Count) Then
; Do normal (Upwards) Copy
; Else
; Do Downwards Copy to avoid propagation
;
mov eax,ecx ;V - eax = byte count...
0012B09E 8B C1 mov eax,ecx
mov edx,ecx ;U - edx = byte count...
0012B0A0 8B D1 mov edx,ecx
add eax,esi ;V - eax = point past source end
0012B0A2 03 C6 add eax,esi
cmp edi,esi ;U - dst <= src ?
0012B0A4 3B FE cmp edi,esi
jbe short CopyUp ;V - yes, copy toward higher addresses
0012B0A6 76 08 jbe CopyUp (012B0B0h)
cmp edi,eax ;U - dst < (src + count) ?
0012B0A8 3B F8 cmp edi,eax
jb CopyDown ;V - yes, copy toward lower addresses
0012B0AA 0F 82 68 03 00 00 jb TrailUpVec+50h (012B418h)
;
; Copy toward higher addresses.
;
CopyUp:
;
; See if Enhanced Fast Strings is supported.
; ENFSTRG supported?
bt __favor, __FAVOR_ENFSTRG
0012B0B0 0F BA 25 FC 63 17 00 01 bt dword ptr ds:,1
jnc CopyUpSSE2Check ; no jump
0012B0B8 73 07 jae CopyUp+11h (012B0C1h)
;
; use Enhanced Fast Strings
rep movsb
0012B0BA F3 A4 rep movs byte ptr es:,byte ptr
jmp TrailUp0 ; Done
0012B0BC E9 17 03 00 00 jmp TrailUpVec+10h (012B3D8h)
CopyUpSSE2Check:
;
; Next, see if we can use a "fast" copy SSE2 routine
; block size greater than min threshold?
cmp ecx,080h
0012B0C1 81 F9 80 00 00 00 cmp ecx,80h
jb Dword_align; length too small go use dwords
0012B0C7 0F 82 CE 01 00 00 jb CopyUp+1EBh (012B29Bh)
; alignments equal?
mov eax,edi
0012B0CD 8B C7 mov eax,edi
xor eax,esi
0012B0CF 33 C6 xor eax,esi
test eax,15
0012B0D1 A9 0F 00 00 00 test eax,0Fh
jne AtomChk ; Not aligned go check Atom
0012B0D6 75 0E jne CopyUp+36h (012B0E6h)
bt __isa_enabled, __ISA_AVAILABLE_SSE2
0012B0D8 0F BA 25 00 50 17 00 01 bt dword ptr ds:,1
jc VEC_memcpy ; yes, go SSE2 copy (params already set)
0012B0E0 0F 82 DA 04 00 00 jb TrailDownVec+5Ch (012B5C0h)
AtomChk:
; Is Atom supported?
bt __favor, __FAVOR_ATOM
0012B0E6 0F BA 25 FC 63 17 00 00 bt dword ptr ds:,0
jnc Dword_align ; no,jump
0012B0EE 0F 83 A7 01 00 00 jae CopyUp+1EBh (012B29Bh)
; check if dst is 4 byte aligned
test edi, 3
0012B0F4 F7 C7 03 00 00 00 test edi,3
jne CopyLeadUp
0012B0FA 0F 85 B8 01 00 00 jne CopyUp+208h (012B2B8h)
; check if src is 4 byte aligned
test esi, 3
0012B100 F7 C6 03 00 00 00 test esi,3
jne Dword_align_Ok
0012B106 0F 85 97 01 00 00 jne CopyUp+1F3h (012B2A3h)
; A software pipelining vectorized memcpy loop using PALIGN instructions
; (1) copy the first bytes to align dst up to the nearest 16-byte boundary
; 4 byte align -> 12 byte copy, 8 byte align -> 8 byte copy, 12 byte align -> 4 byte copy
PalignHead4:
bt edi, 2
0012B10C 0F BA E7 02 bt edi,2
jae PalignHead8
0012B110 73 0D jae CopyUp+6Fh (012B11Fh)
mov eax, dword ptr
0012B112 8B 06 mov eax,dword ptr
sub ecx, 4
0012B114 83 E9 04 sub ecx,4
lea esi, byte ptr
0012B117 8D 76 04 lea esi,
mov dword ptr , eax
0012B11A 89 07 mov dword ptr ,eax
lea edi, byte ptr
0012B11C 8D 7F 04 lea edi,
PalignHead8:
bt edi, 3
0012B11F 0F BA E7 03 bt edi,3
jae PalignLoop
0012B123 73 11 jae CopyUp+86h (012B136h)
movq xmm1, qword ptr
0012B125 F3 0F 7E 0E movq xmm1,mmword ptr
sub ecx, 8
0012B129 83 E9 08 sub ecx,8
lea esi, byte ptr
0012B12C 8D 76 08 lea esi,
movq qword ptr , xmm1
0012B12F 66 0F D6 0F movq mmword ptr ,xmm1
lea edi, byte ptr
0012B133 8D 7F 08 lea edi,
;(2) Use SSE palign loop
PalignLoop:
test esi, 7
0012B136 F7 C6 07 00 00 00 test esi,7
je MovPalign8
0012B13C 74 63 je CopyUp+0F1h (012B1A1h)
bt esi, 3
0012B13E 0F BA E6 03 bt esi,3
jae MovPalign4
0012B142 0F 83 B2 00 00 00 jae CopyUp+14Ah (012B1FAh)
PALIGN_memcpy 12
0012B148 66 0F 6F 4E F4 movdqa xmm1,xmmword ptr
0012B14D 8D 76 F4 lea esi,
PalignLoop12:
0012B150 66 0F 6F 5E 10 movdqa xmm3,xmmword ptr
0012B155 83 E9 30 sub ecx,30h
0012B158 66 0F 6F 46 20 movdqa xmm0,xmmword ptr
0012B15D 66 0F 6F 6E 30 movdqa xmm5,xmmword ptr
0012B162 8D 76 30 lea esi,
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 ,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 ,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 ,xmm5
0012B194 8D 7F 30 lea edi,
0012B197 7D B7 jge CopyUp+0A0h (012B150h)
0012B199 8D 76 0C lea esi,
jmp PalignTail
0012B19C E9 AF 00 00 00 jmp CopyUp+1A0h (012B250h)
PALIGN_memcpy 8
0012B1A1 66 0F 6F 4E F8 movdqa xmm1,xmmword ptr
0012B1A6 8D 76 F8 lea esi,
0012B1A9 8D 49 00 lea ecx,
PalignLoop8:
0012B1AC 66 0F 6F 5E 10 movdqa xmm3,xmmword ptr
0012B1B1 83 E9 30 sub ecx,30h
0012B1B4 66 0F 6F 46 20 movdqa xmm0,xmmword ptr
0012B1B9 66 0F 6F 6E 30 movdqa xmm5,xmmword ptr
0012B1BE 8D 76 30 lea esi,
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 ,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 ,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 ,xmm5
0012B1F0 8D 7F 30 lea edi,
0012B1F3 7D B7 jge CopyUp+0FCh (012B1ACh)
0012B1F5 8D 76 08 lea esi,
jmp PalignTail
0012B1F8 EB 56 jmp CopyUp+1A0h (012B250h)
PALIGN_memcpy 4
0012B1FA 66 0F 6F 4E FC movdqa xmm1,xmmword ptr
0012B1FF 8D 76 FC lea esi,
0012B202 8B FF mov edi,edi
PalignLoop4:
0012B204 66 0F 6F 5E 10 movdqa xmm3,xmmword ptr
0012B209 83 E9 30 sub ecx,30h
0012B20C 66 0F 6F 46 20 movdqa xmm0,xmmword ptr
0012B211 66 0F 6F 6E 30 movdqa xmm5,xmmword ptr
0012B216 8D 76 30 lea esi,
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 ,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 ,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 ,xmm5
0012B248 8D 7F 30 lea edi,
0012B24B 7D B7 jge CopyUp+154h (012B204h)
0012B24D 8D 76 04 lea esi,
;(3) Copy the tailing bytes.
PalignTail:
cmp ecx,10h
0012B250 83 F9 10 cmp ecx,10h
jl PalignTail4
0012B253 7C 13 jl CopyUp+1B8h (012B268h)
movdqu xmm1,xmmword ptr
0012B255 F3 0F 6F 0E movdqu xmm1,xmmword ptr
sub ecx, 10h
0012B259 83 E9 10 sub ecx,10h
lea esi, xmmword ptr
0012B25C 8D 76 10 lea esi,
movdqa xmmword ptr ,xmm1
0012B25F 66 0F 7F 0F movdqa xmmword ptr ,xmm1
lea edi, xmmword ptr
0012B263 8D 7F 10 lea edi,
jmp PalignTail
0012B266 EB E8 jmp CopyUp+1A0h (012B250h)
PalignTail4:
bt ecx, 2
0012B268 0F BA E1 02 bt ecx,2
jae PalignTail8
0012B26C 73 0D jae CopyUp+1CBh (012B27Bh)
mov eax, dword ptr
0012B26E 8B 06 mov eax,dword ptr
sub ecx,4
0012B270 83 E9 04 sub ecx,4
lea esi, byte ptr
0012B273 8D 76 04 lea esi,
mov dword ptr , eax
0012B276 89 07 mov dword ptr ,eax
lea edi, byte ptr
0012B278 8D 7F 04 lea edi,
PalignTail8:
bt ecx, 3
0012B27B 0F BA E1 03 bt ecx,3
jae PalignTailLE3
0012B27F 73 11 jae CopyUp+1E2h (012B292h)
movq xmm1, qword ptr
0012B281 F3 0F 7E 0E movq xmm1,mmword ptr
sub ecx,8
0012B285 83 E9 08 sub ecx,8
lea esi, byte ptr
0012B288 8D 76 08 lea esi,
movq qword ptr , xmm1
0012B28B 66 0F D6 0F movq mmword ptr ,xmm1
lea edi, byte ptr
0012B28F 8D 7F 08 lea edi,
PalignTailLE3:
mov eax, dword ptr TrailUpVec
0012B292 8B 04 8D C8 B3 12 00 mov eax,dword ptr
jmp eax
0012B299 FF E0 jmp eax
; The algorithm for forward moves is to align the destination to a dword
; boundary and so we can move dwords with an aligned destination.This
; occurs in 3 steps.
;
; - move x = ((4 - Dest & 3) & 3) bytes
; - move y = ((L-x) >> 2) dwords
; - move (L - x - y*4) bytes
;
Dword_align:
test edi,11b ;U - destination dword aligned?
0012B29B F7 C7 03 00 00 00 test edi,3
jnz short CopyLeadUp ;V - if we are not dword aligned already, align
0012B2A1 75 15 jne CopyUp+208h (012B2B8h)
Dword_align_Ok:
shr ecx,2 ;U - shift down to dword count
0012B2A3 C1 E9 02 shr ecx,2
and edx,11b ;V - trailing byte count
0012B2A6 83 E2 03 and edx,3
cmp ecx,8 ;U - test if small enough for unwind copy
0012B2A9 83 F9 08 cmp ecx,8
jb short CopyUnwindUp ;V - if so, then jump
0012B2AC 72 2A jb CopyUp+228h (012B2D8h)
rep movsd ;N - move all of our dwords
0012B2AE F3 A5 rep movs dword ptr es:,dword ptr
jmp dword ptr TrailUpVec ;N - process trailing bytes
0012B2B0 FF 24 95 C8 B3 12 00 jmp dword ptr
0012B2B7 90 nop
;
; Code to do optimal memory copies for non-dword-aligned destinations.
;
; The following length check is done for two reasons:
;
; 1. to ensure that the actual move length is greater than any possiale
; alignment move, and
;
; 2. to skip the multiple move logic for small moves where it would
; be faster to move the bytes with one instruction.
;
align @WordSize
CopyLeadUp:
mov eax,edi ;U - get destination offset
0012B2B8 8B C7 mov eax,edi
mov edx,11b ;V - prepare for mask
0012B2BA BA 03 00 00 00 mov edx,3
sub ecx,4 ;U - check for really short string - sub for adjust
0012B2BF 83 E9 04 sub ecx,4
jb short ByteCopyUp ;V - branch to just copy bytes
0012B2C2 72 0C jb CopyUp+220h (012B2D0h)
and eax,11b ;U - get offset within first dword
0012B2C4 83 E0 03 and eax,3
add ecx,eax ;V - update size after leading bytes copied
0012B2C7 03 C8 add ecx,eax
jmp dword ptr LeadUpVec ;N - process leading bytes
0012B2C9 FF 24 85 DC B2 12 00 jmp dword ptr
align @WordSize
ByteCopyUp:
jmp dword ptr TrailUpVec ;N - process just bytes
0012B2D0 FF 24 8D D8 B3 12 00 jmp dword ptr
0012B2D7 90 nop
align @WordSize
CopyUnwindUp:
jmp dword ptr UnwindUpVec ;N - unwind dword copy
0012B2D8 FF 24 8D 5C B3 12 00 jmp dword ptr
0012B2DF 90 nop
--- 无源文件 -----------------------------------------------------------------------
0012B2E0 EC in al,dx
0012B2E1 B2 12 mov dl,12h
0012B2E3 00 18 add byte ptr ,bl
0012B2E5 B3 12 mov bl,12h
0012B2E7 00 3C B3 add byte ptr ,bh
0012B2EA 12 00 adc al,byte ptr
LeadUp1:
0012B2EC 23 D1 and edx,ecx
0012B2EE 8A 06 mov al,byte ptr
0012B2F0 88 07 mov byte ptr ,al
0012B2F2 8A 46 01 mov al,byte ptr
0012B2F5 88 47 01 mov byte ptr ,al
0012B2F8 8A 46 02 mov al,byte ptr
0012B2FB C1 E9 02 shr ecx,2
0012B2FE 88 47 02 mov byte ptr ,al
0012B301 83 C6 03 add esi,3
0012B304 83 C7 03 add edi,3
0012B307 83 F9 08 cmp ecx,8
0012B30A 72 CC jb CopyUp+228h (012B2D8h)
0012B30C F3 A5 rep movs dword ptr es:,dword ptr
0012B30E FF 24 95 C8 B3 12 00 jmp dword ptr
0012B315 8D 49 00 lea ecx,
LeadUp2:
0012B318 23 D1 and edx,ecx
0012B31A 8A 06 mov al,byte ptr
0012B31C 88 07 mov byte ptr ,al
0012B31E 8A 46 01 mov al,byte ptr
0012B321 C1 E9 02 shr ecx,2
0012B324 88 47 01 mov byte ptr ,al
0012B327 83 C6 02 add esi,2
0012B32A 83 C7 02 add edi,2
0012B32D 83 F9 08 cmp ecx,8
0012B330 72 A6 jb CopyUp+228h (012B2D8h)
0012B332 F3 A5 rep movs dword ptr es:,dword ptr
0012B334 FF 24 95 C8 B3 12 00 jmp dword ptr
0012B33B 90 nop
LeadUp3:
0012B33C 23 D1 and edx,ecx
0012B33E 8A 06 mov al,byte ptr
0012B340 88 07 mov byte ptr ,al
0012B342 83 C6 01 add esi,1
0012B345 C1 E9 02 shr ecx,2
0012B348 83 C7 01 add edi,1
0012B34B 83 F9 08 cmp ecx,8
0012B34E 72 88 jb CopyUp+228h (012B2D8h)
0012B350 F3 A5 rep movs dword ptr es:,dword ptr
0012B352 FF 24 95 C8 B3 12 00 jmp dword ptr
0012B359 8D 49 00 lea ecx,
0012B35C BF B3 12 00 AC mov edi,0AC0012B3h
0012B361 B3 12 mov bl,12h
0012B363 00 A4 B3 12 00 9C B3 add byte ptr ,ah
0012B36A 12 00 adc al,byte ptr
0012B36C 94 xchg eax,esp
0012B36D B3 12 mov bl,12h
0012B36F 00 8C B3 12 00 84 B3 add byte ptr ,cl
0012B376 12 00 adc al,byte ptr
0012B378 7C B3 jl LeadUpVec+4Dh (012B32Dh)
0012B37A 12 00 adc al,byte ptr
UnwindUp7:
0012B37C 8B 44 8E E4 mov eax,dword ptr
0012B380 89 44 8F E4 mov dword ptr ,eax
UnwindUp6:
0012B384 8B 44 8E E8 mov eax,dword ptr
0012B388 89 44 8F E8 mov dword ptr ,eax
UnwindUp5:
0012B38C 8B 44 8E EC mov eax,dword ptr
0012B390 89 44 8F EC mov dword ptr ,eax
UnwindUp4:
0012B394 8B 44 8E F0 mov eax,dword ptr
0012B398 89 44 8F F0 mov dword ptr ,eax
UnwindUp3:
0012B39C 8B 44 8E F4 mov eax,dword ptr
0012B3A0 89 44 8F F4 mov dword ptr ,eax
UnwindUp2:
0012B3A4 8B 44 8E F8 mov eax,dword ptr
0012B3A8 89 44 8F F8 mov dword ptr ,eax
UnwindUp1:
0012B3AC 8B 44 8E FC mov eax,dword ptr
0012B3B0 89 44 8F FC mov dword ptr ,eax
0012B3B4 8D 04 8D 00 00 00 00 lea eax,
0012B3BB 03 F0 add esi,eax
0012B3BD 03 F8 add edi,eax
UnwindUp0:
0012B3BF FF 24 95 C8 B3 12 00 jmp dword ptr
0012B3C6 8B FF mov edi,edi
0012B3C8 D8 B3 12 00 E0 B3 fdiv dword ptr
0012B3CE 12 00 adc al,byte ptr
0012B3D0 EC in al,dx
0012B3D1 B3 12 mov bl,12h
0012B3D3 00 00 add byte ptr ,al
0012B3D5 B4 12 mov ah,12h
0012B3D7 00 8B 44 24 0C 5E add byte ptr ,cl
0012B3DD 5F pop edi
0012B3DE C3 ret
0012B3DF 90 nop
TrailUp1:
0012B3E0 8A 06 mov al,byte ptr
0012B3E2 88 07 mov byte ptr ,al
0012B3E4 8B 44 24 0C mov eax,dword ptr
0012B3E8 5E pop esi
0012B3E9 5F pop edi
0012B3EA C3 ret
0012B3EB 90 nop
TrailUp2:
0012B3EC 8A 06 mov al,byte ptr
0012B3EE 88 07 mov byte ptr ,al
0012B3F0 8A 46 01 mov al,byte ptr
0012B3F3 88 47 01 mov byte ptr ,al
0012B3F6 8B 44 24 0C mov eax,dword ptr
0012B3FA 5E pop esi
0012B3FB 5F pop edi
0012B3FC C3 ret
0012B3FD 8D 49 00 lea ecx,
TrailUp3:
0012B400 8A 06 mov al,byte ptr
0012B402 88 07 mov byte ptr ,al
0012B404 8A 46 01 mov al,byte ptr
0012B407 88 47 01 mov byte ptr ,al
0012B40A 8A 46 02 mov al,byte ptr
0012B40D 88 47 02 mov byte ptr ,al
0012B410 8B 44 24 0C mov eax,dword ptr
0012B414 5E pop esi
0012B415 5F pop edi
0012B416 C3 ret
0012B417 90 nop
CopyDown:
0012B418 8D 74 31 FC lea esi,
0012B41C 8D 7C 39 FC lea edi,
0012B420 F7 C7 03 00 00 00 test edi,3
0012B426 75 24 jne TrailUpVec+84h (012B44Ch)
0012B428 C1 E9 02 shr ecx,2
0012B42B 83 E2 03 and edx,3
0012B42E 83 F9 08 cmp ecx,8
0012B431 72 0D jb TrailUpVec+78h (012B440h)
0012B433 FD std
0012B434 F3 A5 rep movs dword ptr es:,dword ptr
0012B436 FC cld
0012B437 FF 24 95 64 B5 12 00 jmp dword ptr
0012B43E 8B FF mov edi,edi
CopyUnwindDown:
0012B440 F7 D9 neg ecx
0012B442 FF 24 8D 14 B5 12 00 jmp dword ptr
0012B449 8D 49 00 lea ecx,
CopyLeadDown:
0012B44C 8B C7 mov eax,edi
0012B44E BA 03 00 00 00 mov edx,3
0012B453 83 F9 04 cmp ecx,4
0012B456 72 0C jb TrailUpVec+9Ch (012B464h)
0012B458 83 E0 03 and eax,3
0012B45B 2B C8 sub ecx,eax
0012B45D FF 24 85 68 B4 12 00 jmp dword ptr
ByteCopyDown:
0012B464 FF 24 8D 64 B5 12 00 jmp dword ptr
0012B46B 90 nop
0012B46C 78 B4 js TrailUpVec+5Ah (012B422h)
0012B46E 12 00 adc al,byte ptr
0012B470 9C pushfd
0012B471 B4 12 mov ah,12h
0012B473 00 C4 add ah,al
0012B475 B4 12 mov ah,12h
0012B477 00 8A 46 03 23 D1 add byte ptr ,cl
0012B47D 88 47 03 mov byte ptr ,al
0012B480 83 EE 01 sub esi,1
0012B483 C1 E9 02 shr ecx,2
0012B486 83 EF 01 sub edi,1
0012B489 83 F9 08 cmp ecx,8
0012B48C 72 B2 jb TrailUpVec+78h (012B440h)
0012B48E FD std
0012B48F F3 A5 rep movs dword ptr es:,dword ptr
0012B491 FC cld
0012B492 FF 24 95 64 B5 12 00 jmp dword ptr
0012B499 8D 49 00 lea ecx,
LeadDown2:
0012B49C 8A 46 03 mov al,byte ptr
0012B49F 23 D1 and edx,ecx
0012B4A1 88 47 03 mov byte ptr ,al
0012B4A4 8A 46 02 mov al,byte ptr
0012B4A7 C1 E9 02 shr ecx,2
0012B4AA 88 47 02 mov byte ptr ,al
0012B4AD 83 EE 02 sub esi,2
0012B4B0 83 EF 02 sub edi,2
0012B4B3 83 F9 08 cmp ecx,8
0012B4B6 72 88 jb TrailUpVec+78h (012B440h)
0012B4B8 FD std
0012B4B9 F3 A5 rep movs dword ptr es:,dword ptr
0012B4BB FC cld
0012B4BC FF 24 95 64 B5 12 00 jmp dword ptr
0012B4C3 90 nop
LeadDown3:
0012B4C4 8A 46 03 mov al,byte ptr
0012B4C7 23 D1 and edx,ecx
0012B4C9 88 47 03 mov byte ptr ,al
0012B4CC 8A 46 02 mov al,byte ptr
0012B4CF 88 47 02 mov byte ptr ,al
0012B4D2 8A 46 01 mov al,byte ptr
0012B4D5 C1 E9 02 shr ecx,2
0012B4D8 88 47 01 mov byte ptr ,al
0012B4DB 83 EE 03 sub esi,3
0012B4DE 83 EF 03 sub edi,3
0012B4E1 83 F9 08 cmp ecx,8
0012B4E4 0F 82 56 FF FF FF jb TrailUpVec+78h (012B440h)
0012B4EA FD std
0012B4EB F3 A5 rep movs dword ptr es:,dword ptr
0012B4ED FC cld
0012B4EE FF 24 95 64 B5 12 00 jmp dword ptr
0012B4F5 8D 49 00 lea ecx,
0012B4F8 18 B5 12 00 20 B5 sbb byte ptr ,dh
0012B4FE 12 00 adc al,byte ptr
0012B500 28 B5 12 00 30 B5 sub byte ptr ,dh
0012B506 12 00 adc al,byte ptr
0012B508 38 B5 12 00 40 B5 cmp byte ptr ,dh
0012B50E 12 00 adc al,byte ptr
0012B510 48 dec eax
0012B511 B5 12 mov ch,12h
0012B513 00 5B B5 add byte ptr ,bl
0012B516 12 00 adc al,byte ptr
UnwindDown7:
0012B518 8B 44 8E 1C mov eax,dword ptr
0012B51C 89 44 8F 1C mov dword ptr ,eax
UnwindDown6:
0012B520 8B 44 8E 18 mov eax,dword ptr
0012B524 89 44 8F 18 mov dword ptr ,eax
UnwindDown5:
0012B528 8B 44 8E 14 mov eax,dword ptr
0012B52C 89 44 8F 14 mov dword ptr ,eax
UnwindDown4:
0012B530 8B 44 8E 10 mov eax,dword ptr
0012B534 89 44 8F 10 mov dword ptr ,eax
UnwindDown3:
0012B538 8B 44 8E 0C mov eax,dword ptr
0012B53C 89 44 8F 0C mov dword ptr ,eax
UnwindDown2:
0012B540 8B 44 8E 08 mov eax,dword ptr
0012B544 89 44 8F 08 mov dword ptr ,eax
UnwindDown1:
0012B548 8B 44 8E 04 mov eax,dword ptr
0012B54C 89 44 8F 04 mov dword ptr ,eax
0012B550 8D 04 8D 00 00 00 00 lea eax,
0012B557 03 F0 add esi,eax
0012B559 03 F8 add edi,eax
UnwindDown0:
0012B55B FF 24 95 64 B5 12 00 jmp dword ptr
0012B562 8B FF mov edi,edi
0012B564 74 B5 je UnwindDownVec+23h (012B51Bh)
0012B566 12 00 adc al,byte ptr
0012B568 7C B5 jl UnwindDownVec+27h (012B51Fh)
0012B56A 12 00 adc al,byte ptr
0012B56C 8C B5 12 00 A0 B5 mov word ptr ,st(-2)
0012B572 12 00 adc al,byte ptr
TrailDown0:
0012B574 8B 44 24 0C mov eax,dword ptr
0012B578 5E pop esi
0012B579 5F pop edi
0012B57A C3 ret
0012B57B 90 nop
TrailDown1:
0012B57C 8A 46 03 mov al,byte ptr
0012B57F 88 47 03 mov byte ptr ,al
0012B582 8B 44 24 0C mov eax,dword ptr
0012B586 5E pop esi
0012B587 5F pop edi
0012B588 C3 ret
0012B589 8D 49 00 lea ecx,
TrailDown2:
0012B58C 8A 46 03 mov al,byte ptr
0012B58F 88 47 03 mov byte ptr ,al
0012B592 8A 46 02 mov al,byte ptr
0012B595 88 47 02 mov byte ptr ,al
0012B598 8B 44 24 0C mov eax,dword ptr
0012B59C 5E pop esi
0012B59D 5F pop edi
0012B59E C3 ret
0012B59F 90 nop
TrailDown3:
0012B5A0 8A 46 03 mov al,byte ptr
0012B5A3 88 47 03 mov byte ptr ,al
0012B5A6 8A 46 02 mov al,byte ptr
0012B5A9 88 47 02 mov byte ptr ,al
0012B5AC 8A 46 01 mov al,byte ptr
0012B5AF 88 47 01 mov byte ptr ,al
0012B5B2 8B 44 24 0C mov eax,dword ptr
0012B5B6 5E pop esi
0012B5B7 5F pop edi
0012B5B8 C3 ret
0012B5B9 8D A4 24 00 00 00 00 lea esp,
VEC_memcpy:
0012B5C0 57 push edi
0012B5C1 8B C6 mov eax,esi
0012B5C3 83 E0 0F and eax,0Fh
0012B5C6 85 C0 test eax,eax
0012B5C8 0F 85 D2 00 00 00 jne TrailDownVec+13Ch (012B6A0h)
L_Aligned:
0012B5CE 8B D1 mov edx,ecx
0012B5D0 83 E1 7F and ecx,7Fh
0012B5D3 C1 EA 07 shr edx,7
0012B5D6 74 65 je TrailDownVec+0D9h (012B63Dh)
0012B5D8 8D A4 24 00 00 00 00 lea esp,
0012B5DF 90 nop
L_1:
0012B5E0 66 0F 6F 06 movdqa xmm0,xmmword ptr
0012B5E4 66 0F 6F 4E 10 movdqa xmm1,xmmword ptr
0012B5E9 66 0F 6F 56 20 movdqa xmm2,xmmword ptr
0012B5EE 66 0F 6F 5E 30 movdqa xmm3,xmmword ptr
0012B5F3 66 0F 7F 07 movdqa xmmword ptr ,xmm0
0012B5F7 66 0F 7F 4F 10 movdqa xmmword ptr ,xmm1
0012B5FC 66 0F 7F 57 20 movdqa xmmword ptr ,xmm2
0012B601 66 0F 7F 5F 30 movdqa xmmword ptr ,xmm3
0012B606 66 0F 6F 66 40 movdqa xmm4,xmmword ptr
0012B60B 66 0F 6F 6E 50 movdqa xmm5,xmmword ptr
0012B610 66 0F 6F 76 60 movdqa xmm6,xmmword ptr
0012B615 66 0F 6F 7E 70 movdqa xmm7,xmmword ptr
0012B61A 66 0F 7F 67 40 movdqa xmmword ptr ,xmm4
0012B61F 66 0F 7F 6F 50 movdqa xmmword ptr ,xmm5
0012B624 66 0F 7F 77 60 movdqa xmmword ptr ,xmm6
0012B629 66 0F 7F 7F 70 movdqa xmmword ptr ,xmm7
0012B62E 8D B6 80 00 00 00 lea esi,
0012B634 8D BF 80 00 00 00 lea edi,
0012B63A 4A dec edx
0012B63B 75 A3 jne TrailDownVec+7Ch (012B5E0h)
L_1a:
0012B63D 85 C9 test ecx,ecx
0012B63F 74 4F je TrailDownVec+12Ch (012B690h)
0012B641 8B D1 mov edx,ecx
0012B643 C1 EA 04 shr edx,4
0012B646 85 D2 test edx,edx
0012B648 74 17 je TrailDownVec+0FDh (012B661h)
0012B64A 8D 9B 00 00 00 00 lea ebx,
L_2:
0012B650 66 0F 6F 06 movdqa xmm0,xmmword ptr
0012B654 66 0F 7F 07 movdqa xmmword ptr ,xmm0
0012B658 8D 76 10 lea esi,
0012B65B 8D 7F 10 lea edi,
0012B65E 4A dec edx
0012B65F 75 EF jne TrailDownVec+0ECh (012B650h)
L_Trailing:
0012B661 83 E1 0F and ecx,0Fh
0012B664 74 2A je TrailDownVec+12Ch (012B690h)
0012B666 8B C1 mov eax,ecx
0012B668 C1 E9 02 shr ecx,2
0012B66B 74 0D je TrailDownVec+116h (012B67Ah)
L_TrailDword:
0012B66D 8B 16 mov edx,dword ptr
0012B66F 89 17 mov dword ptr ,edx
0012B671 8D 76 04 lea esi,
0012B674 8D 7F 04 lea edi,
0012B677 49 dec ecx
0012B678 75 F3 jne TrailDownVec+109h (012B66Dh)
L_TrailBytes:
0012B67A 8B C8 mov ecx,eax
0012B67C 83 E1 03 and ecx,3
0012B67F 74 0F je TrailDownVec+12Ch (012B690h)
L_TrailNextByte:
0012B681 8A 06 mov al,byte ptr
0012B683 88 07 mov byte ptr ,al
0012B685 46 inc esi
0012B686 47 inc edi
0012B687 49 dec ecx
0012B688 75 F7 jne TrailDownVec+11Dh (012B681h)
0012B68A 8D 9B 00 00 00 00 lea ebx,
L_Return:
0012B690 58 pop eax
0012B691 5E pop esi
0012B692 5F pop edi
0012B693 C3 ret
0012B694 8D A4 24 00 00 00 00 lea esp,
0012B69B EB 03 jmp TrailDownVec+13Ch (012B6A0h)
0012B69D CC int 3
0012B69E CC int 3
0012B69F CC int 3
L_Notaligned:
0012B6A0 BA 10 00 00 00 mov edx,10h
0012B6A5 2B D0 sub edx,eax
0012B6A7 2B CA sub ecx,edx
0012B6A9 51 push ecx
0012B6AA 8B C2 mov eax,edx
0012B6AC 8B C8 mov ecx,eax
0012B6AE 83 E1 03 and ecx,3
0012B6B1 74 09 je TrailDownVec+158h (012B6BCh)
L_Byte:
0012B6B3 8A 16 mov dl,byte ptr
0012B6B5 88 17 mov byte ptr ,dl
0012B6B7 46 inc esi
0012B6B8 47 inc edi
0012B6B9 49 dec ecx
0012B6BA 75 F7 jne TrailDownVec+14Fh (012B6B3h)
L_MovDword:
0012B6BC C1 E8 02 shr eax,2
0012B6BF 74 0D je TrailDownVec+16Ah (012B6CEh)
L_Dword:
0012B6C1 8B 16 mov edx,dword ptr
0012B6C3 89 17 mov dword ptr ,edx
0012B6C5 8D 76 04 lea esi,
0012B6C8 8D 7F 04 lea edi,
0012B6CB 48 dec eax
0012B6CC 75 F3 jne TrailDownVec+15Dh (012B6C1h)
L_Adjustcnt:
0012B6CE 59 pop ecx
0012B6CF E9 FA FE FF FF jmp TrailDownVec+6Ah (012B5CEh)一个memcpy竟然有700+行,这简直比想象中的长得多,没错,确实不是简简单单地一个rep movsb就复制了内存的。它为什么这样做呢?我来分析一下。
首先开头的废话先不看,这里面有这样的几行注释:
;
; Check for overlapping buffers:
; If (dst <= src) Or (dst >= src + Count) Then
; Do normal (Upwards) Copy
; Else
; Do Downwards Copy to avoid propagation
;
我给翻译一下:检查缓冲区是否有重叠:
如果 目标在源的前面 或者 目标不在源的长度范围内 那么
做通常的(向后的)复制
否则
做向前的复制来避免错误复制(复制成片段重复的内容)(虽然括号里的内容是脑补翻译。此外注意我把“向上复制”翻译为“向后复制”,“向下复制”翻译为“向前复制”,请留意)
嗯虽说C语言规范说memmove能保证缓冲区重叠也能正常复制而memcpy则行为未定义,但VS2012还是做了保守的处理。毕竟比起性能消耗(而且反正后面是有优化的,我接下来讲),少一个坑是一个坑。
接下来从CopyUp开始看:这是正常的向后复制的代码实现。
然后,它先检测“增强快速串处理”是否支持,是的话,直接rep movsb
; See if Enhanced Fast Strings is supported.
; ENFSTRG supported?
bt __favor, __FAVOR_ENFSTRG
jnc CopyUpSSE2Check ; no jump
;
; use Enhanced Fast Strings
rep movsb
jmp TrailUp0 ; Done
嗯也就是CPU如果没有这个功能的话,它还有其它的优化手段。可以从jnc CopyUpSSE2Check这条指令看出,它会检测CPU是否支持SSE2指令集,然后使用SSE2指令集进行加速复制。
CopyUpSSE2Check:
;
; Next, see if we can use a "fast" copy SSE2 routine
; block size greater than min threshold?
cmp ecx,080h
jb Dword_align; length too small go use dwords
; alignments equal?
mov eax,edi
xor eax,esi
test eax,15
jne AtomChk ; Not aligned go check Atom
bt __isa_enabled, __ISA_AVAILABLE_SSE2
jc VEC_memcpy ; yes, go SSE2 copy (params already set)
先判断要复制的内容是否超过128字节,没有的话,因为此时再用SSE2的加速意义不大,此时它会跳到使用REP MOVSD的地方进行复制。
然后检查源地址和目标地址是不是都是16字节对齐的,如果没有对齐的话,检查CPU是不是Atom的,如果是对齐的,检查SSE2是否可用,可用的话直接跳去用SSE2的指令。
AtomChk:
; Is Atom supported?
bt __favor, __FAVOR_ATOM
jnc Dword_align ; no,jump
; check if dst is 4 byte aligned
test edi, 3
jne CopyLeadUp
; check if src is 4 byte aligned
test esi, 3
jne Dword_align_Ok
如果不是Atom处理器的话,直接跳到使用REP MOVSD的地方进行复制。
如果是的话,检查目标是否4字节对齐,不是的话跳到CopyLeadUp(CopyLeadUp的入口处的注释写的是“用于对未对齐的数据进行复制”)
然后再检查源是否4字节对齐,不是的话跳到使用REP MOVSD的、已经判断过目标是否对齐的那个地方继续执行。
; A software pipelining vectorized memcpy loop using PALIGN instructions
; (1) copy the first bytes to align dst up to the nearest 16-byte boundary
; 4 byte align -> 12 byte copy, 8 byte align -> 8 byte copy, 12 byte align -> 4 byte copy
PalignHead4:
bt edi, 2
jae PalignHead8
mov eax, dword ptr
sub ecx, 4
lea esi, byte ptr
mov dword ptr , eax
lea edi, byte ptr
此处是:一个使用PALIGN指令的软件处理管线的向量化内存循环
(1)复制开头的几个字节来让目标地址对齐到最近的16字节边界
4字节对齐 -> 12字节复制;8字节对齐 -> 8字节复制;12字节对齐->4字节复制
判断目标地址是否已经是4字节对齐了,是的话进行8字节对齐。
4字节对齐,直接mov搞定。
PalignHead8:
bt edi, 3
jae PalignLoop
movq xmm1, qword ptr
sub ecx, 8
lea esi, byte ptr
movq qword ptr , xmm1
lea edi, byte ptr
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
0012B14D 8D 76 F4 lea esi,
PalignLoop12:
0012B150 66 0F 6F 5E 10 movdqa xmm3,xmmword ptr
0012B155 83 E9 30 sub ecx,30h
0012B158 66 0F 6F 46 20 movdqa xmm0,xmmword ptr
0012B15D 66 0F 6F 6E 30 movdqa xmm5,xmmword ptr
0012B162 8D 76 30 lea esi,
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 ,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 ,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 ,xmm5
0012B194 8D 7F 30 lea edi,
0012B197 7D B7 jge CopyUp+0A0h (012B150h)
0012B199 8D 76 0C lea esi,
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
0012B1A6 8D 76 F8 lea esi,
0012B1A9 8D 49 00 lea ecx,
PalignLoop8:
0012B1AC 66 0F 6F 5E 10 movdqa xmm3,xmmword ptr
0012B1B1 83 E9 30 sub ecx,30h
0012B1B4 66 0F 6F 46 20 movdqa xmm0,xmmword ptr
0012B1B9 66 0F 6F 6E 30 movdqa xmm5,xmmword ptr
0012B1BE 8D 76 30 lea esi,
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 ,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 ,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 ,xmm5
0012B1F0 8D 7F 30 lea edi,
0012B1F3 7D B7 jge CopyUp+0FCh (012B1ACh)
0012B1F5 8D 76 08 lea esi,
jmp PalignTail
0012B1F8 EB 56 jmp CopyUp+1A0h (012B250h)
上面这里是8字节对齐的复制。
PALIGN_memcpy 4
0012B1FA 66 0F 6F 4E FC movdqa xmm1,xmmword ptr
0012B1FF 8D 76 FC lea esi,
0012B202 8B FF mov edi,edi
PalignLoop4:
0012B204 66 0F 6F 5E 10 movdqa xmm3,xmmword ptr
0012B209 83 E9 30 sub ecx,30h
0012B20C 66 0F 6F 46 20 movdqa xmm0,xmmword ptr
0012B211 66 0F 6F 6E 30 movdqa xmm5,xmmword ptr
0012B216 8D 76 30 lea esi,
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 ,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 ,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 ,xmm5
0012B248 8D 7F 30 lea edi,
0012B24B 7D B7 jge CopyUp+154h (012B204h)
0012B24D 8D 76 04 lea esi,
上面这里是4字节对齐复制。
;(3) Copy the tailing bytes.
PalignTail:
cmp ecx,10h
jl PalignTail4
movdqu xmm1,xmmword ptr
sub ecx, 10h
lea esi, xmmword ptr
movdqa xmmword ptr ,xmm1
lea edi, xmmword ptr
jmp PalignTail
上面这里是复制结尾的字节。
PalignTail4:
bt ecx, 2
jae PalignTail8
mov eax, dword ptr
sub ecx,4
lea esi, byte ptr
mov dword ptr , eax
lea edi, byte ptr
PalignTail8:
bt ecx, 3
jae PalignTailLE3
movq xmm1, qword ptr
sub ecx,8
lea esi, byte ptr
movq qword ptr , xmm1
lea edi, byte ptr
PalignTailLE3:
mov eax, dword ptr TrailUpVec
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 ;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 ;N - process leading bytes
align @WordSize
ByteCopyUp:
jmp dword ptr TrailUpVec ;N - process just bytes
align @WordSize
CopyUnwindUp:
jmp dword ptr UnwindUpVec ;N - unwind dword copy
此处的代码负责对没有进行4字节对齐的地址的数据的复制操作进行优化。后面的检测代码存在的原因有两个:
1、确保要复制的数据的长度超出任何可能的对齐长度
2、跳过多个复制逻辑让小的复制能更快一些
后面的部分没有源文件我也不分析了,不过值得留意的一个片段,我这里专门提一下:
L_1:
0012B5E0 66 0F 6F 06 movdqa xmm0,xmmword ptr
0012B5E4 66 0F 6F 4E 10 movdqa xmm1,xmmword ptr
0012B5E9 66 0F 6F 56 20 movdqa xmm2,xmmword ptr
0012B5EE 66 0F 6F 5E 30 movdqa xmm3,xmmword ptr
0012B5F3 66 0F 7F 07 movdqa xmmword ptr ,xmm0
0012B5F7 66 0F 7F 4F 10 movdqa xmmword ptr ,xmm1
0012B5FC 66 0F 7F 57 20 movdqa xmmword ptr ,xmm2
0012B601 66 0F 7F 5F 30 movdqa xmmword ptr ,xmm3
0012B606 66 0F 6F 66 40 movdqa xmm4,xmmword ptr
0012B60B 66 0F 6F 6E 50 movdqa xmm5,xmmword ptr
0012B610 66 0F 6F 76 60 movdqa xmm6,xmmword ptr
0012B615 66 0F 6F 7E 70 movdqa xmm7,xmmword ptr
0012B61A 66 0F 7F 67 40 movdqa xmmword ptr ,xmm4
0012B61F 66 0F 7F 6F 50 movdqa xmmword ptr ,xmm5
0012B624 66 0F 7F 77 60 movdqa xmmword ptr ,xmm6
0012B629 66 0F 7F 7F 70 movdqa xmmword ptr ,xmm7
这里面使用了8个SSE2寄存器进行复制操作,每个寄存器能存储16个字节,用这种方式进行复制的时候,这些movdqa指令其实有可能是并发执行的,尤其是你的内存是多通道的情况。此处进行数据量大的内容的复制的时候,效率应该会有很大的提升。
VS2012的memcpy函数,根据数据的量的大小对齐的情况,对每一种情况都进行了优化处理,各方面证明了它是无可替代的。不是什么时候,自己造的轮子都比别人的好。 这个帖子简直漂亮!
这边发一个别人用C实现的malloc,当然,malloc也不是那么简单的!
ftp://gee.cs.oswego.edu/pub/misc/malloc.c
注意这个开源代码协议是public domain。 page ,132
title memcpy - Copy source memory bytes to destination
;***
;memcpy.asm - contains memcpy and memmove routines
;
; Copyright (c) Microsoft Corporation. All rights reserved.
;
;Purpose:
; memcpy() copies a source memory buffer to a destination buffer.
; Overlapping buffers are not treated specially, so propogation may occur.
; memmove() copies a source memory buffer to a destination buffer.
; Overlapping buffers are treated specially, to avoid propogation.
;
;*******************************************************************************
.xlist
include cruntime.inc
.list
.xmm
M_EXITmacro
ret ; _cdecl return
endm ; M_EXIT
PALIGN_memcpy macro d
MovPalign&d&:
movdqa xmm1,xmmword ptr
lea esi, byte ptr
align @WordSize
PalignLoop&d&:
movdqaxmm3,xmmword ptr
sub ecx,30h
movdqaxmm0,xmmword ptr
movdqaxmm5,xmmword ptr
lea esi, xmmword ptr
cmp ecx,30h
movdqaxmm2,xmm3
palignr xmm3,xmm1,d
movdqaxmmword ptr ,xmm3
movdqaxmm4,xmm0
palignr xmm0,xmm2,d
movdqaxmmword ptr ,xmm0
movdqaxmm1,xmm5
palignr xmm5,xmm4,d
movdqaxmmword ptr ,xmm5
lea edi, xmmword ptr
jge PalignLoop&d&
lea esi, xmmword ptr
endm ; PALIGN_memcpy
CODESEG
extrn __isa_available:dword
extrn __isa_enabled:dword
extrn __favor:dword
page
;***
;memcpy - Copy source buffer to destination buffer
;
;Purpose:
; memcpy() copies a source memory buffer to a destination memory buffer.
; This routine does NOT recognize overlapping buffers, and thus can lead
; to propogation.
; For cases where propogation must be avoided, memmove() must be used.
;
; Algorithm:
;
; Same as memmove. See Below
;
;
;memmove - Copy source buffer to destination buffer
;
;Purpose:
; memmove() copies a source memory buffer to a destination memory buffer.
; This routine recognize overlapping buffers to avoid propogation.
; For cases where propogation is not a problem, memcpy() can be used.
;
; Algorithm:
;
; void * memmove(void * dst, void * src, size_t count)
; {
; void * ret = dst;
;
; if (dst <= src || dst >= (src + count)) {
; /*
; * Non-Overlapping Buffers
; * copy from lower addresses to higher addresses
; */
; while (count--)
; *dst++ = *src++;
; }
; else {
; /*
; * Overlapping Buffers
; * copy from higher addresses to lower addresses
; */
; dst += count - 1;
; src += count - 1;
;
; while (count--)
; *dst-- = *src--;
; }
;
; return(ret);
; }
;
;
;Entry:
; void *dst = pointer to destination buffer
; const void *src = pointer to source buffer
; size_t count = number of bytes to copy
;
;Exit:
; Returns a pointer to the destination buffer in AX/DX:AX
;
;Uses:
; CX, DX
;
;Exceptions:
;*******************************************************************************
ifdef MEM_MOVE
_MEM_ equ <memmove>
else; MEM_MOVE
_MEM_ equ <memcpy>
endif; MEM_MOVE
% public_MEM_
_MEM_ proc \
dst:ptr byte, \
src:ptr byte, \
count:IWORD
; destination pointer
; source pointer
; number of bytes to copy
OPTION PROLOGUE:NONE, EPILOGUE:NONE
push edi ;U - save edi
push esi ;V - save esi
; size param/4 prolog byte#reg saved
.FPO ( 0, 3 , $-_MEM_ , 2, 0, 0 )
mov esi, ;U - esi = source
mov ecx, ;V - ecx = number of bytes to move
mov edi, ;U - edi = dest
;
; Check for overlapping buffers:
; If (dst <= src) Or (dst >= src + Count) Then
; Do normal (Upwards) Copy
; Else
; Do Downwards Copy to avoid propagation
;
mov eax,ecx ;V - eax = byte count...
mov edx,ecx ;U - edx = byte count...
add eax,esi ;V - eax = point past source end
cmp edi,esi ;U - dst <= src ?
jbe short CopyUp ;V - yes, copy toward higher addresses
cmp edi,eax ;U - dst < (src + count) ?
jb CopyDown ;V - yes, copy toward lower addresses
;
; Copy toward higher addresses.
;
CopyUp:
;
; See if Enhanced Fast Strings is supported.
; ENFSTRG supported?
bt __favor, __FAVOR_ENFSTRG
jnc CopyUpSSE2Check ; no jump
;
; use Enhanced Fast Strings
rep movsb
jmp TrailUp0 ; Done
CopyUpSSE2Check:
;
; Next, see if we can use a "fast" copy SSE2 routine
; block size greater than min threshold?
cmp ecx,080h
jb Dword_align; length too small go use dwords
; alignments equal?
mov eax,edi
xor eax,esi
test eax,15
jne AtomChk ; Not aligned go check Atom
bt __isa_enabled, __ISA_AVAILABLE_SSE2
jc VEC_memcpy ; yes, go SSE2 copy (params already set)
AtomChk:
; Is Atom supported?
bt __favor, __FAVOR_ATOM
jnc Dword_align ; no,jump
; check if dst is 4 byte aligned
test edi, 3
jne CopyLeadUp
; check if src is 4 byte aligned
test esi, 3
jne Dword_align_Ok
; A software pipelining vectorized memcpy loop using PALIGN instructions
; (1) copy the first bytes to align dst up to the nearest 16-byte boundary
; 4 byte align -> 12 byte copy, 8 byte align -> 8 byte copy, 12 byte align -> 4 byte copy
PalignHead4:
bt edi, 2
jae PalignHead8
mov eax, dword ptr
sub ecx, 4
lea esi, byte ptr
mov dword ptr , eax
lea edi, byte ptr
PalignHead8:
bt edi, 3
jae PalignLoop
movq xmm1, qword ptr
sub ecx, 8
lea esi, byte ptr
movq qword ptr , xmm1
lea edi, byte ptr
;(2) Use SSE palign loop
PalignLoop:
test esi, 7
je MovPalign8
bt esi, 3
jae MovPalign4
PALIGN_memcpy 12
jmp PalignTail
PALIGN_memcpy 8
jmp PalignTail
PALIGN_memcpy 4
;(3) Copy the tailing bytes.
PalignTail:
cmp ecx,10h
jl PalignTail4
movdqu xmm1,xmmword ptr
sub ecx, 10h
lea esi, xmmword ptr
movdqa xmmword ptr ,xmm1
lea edi, xmmword ptr
jmp PalignTail
PalignTail4:
bt ecx, 2
jae PalignTail8
mov eax, dword ptr
sub ecx,4
lea esi, byte ptr
mov dword ptr , eax
lea edi, byte ptr
PalignTail8:
bt ecx, 3
jae PalignTailLE3
movq xmm1, qword ptr
sub ecx,8
lea esi, byte ptr
movq qword ptr , xmm1
lea edi, byte ptr
PalignTailLE3:
mov eax, dword ptr TrailUpVec
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 ;N - process trailing bytes
;
; Code to do optimal memory copies for non-dword-aligned destinations.
;
; The following length check is done for two reasons:
;
; 1. to ensure that the actual move length is greater than any possiale
; alignment move, and
;
; 2. to skip the multiple move logic for small moves where it would
; be faster to move the bytes with one instruction.
;
align @WordSize
CopyLeadUp:
mov eax,edi ;U - get destination offset
mov edx,11b ;V - prepare for mask
sub ecx,4 ;U - check for really short string - sub for adjust
jb short ByteCopyUp ;V - branch to just copy bytes
and eax,11b ;U - get offset within first dword
add ecx,eax ;V - update size after leading bytes copied
jmp dword ptr LeadUpVec ;N - process leading bytes
align @WordSize
ByteCopyUp:
jmp dword ptr TrailUpVec ;N - process just bytes
align @WordSize
CopyUnwindUp:
jmp dword ptr UnwindUpVec ;N - unwind dword copy
align @WordSize
LeadUpVec dd LeadUp1, LeadUp2, LeadUp3
align @WordSize
LeadUp1:
and edx,ecx ;U - trailing byte count
mov al, ;V - get first byte from source
mov ,al ;U - write second byte to destination
mov al, ;V - get second byte from source
mov ,al ;U - write second byte to destination
mov al, ;V - get third byte from source
shr ecx,2 ;U - shift down to dword count
mov ,al ;V - write third byte to destination
add esi,3 ;U - advance source pointer
add edi,3 ;V - advance destination pointer
cmp ecx,8 ;U - test if small enough for unwind copy
jb short CopyUnwindUp ;V - if so, then jump
rep movsd ;N - move all of our dwords
jmp dword ptr TrailUpVec ;N - process trailing bytes
align @WordSize
LeadUp2:
and edx,ecx ;U - trailing byte count
mov al, ;V - get first byte from source
mov ,al ;U - write second byte to destination
mov al, ;V - get second byte from source
shr ecx,2 ;U - shift down to dword count
mov ,al ;V - write second byte to destination
add esi,2 ;U - advance source pointer
add edi,2 ;V - advance destination pointer
cmp ecx,8 ;U - test if small enough for unwind copy
jb short CopyUnwindUp ;V - if so, then jump
rep movsd ;N - move all of our dwords
jmp dword ptr TrailUpVec ;N - process trailing bytes
align @WordSize
LeadUp3:
and edx,ecx ;U - trailing byte count
mov al, ;V - get first byte from source
mov ,al ;U - write second byte to destination
add esi,1 ;V - advance source pointer
shr ecx,2 ;U - shift down to dword count
add edi,1 ;V - advance destination pointer
cmp ecx,8 ;U - test if small enough for unwind copy
jb short CopyUnwindUp ;V - if so, then jump
rep movsd ;N - move all of our dwords
jmp dword ptr TrailUpVec ;N - process trailing bytes
align @WordSize
UnwindUpVec dd UnwindUp0, UnwindUp1, UnwindUp2, UnwindUp3
dd UnwindUp4, UnwindUp5, UnwindUp6, UnwindUp7
UnwindUp7:
mov eax, ;U - get dword from source
;V - spare
mov ,eax ;U - put dword into destination
UnwindUp6:
mov eax, ;U(entry)/V(not) - get dword from source
;V(entry) - spare
mov ,eax ;U - put dword into destination
UnwindUp5:
mov eax, ;U(entry)/V(not) - get dword from source
;V(entry) - spare
mov ,eax ;U - put dword into destination
UnwindUp4:
mov eax, ;U(entry)/V(not) - get dword from source
;V(entry) - spare
mov ,eax ;U - put dword into destination
UnwindUp3:
mov eax, ;U(entry)/V(not) - get dword from source
;V(entry) - spare
mov ,eax ;U - put dword into destination
UnwindUp2:
mov eax, ;U(entry)/V(not) - get dword from source
;V(entry) - spare
mov ,eax ;U - put dword into destination
UnwindUp1:
mov eax, ;U(entry)/V(not) - get dword from source
;V(entry) - spare
mov ,eax ;U - put dword into destination
lea eax, ;V - compute update for pointer
add esi,eax ;U - update source pointer
add edi,eax ;V - update destination pointer
UnwindUp0:
jmp dword ptr TrailUpVec ;N - process trailing bytes
;-----------------------------------------------------------------------------
align @WordSize
TrailUpVec dd TrailUp0, TrailUp1, TrailUp2, TrailUp3
align @WordSize
TrailUp0:
mov eax, ;U - return pointer to destination
pop esi ;V - restore esi
pop edi ;U - restore edi
;V - spare
M_EXIT
align @WordSize
TrailUp1:
mov al, ;U - get byte from source
;V - spare
mov ,al ;U - put byte in destination
mov eax, ;V - return pointer to destination
pop esi ;U - restore esi
pop edi ;V - restore edi
M_EXIT
align @WordSize
TrailUp2:
mov al, ;U - get first byte from source
;V - spare
mov ,al ;U - put first byte into destination
mov al, ;V - get second byte from source
mov ,al ;U - put second byte into destination
mov eax, ;V - return pointer to destination
pop esi ;U - restore esi
pop edi ;V - restore edi
M_EXIT
align @WordSize
TrailUp3:
mov al, ;U - get first byte from source
;V - spare
mov ,al ;U - put first byte into destination
mov al, ;V - get second byte from source
mov ,al ;U - put second byte into destination
mov al, ;V - get third byte from source
mov ,al ;U - put third byte into destination
mov eax, ;V - return pointer to destination
pop esi ;U - restore esi
pop edi ;V - restore edi
M_EXIT
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;
; Copy down to avoid propogation in overlapping buffers.
;
align @WordSize
CopyDown:
lea esi, ;U - point to 4 bytes before src buffer end
lea edi, ;V - point to 4 bytes before dest buffer end
;
; See if the destination start is dword aligned
;
test edi,11b ;U - test if dword aligned
jnz short CopyLeadDown ;V - if not, jump
shr ecx,2 ;U - shift down to dword count
and edx,11b ;V - trailing byte count
cmp ecx,8 ;U - test if small enough for unwind copy
jb short CopyUnwindDown ;V - if so, then jump
std ;N - set direction flag
rep movsd ;N - move all of our dwords
cld ;N - clear direction flag back
jmp dword ptr TrailDownVec ;N - process trailing bytes
align @WordSize
CopyUnwindDown:
neg ecx ;U - negate dword count for table merging
;V - spare
jmp dword ptr UnwindDownVec ;N - unwind copy
align @WordSize
CopyLeadDown:
mov eax,edi ;U - get destination offset
mov edx,11b ;V - prepare for mask
cmp ecx,4 ;U - check for really short string
jb short ByteCopyDown ;V - branch to just copy bytes
and eax,11b ;U - get offset within first dword
sub ecx,eax ;U - to update size after lead copied
jmp dword ptr LeadDownVec ;N - process leading bytes
align @WordSize
ByteCopyDown:
jmp dword ptr TrailDownVec ;N - process just bytes
align @WordSize
LeadDownVec dd LeadDown1, LeadDown2, LeadDown3
align @WordSize
LeadDown1:
mov al, ;U - load first byte
and edx,ecx ;V - trailing byte count
mov ,al ;U - write out first byte
sub esi,1 ;V - point to last src dword
shr ecx,2 ;U - shift down to dword count
sub edi,1 ;V - point to last dest dword
cmp ecx,8 ;U - test if small enough for unwind copy
jb short CopyUnwindDown ;V - if so, then jump
std ;N - set direction flag
rep movsd ;N - move all of our dwords
cld ;N - clear direction flag
jmp dword ptr TrailDownVec ;N - process trailing bytes
align @WordSize
LeadDown2:
mov al, ;U - load first byte
and edx,ecx ;V - trailing byte count
mov ,al ;U - write out first byte
mov al, ;V - get second byte from source
shr ecx,2 ;U - shift down to dword count
mov ,al ;V - write second byte to destination
sub esi,2 ;U - point to last src dword
sub edi,2 ;V - point to last dest dword
cmp ecx,8 ;U - test if small enough for unwind copy
jb short CopyUnwindDown ;V - if so, then jump
std ;N - set direction flag
rep movsd ;N - move all of our dwords
cld ;N - clear direction flag
jmp dword ptr TrailDownVec ;N - process trailing bytes
align @WordSize
LeadDown3:
mov al, ;U - load first byte
and edx,ecx ;V - trailing byte count
mov ,al ;U - write out first byte
mov al, ;V - get second byte from source
mov ,al ;U - write second byte to destination
mov al, ;V - get third byte from source
shr ecx,2 ;U - shift down to dword count
mov ,al ;V - write third byte to destination
sub esi,3 ;U - point to last src dword
sub edi,3 ;V - point to last dest dword
cmp ecx,8 ;U - test if small enough for unwind copy
jb CopyUnwindDown;V - if so, then jump
std ;N - set direction flag
rep movsd ;N - move all of our dwords
cld ;N - clear direction flag
jmp dword ptr TrailDownVec ;N - process trailing bytes
;------------------------------------------------------------------
align @WordSize
UnwindDownVec dd UnwindDown7, UnwindDown6, UnwindDown5, UnwindDown4
dd UnwindDown3, UnwindDown2, UnwindDown1, UnwindDown0
UnwindDown7:
mov eax, ;U - get dword from source
;V - spare
mov ,eax ;U - put dword into destination
UnwindDown6:
mov eax, ;U(entry)/V(not) - get dword from source
;V(entry) - spare
mov ,eax ;U - put dword into destination
UnwindDown5:
mov eax, ;U(entry)/V(not) - get dword from source
;V(entry) - spare
mov ,eax ;U - put dword into destination
UnwindDown4:
mov eax, ;U(entry)/V(not) - get dword from source
;V(entry) - spare
mov ,eax ;U - put dword into destination
UnwindDown3:
mov eax, ;U(entry)/V(not) - get dword from source
;V(entry) - spare
mov ,eax ;U - put dword into destination
UnwindDown2:
mov eax, ;U(entry)/V(not) - get dword from source
;V(entry) - spare
mov ,eax ;U - put dword into destination
UnwindDown1:
mov eax, ;U(entry)/V(not) - get dword from source
;V(entry) - spare
mov ,eax ;U - put dword into destination
lea eax, ;V - compute update for pointer
add esi,eax ;U - update source pointer
add edi,eax ;V - update destination pointer
UnwindDown0:
jmp dword ptr TrailDownVec ;N - process trailing bytes
;-----------------------------------------------------------------------------
align @WordSize
TrailDownVec dd TrailDown0, TrailDown1, TrailDown2, TrailDown3
align @WordSize
TrailDown0:
mov eax, ;U - return pointer to destination
;V - spare
pop esi ;U - restore esi
pop edi ;V - restore edi
M_EXIT
align @WordSize
TrailDown1:
mov al, ;U - get byte from source
;V - spare
mov ,al ;U - put byte in destination
mov eax, ;V - return pointer to destination
pop esi ;U - restore esi
pop edi ;V - restore edi
M_EXIT
align @WordSize
TrailDown2:
mov al, ;U - get first byte from source
;V - spare
mov ,al ;U - put first byte into destination
mov al, ;V - get second byte from source
mov ,al ;U - put second byte into destination
mov eax, ;V - return pointer to destination
pop esi ;U - restore esi
pop edi ;V - restore edi
M_EXIT
align @WordSize
TrailDown3:
mov al, ;U - get first byte from source
;V - spare
mov ,al ;U - put first byte into destination
mov al, ;V - get second byte from source
mov ,al ;U - put second byte into destination
mov al, ;V - get third byte from source
mov ,al ;U - put third byte into destination
mov eax, ;V - return pointer to destination
pop esi ;U - restore esi
pop edi ;V - restore edi
M_EXIT
align 16
VEC_memcpy:
push edi ; save dst for returning
mov eax, esi
and eax, 0Fh
; eax = src and dst alignment (src mod 16)
test eax, eax
jne L_Notaligned
; in:
;edi = dst (16 byte aligned)
;esi = src (16 byte aligned)
;ecx = len is >= (128 - head alignment bytes)
; do block copy using SSE2 stores
L_Aligned:
mov edx, ecx
and ecx, 7Fh
shr edx, 7
je L_1a
; ecx = loop count
; edx = remaining copy length
align 16
L_1:
movdqa xmm0,xmmword ptr
movdqa xmm1,xmmword ptr
movdqa xmm2,xmmword ptr
movdqa xmm3,xmmword ptr
movdqa xmmword ptr ,xmm0
movdqa xmmword ptr ,xmm1
movdqa xmmword ptr ,xmm2
movdqa xmmword ptr ,xmm3
movdqa xmm4,xmmword ptr
movdqa xmm5,xmmword ptr
movdqa xmm6,xmmword ptr
movdqa xmm7,xmmword ptr
movdqa xmmword ptr ,xmm4
movdqa xmmword ptr ,xmm5
movdqa xmmword ptr ,xmm6
movdqa xmmword ptr ,xmm7
lea esi,
lea edi,
dec edx
jne L_1
L_1a:
test ecx, ecx
je L_Return
; ecx = length (< 128 bytes)
mov edx, ecx
shr edx, 4
test edx, edx
je L_Trailing
; if > 16 bytes do a loop (16 bytes at a time)
; edx - loop count
; edi = dst
; esi = src
align 16
L_2:
movdqa xmm0, xmmword ptr
movdqa xmmword ptr , xmm0
lea esi,
lea edi,
dec edx
jne L_2
L_Trailing:
; last 1-15 bytes: step back according to dst and src alignment and do a 16-byte copy
; esi = src
; eax = src alignment(set at the start of the procedure and preserved up to here)
; edi = dst
and ecx, 0Fh
; ecx = remaining len
je L_Return
; get dword aligned
mov eax, ecx; save remaining len and calc number of dwords
shr ecx, 2
je L_TrailBytes ; if none try bytes
L_TrailDword:
mov edx, dword ptr
mov dword ptr , edx
lea esi,
lea edi,
dec ecx
jne L_TrailDword
L_TrailBytes:
mov ecx, eax
and ecx, 03h
je L_Return ; if none return
L_TrailNextByte:
mov al, byte ptr
mov byte ptr , al
inc esi
inc edi
dec ecx
jne L_TrailNextByte
align 16
L_Return:
; return dst
pop eax ; Get destination for return
pop esi
pop edi
M_EXIT
; dst addr is not 16 byte aligned
align 16
L_Notaligned:
; copy the first the first 1-15 bytes to align both src and dst up to the nearest 16-byte boundary:
; in
; esi = src
; edi = dst
; eax = src and dst alignment
; ecx = length
mov edx, 010h
sub edx, eax ; calc num bytes to get it aligned
sub ecx, edx ; calc new length and save it
push ecx
mov eax, edx ; save alignment byte count for dwords
mov ecx, eax ; set exc to rep count
and ecx, 03h
je L_MovDword ; if no bytes go do dwords
L_Byte:
mov dl, byte ptr ; move the bytes
mov byte ptr , dl
inc esi ; inc the adrs
inc edi
dec ecx ; dec the counter
jne L_Byte
L_MovDword:
shr eax, 2 ; get dword count
je L_Adjustcnt ; if none go to main loop
L_Dword:
mov edx, dword ptr ; move the dwords
mov dword ptr , edx
lea esi, ; inc the adrs
lea edi,
dec eax ; dec the counter
jne L_Dword
L_Adjustcnt:
pop ecx ; retrive the adjusted length
jmp L_Aligned
_MEM_ endp
end
本帖最后由 Ayala 于 2017-5-30 23:57 编辑
page ,132
title memcpy - Copy source memory bytes to destination
;***
;memcpy.asm - contains memcpy and memmove routines
;
; Copyright (c) Microsoft Corporation. All rights reserved.
;
;Purpose:
; memcpy() copies a source memory buffer to a destination buffer.
; Overlapping buffers are not treated specially, so propogation may occur.
; memmove() copies a source memory buffer to a destination buffer.
; Overlapping buffers are treated specially, to avoid propogation.
;
;*******************************************************************************
include ksamd64.inc
subttl"memcpy"
;***
;memcpy - Copy source buffer to destination buffer
;
;Purpose:
; memcpy() copies a source memory buffer to a destination memory buffer.
; This routine does NOT recognize overlapping buffers, and thus can lead
; to propogation.
; For cases where propogation must be avoided, memmove() must be used.
;
; Algorithm:
;
; void * memcpy(void * dst, void * src, size_t count)
; {
; void * ret = dst;
;
; /*
; * copy from lower addresses to higher addresses
; */
; while (count--)
; *dst++ = *src++;
;
; return(ret);
; }
;
;memmove - Copy source buffer to destination buffer
;
;Purpose:
; memmove() copies a source memory buffer to a destination memory buffer.
; This routine recognize overlapping buffers to avoid propogation.
; For cases where propogation is not a problem, memcpy() can be used.
;
; Algorithm:
;
; void * memmove(void * dst, void * src, size_t count)
; {
; void * ret = dst;
;
; if (dst <= src || dst >= (src + count)) {
; /*
; * Non-Overlapping Buffers
; * copy from lower addresses to higher addresses
; */
; while (count--)
; *dst++ = *src++;
; }
; else {
; /*
; * Overlapping Buffers
; * copy from higher addresses to lower addresses
; */
; dst += count - 1;
; src += count - 1;
;
; while (count--)
; *dst-- = *src--;
; }
;
; return(ret);
; }
;
;
;Entry:
; void *dst = pointer to destination buffer
; const void *src = pointer to source buffer
; size_t count = number of bytes to copy
;
;Exit:
; Returns a pointer to the destination buffer in AX/DX:AX
;
;Uses:
; CX, DX
;
;Exceptions:
;*******************************************************************************
extrn __favor:dword
extrn __ImageBase:byte
extrn __memcpy_nt_iters:qword ; defined in cpu_disp.c
__FAVOR_ENFSTRG equ 1
public memmove
LEAF_ENTRY_ARG3 memcpy, _TEXT, dst:ptr byte, src:ptr byte, count:dword
OPTION PROLOGUE:NONE, EPILOGUE:NONE
memmove = memcpy
mov r11, rcx ; save destination address
mov r10, rdx ; save source address
cmp r8, 16 ; if 16 bytes or less
jbe MoveBytes16 ; go move them quick
cmp r8, 32 ; check for length <= 32 (we know its > 16)
jbe Move17to32 ; go handle lengths 17-32 as a special case
sub rdx, rcx ; compute offset to source buffer
jae CopyUp ; if above or equal, go move up
mov rax, r10 ; else check that src+count < dst
add rax, r8 ; src + count
cmp rcx, rax ; (src + count) < dst
jl CopyDown ; no, buffers overlap go move downward
CopyUp:
cmp r8, 128
jbe XmmCopySmall
bt __favor, __FAVOR_ENFSTRG ; check for ENFSTRG (enhanced fast strings)
jnc XmmCopyUp ; If Enhanced Fast String not available, use XMM
; use Enhanced Fast Strings
; but first align the destination dst to 16 byte alignment
mov rax, r11 ; return original destination pointer
mov r11, rdi ; save rdi in r11
mov rdi, rcx ; move destination pointer to rdi
mov rcx, r8 ; move length to rcx
mov r8, rsi ; save rsi in r8
mov rsi, r10 ; move source pointer to rsi
rep movsb ; copy source to destination buffer
mov rsi, r8 ; restore rsi
mov rdi, r11 ; restore rdi
ret
; Handle lengths 17-32 as a special case using XMM registers.
; This allows the regular code to assume that there will always be enough
; bytes for the "deferred" block of 16. Also any case that can be handled
; with just two stores is handled with just two stores, the regular code
; will always do 3 stores for unaligned moves that have a remainder.
; No assumptions are made here about buffer alignment or overlap.
; We load the entire string to be moved in 2 xmm registers before storing
; anything, so this works for any arrangement of overlapping buffers.
;
; dst is in rcx (can modify) and r11 (must preserve for return value)
; src is in r10 (should preserve for consistency)
; rdx is the offset from the dst to the source, so rcx + rdx is the src
; r8 is the length, and is known to be 17 <= r8 <= 32
;
; When length < 32 the first 16 bytes includes some of the last 16 bytes
; and we will store (length - 32) bytes twice. (E.g. in the worst case
; of len 17 we are storing the middle 15 bytes of the buffer twice).
; This is still much faster than doing logic and branching with 1, 2, 4
; and 8 byte conditional copies.
;
align 16
Move17to32:
movupsxmm0, ; load first 16 bytes of src
movupsxmm1, (-16) ; load last 16 bytes of src
movups, xmm0 ; store first 16 bytes of dst
movups(-16), xmm1 ; store last 16 bytes of dst
mov rax, rcx ; set destination address
ret
;
; Move residual bytes.
;
align 16
MoveBytes16:
mov rax, rcx ; mov destination address to rax
lea r9, OFFSET __ImageBase
mov ecx, [(IMAGERELMoveSmall) + r9 +r8*4]
add rcx, r9
jmp rcx
MoveSmall ddIMAGEREL MoveSmall0
ddIMAGEREL MoveSmall1
ddIMAGEREL MoveSmall2
ddIMAGEREL MoveSmall3
ddIMAGEREL MoveSmall4
ddIMAGEREL MoveSmall5
ddIMAGEREL MoveSmall6
ddIMAGEREL MoveSmall7
ddIMAGEREL MoveSmall8
ddIMAGEREL MoveSmall9
ddIMAGEREL MoveSmall10
ddIMAGEREL MoveSmall11
ddIMAGEREL MoveSmall12
ddIMAGEREL MoveSmall13
ddIMAGEREL MoveSmall14
ddIMAGEREL MoveSmall15
ddIMAGEREL MoveSmall16
align 16
MoveSmall0::
ret
MoveSmall2::
movzx ecx, word ptr ; get two byte from source
mov , cx ; write two bytes to destination
ret
MoveSmall8::
mov rcx, qword ptr ; get eight bytes from source
mov , rcx ; write eight bytes to destination
ret
MoveSmall3::
movzx ecx, word ptr ; get two bytes from source
movzx r8d, byte ptr 2 ; get last byte from source
mov , cx ; write two bytes to destination
mov 2, r8b ; write last byte to destination
ret
MoveSmall1::
movzx ecx, byte ptr ; get byte from source
mov , cl ; write byte to destination
ret
MoveSmall16::
movdquxmm0, xmmword ptr ; get sixteen bytes from source
movdquxmmword ptr , xmm0 ; write sixteen bytes to destination
ret
align 16
MoveSmall11::
mov r8, qword ptr ; get eight bytes from source
movzx ecx, word ptr 8 ; get two bytes from source
movzx r9d, byte ptr 10 ; get last byte from source
mov , r8 ; write eight bytes to destination
mov 8, cx ; write two bytes to destination
mov 10, r9b ; write last byte to destination
mov rcx, r11 ; set destination address
ret
MoveSmall4::
mov ecx, dword ptr ; get four bytes from source
mov , ecx ; write four bytes to destination
ret
align 16
MoveSmall5::
mov ecx, dword ptr ; get four bytes from source
movzx r8d, byte ptr 4 ; get last byte from source
mov , ecx ; write four bytes to destination
mov 4, r8b ; write last byte to destination
ret
align 16
MoveSmall6::
mov ecx, dword ptr ; get four bytes from source
movzx r8d, word ptr 4 ; get two bytes from source
mov , ecx ; write four bytes to destination
mov 4, r8w ; write two bytes to destination
ret
align 16
MoveSmall7::
mov ecx, dword ptr ; get four bytes from source
movzx r8d, word ptr 4 ; get two bytes from source
movzx r9d, byte ptr 6 ; get last byte from source
mov , ecx ; write four bytes to destination
mov 4, r8w ; write two bytes to destination
mov 6, r9b ; write last byte to destination
ret
MoveSmall13::
mov r8, qword ptr ; get eight bytes from source
mov ecx, dword ptr 8 ; get four bytes from source
movzx r9d, byte ptr 12 ; get last bytes from source
mov , r8 ; write eight bytes to destination
mov 8, ecx ; write four bytesto destination
mov 12, r9b ; write last byte to destination
ret
align 16
MoveSmall9::
mov r8, qword ptr ; get eight bytes from source
movzx ecx, byte ptr 8 ; get last byte from source
mov , r8 ; write eight bytes to destination
mov 8, cl ; write last byte to destination
ret
align 16
MoveSmall10::
mov r8, qword ptr ; get eight bytes from source
movzx ecx, word ptr 8 ; get two bytes from source
mov , r8 ; write eight bytes to destination
mov 8, cx ; write two bytes to destination
ret
align 16
MoveSmall12::
mov r8, qword ptr ; get eight bytes from source
mov ecx, dword ptr 8 ; get four bytes from source
mov , r8 ; write eight bytes to destination
mov 8, ecx ; write four bytes to destination
ret
align 16
MoveSmall14::
mov r8, qword ptr ; get eight bytes from source
mov ecx, dword ptr 8 ; get four bytes from source
movzx r9d, word ptr 12 ; get two bytes from source
mov , r8 ; write eight bytes to destination
mov 8, ecx ; write four bytes to destination
mov 12, r9w ; write two bytes to destination
ret
align 16
MoveSmall15::
mov r8, qword ptr ; get eight bytes from source
mov ecx, dword ptr 8 ; get four bytes from source
movzx r9d, word ptr 12 ; get two bytes from source
movzx r10d, byte ptr 14; get last byte from source
mov , r8 ; write eight bytes to destination
mov 8, ecx ; write four bytes to destination
mov 12, r9w ; write two bytes to destination
mov 14, r10b ; write last byte to destination
ret
;
; Memcpy up using SSE instructions.
;
; Preconditions:
; destination in rcx (destructable) and r11 (must preserve for return value)
; source in r10
; length in r8, must be greater than 16
; offset from dest to src in rdx
; source addr > dest addr or else buffers don't overlap
;
; Aligned stores are much faster on AMD hardware, so start by moving however many
; bytes must be moved so updated dst is 16-byte aligned. We need to copy
; (16 - (dest mod 16)) bytes, but it's faster to just do an unaligned copy of 16
; bytes and then start the aligned loop as usual at ((dest - (dest mod 16)) + 16).
; This results in (dest mod 16) bytes being copied twice. This is a lot faster
; than a bunch of code to copy maybe 1 then maybe 2 then maybe 4 then maybe 8
; bytes to achieve dst alignement.
;
; We know the src address is greater than the dst, but not by how much. In the
; case where the difference is less than 16 we must be careful about the bytes
; that will be stored twice. We must do both loads before either store, or the
; second load of those bytes will get the wrong values. We handle this by
; loading the last 16 bytes that can be stored at an aligned address, but
; deferring the store of those bytes to the remainder code, so it can load the
; remainder before storing the deferred bytes. Since either or both of the two
; loops can be skipped, the preconditions needed by the remaindercode must
; also apply to the loops. These conditions are:
;- r8 is the count remaining, not including the deferred bytes
;- and as usual point to the src and dst where the number
; number of bytes given by r8 should be copied from and to.
;- xmm0 holds the 16 deferred bytes that need to be stored at (-16)
;
align 16
XmmCopyUp:
movupsxmm0, ; load deferred bytes
add r8, rcx ; r8 points 1 byte past end
add rcx, 16 ; update to next block.
test r11b, 15 ; test if destination aligned
jz XmmCopyLargeTest ; go try 128-byte blocks
;
; Move alignment bytes.
;
XmmCopyAlign:
movapsxmm1, xmm0 ; save initial bytes in xmm1
and rcx, -16 ; rcx is 16 bytes past first 16-byte align point
movupsxmm0, ; load aligned deferred-store bytes
add rcx, 16 ; update to next block
movups, xmm1 ; now safe to store 16 unaligned at start
;
; See if we can move any 128-byte blocks.
;
XmmCopyLargeTest:
sub r8, rcx ; r8 restored to count remaining
mov r9, r8 ; copy count of bytes remaining
shr r9, 7 ; compute number of 128-byte blocks
jz XmmCopySmallTest ; if z jump around to 2nd loop
movaps(-16), xmm0 ; going into 1st loop, ok to store deferred bytes
cmp r9, __memcpy_nt_iters ; threshold defined by cpu_disp.c
jna short XmmCopyLargeInner ; jump into 1st loop
jmp XmmCopyLargeInnerNT ; long enough so non-temporal worth it, jump into nt loop
;
; Move 128-byte blocks
;
align 16
;
; When possible, non-mov instructions are put between a load and store
; so their execution can overlap the store.
; The jnz is likewise moved earlier to come before the last store pair.
; Pairs of loads/stores are used to overlap cache latencies.
; movups and movaps are equally fast on aligned storage, we use movaps
; to document movs that we *know* are going to be aligned, movups otherwise.
; xmm0 must be preloaded before jumping into this loop, and the last
; store must be deferred (and the bytes to store left in xmm0) for the
; following loop and/or the remainder code.
;
XmmCopyLargeOuter:
movaps(-32), xmm0 ; store 7th chunk from prior iteration
movaps(-16), xmm1 ; store 8th chunk from prior iteration
XmmCopyLargeInner: ; enter loop here with xmm0 preloaded.
movupsxmm0, ; load first 16 byte chunk
movupsxmm1, 16 ; load 2nd 16 byte chunk
add rcx, 128 ; advance destination address
movaps(-128), xmm0 ; store first 16 byte chunk
movaps(-112), xmm1 ; store 2nd 16 byte chunk
movupsxmm0, (-96); load 3rd chunk
movupsxmm1, (-80); load 4th chunk
dec r9 ; dec block counter (set cc for jnz)
movaps(-96), xmm0 ; store 3rd chunk
movaps(-80), xmm1 ; store 4th chunk
movupsxmm0, (-64); load 5th chunk
movupsxmm1, (-48); load 6th chunk
movaps(-64), xmm0 ; store 5th chunk
movaps(-48), xmm1 ; store 6th chunk
movupsxmm0, (-32); load 7th chunk
movupsxmm1, (-16); load 8th chunk
jnz XmmCopyLargeOuter ; loop if more blocks
XmmCopyFinish: ; non-temporal codepath rejoins here
movaps(-32), xmm0 ; store 7th chunk from final iteration
and r8, 127 ; compute remaining byte count
movapsxmm0, xmm1 ; 8th chunk becomes deferred bytes
jmp XmmCopySmallTest
XmmCopySmall:
movupsxmm0, ; load deferred bytes
add rcx, 16
sub r8, 16
;
; See if we have any 16-byte blocks left to move
;
XmmCopySmallTest:
mov r9, r8 ; copy count of bytes remaining
shr r9, 4 ; compute number of 16-byte blocks
jz short XmmCopyTrail ; on z, no 16-byte blocks, skip 2nd loop
align 16
XmmCopySmallLoop:
movups(-16), xmm0 ; the first time through this is the
; store of the deferred bytes from above
movupsxmm0, ; load a block
add rcx, 16 ; advance dest addr (store is deferred)
dec r9
jnz XmmCopySmallLoop
XmmCopyTrail:
and r8, 15 ; compute remaining byte count
jz short XmmCopyReturn ; if z, no remainder bytes to move
;
; Handle remainder bytes.
;
; As at the start, we are going to do an unaligned copy of 16 bytes which will double-write
; some bytes.We must not touch rcx or xmm0 because they have what we need to store the
; deferred block. We use rax to point to the first byte after the end of the buffer and
; back up from there. Note rax is pointing to an address we must not read or write!
;
lea rax, ; make rax point one past the end
movupsxmm1, (-16); load last 16 bytes of source buffer
movups(-16), xmm1 ; write last 16 bytes, including 16-r8 bytes
; from the last aligned block which we are about to
; overstore with identical values
XmmCopyReturn:
movups(-16), xmm0 ; store the last deferred aligned block
mov rax, r11 ; we must return the original destination address
ret ;
;
; Move 128-byte blocks non-temporal
;
align 16
;
; non-temporal is exactly the same as the regular xmm loop above, except the movaps
; stores are movntps and we use prefetchnta. We are prefetching in two places, each
; prefetch gets 64 bytes about half an iteration ahead of time (about 10 instructions
; lead time). When we come to the end of the memcpy, we'll be prefetching bytes
; beyond the buffer we need to copy from, which may not be valid bytes. This is
; not illegal; if the memory address is invalid it does not trap, the hardware treats
; illegal prefetches as nops.
;
XmmCopyLargeOuterNT:
movntps (-32), xmm0 ; store 7th chunk from prior iteration
movntps (-16), xmm1 ; store 8th chunk from prior iteration
XmmCopyLargeInnerNT: ; enter loop here with xmm0 preloaded.
prefetchnta ; prefetch several cache lines ahead
movupsxmm0, ; load first 16 byte chunk
movupsxmm1, 16 ; load 2nd 16 byte chunk
add rcx, 128 ; advance destination address
movntps (-128), xmm0 ; store first 16 byte chunk
movntps (-112), xmm1 ; store 2nd 16 byte chunk
movupsxmm0, (-96); load 3rd chunk
movupsxmm1, (-80); load 4th chunk
dec r9 ; dec block counter (set cc for jnz)
movntps (-96), xmm0 ; store 3rd chunk
movntps (-80), xmm1 ; store 4th chunk
movupsxmm0, (-64); load 5th chunk
movupsxmm1, (-48); load 6th chunk
prefetchnta ; prefetch several cache lines ahead
movntps (-64), xmm0 ; store 5th chunk
movntps (-48), xmm1 ; store 6th chunk
movupsxmm0, (-32); load 7th chunk
movupsxmm1, (-16); load 8th chunk
jnz XmmCopyLargeOuterNT ; loop if more blocks
sfence
jmp XmmCopyFinish ; rejoin regular memcpy codepath
;
; The source address is less than the destination address.
;
align 16
;
; Move bytes down using SSE registers. The source address is less than
; the destination address and the buffers overlap. We will do everything back-to-front.
;
; Preconditions:
; destination is r11 (must preserve for return value) and rcx
; source in r10 (must preserve for remainder move)
; length in r8, must have been verified to be greater than 16
; offset from dest to src in rdx
; source addr < dest addr and the buffers overlap
;
CopyDown:
add rcx, r8 ; make rcx point one past the end of the dst buffer
movupsxmm0, -16 ; load deferred bytes
sub rcx, 16 ; reduce dst addr
sub r8, 16 ; r8 -= 16 in case aligned
;
; Aligned stores using movaps or movups are faster on AMD hardware than unaligned
; stores using movups. To achieve 16-byte dest alignment, we do an unaligned move
; of the last 16 bytes of the buffers, then reduce rcx only by the amount necessary
; to achieve alignment. This results in some bytes getting copied twice, unless we're
; already aligned.
;
; We know the src address is less than the dst, but not by exactly how much. In the
; case where the difference is less than 16 we must be careful about the bytes
; that will be stored twice. We must do both loads before either store, or the
; second load of those bytes will get the wrong values. We handle this by
; deferring the store of 16 aligned bytes to the remainder code, so it can load the
; remainder before storing the deferred bytes. Since either or both of the two
; loops can be skipped, the preconditions needed by the remaindercode must
; also apply to the loops. These conditions are:
;- r8 is the count remaining, not including the deferred bytes
;- points one past the end of the remainder bytes
;- rdx is the offset from the dst to the source
;- xmm0 holds the 16 deferred bytes that need to be stored at
;
test cl, 15 ; test if dest aligned
jz XmmMovLargeTest ; go try 128-byte blocks
;
; Move alignment bytes.
;
XmmMovAlign:
mov rax, rcx ; save unaligned store address
and rcx, -16 ; rcx is deferred store address
movupsxmm1, xmm0 ; copy unaligned last bytes to xmm1
movupsxmm0, ; load deferred-store bytes
movups, xmm1 ; now safe to do unaligned store
mov r8, rcx ; easier to recalc r8 using rcx-r11 ...
sub r8, r11 ; ... than calc how much to subtract from r8
;
; See if we can move any 128-byte blocks.
;
XmmMovLargeTest:
mov r9, r8 ; copy count of bytes remaining
shr r9, 7 ; compute number of 128-byte blocks
jz short XmmMovSmallTest ; if z jump around to 2nd loop
movaps, xmm0 ; going into 1st loop, ok to store deferred bytes
jmp short XmmMovLargeInner; jump into 1st loop
;
; Move 128-byte blocks
;
align 16
XmmMovLargeOuter:
movaps(128-112), xmm0 ; store 7th chunk from prior iteration
movaps(128-128), xmm1 ; store 8th chunk from prior iteration
XmmMovLargeInner:
movupsxmm0, (-16) ; load first 16 byte chunk
movupsxmm1, (-32) ; load 2nd 16 byte chunk
sub rcx, 128 ; reduce destination address
movaps(128-16), xmm0 ; store first 16 byte chunk
movaps(128-32), xmm1 ; store 2nd 16 byte chunk
movupsxmm0, (128-48) ; load 3rd chunk
movupsxmm1, (128-64) ; load 4th chunk
dec r9 ; dec block counter (set cc for jnz)
movaps(128-48), xmm0 ; store 3rd chunk
movaps(128-64), xmm1 ; store 4th chunk
movupsxmm0, (128-80) ; load 5th chunk
movupsxmm1, (128-96) ; load 6th chunk
movaps(128-80), xmm0 ; store 5th chunk
movaps(128-96), xmm1 ; store 6th chunk
movupsxmm0, (128-112); load 7th chunk
movupsxmm1, (128-128); load 8th chunk
jnz short XmmMovLargeOuter ; loop if more blocks
movaps(128-112), xmm0 ; store 7th chunk from final iteration
and r8, 127 ; compute remaining byte count
movapsxmm0, xmm1 ; 8th chunk becomes deferred bytes
;
; See if we have any 16-byte blocks left to move
;
XmmMovSmallTest:
mov r9, r8 ; copy count of bytes remaining
shr r9, 4 ; compute number of 16-byte blocks
jz short XmmMovTrailing ; if z, no 16-byte blocks
align 16
XmmMovSmallLoop:
movups, xmm0 ; the first time through this is the
; store of the deferred bytes from above
sub rcx, 16 ; reduce dest addr
movupsxmm0, ; load a block
dec r9
jnz XmmMovSmallLoop
XmmMovTrailing:
and r8, 15 ; compute remaining byte count
jz short XmmMovReturn ; if z, no residual bytes to move
;
; Handle remainder bytes.
;
; As at the start, we are going to do an unaligned copy of 16 bytes which will double-write
; some bytes.We must not touch rcx or xmm0 because they have what we need to store the
; deferred block. But unlike for mcpyxmm code above, we have r10 and r11 we can just use
; to copy the lowest 16 bytes.
;
movupsxmm1, ; load lowest 16 bytes, which includes remainder
movups, xmm1 ; store lowest 16 bytes, which includes remainder
XmmMovReturn:
movups, xmm0 ; store deferred bytes
mov rax, r11 ; we must return destination address
ret
LEAF_END memcpy, _TEXT
end
/***
*memcpy.c - contains memcpy routine
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*Purpose:
* memcpy() copies a source memory buffer to a destination buffer.
* Overlapping buffers are not treated specially, so propogation may occur.
*
*******************************************************************************/
#include <cruntime.h>
#include <string.h>
#pragma function(memcpy)
/***
*memcpy - Copy source buffer to destination buffer
*
*Purpose:
* memcpy() copies a source memory buffer to a destination memory buffer.
* This routine does NOT recognize overlapping buffers, and thus can lead
* to propogation.
*
* For cases where propogation must be avoided, memmove() must be used.
*
*Entry:
* void *dst = pointer to destination buffer
* const void *src = pointer to source buffer
* size_t count = number of bytes to copy
*
*Exit:
* Returns a pointer to the destination buffer
*
*Exceptions:
*******************************************************************************/
void * __cdecl memcpy (
void * dst,
const void * src,
size_t count
)
{
void * ret = dst;
/*
* copy from lower addresses to higher addresses
*/
while (count--) {
*(char *)dst = *(char *)src;
dst = (char *)dst + 1;
src = (char *)src + 1;
}
return(ret);
}
其实在远古时代,DOS的年代,有人玩内存到内存DMA呢,不过据说都不是很成功。 不判断内存重叠的话还不如用这货:
https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/hhta9830(v%3dvs.100) tangptr@126.com 发表于 2018-7-27 10:05
不判断内存重叠的话还不如用这货:
https://docs.microsoft.com/en-us/previous-versions/visualstudio/vis ...
然而非atom架构的机器上这货烂得一匹 0xAA55 发表于 2018-7-27 22:35
然而非atom架构的机器上这货烂得一匹
mov_char:
... ...
mov edi,
mov esi,
mov ecx,
rep movsb
... ...
ret
总比
move_char:
push ebp
mov ebp, esp
sub esp, 0x0c
mov eax,
mov edi, eax
mov esi,
mov ecx, dword ptr
move_loop:
mov bl, byte ptr
mov byte ptr , bl
inc esi
inc edi
dec ecx
jnz move_loop
mov esp, ebp
pop ebp
ret
要好。 emm这一堆代码真的长以后潜伏在这个论坛了 小弟目前还在学一些简单的汇编,有些指令看得懂,有些指令看不懂(大部分),但是无疑发现memcpy有700多行的asm程序是多么兴奋的事情。
页:
[1]