Windows下VC++編譯器32位memcpy、memmove函數匯編代碼詳解
整理者:赤勇玄心行天道
QQ號:280604597
微信號:qq280604597
QQ群:511046632
博客:http://www.rzrgm.cn/gaoyaguo http://blog.csdn.net/cyz7758520?type=blog
大家有什么不明白的地方,或者想要詳細了解的地方可以聯系我,我會認真回復的!
你可以隨意轉載,無需注明出處!
寫文檔實屬不易,我希望大家能支持我、捐助我,金額隨意,1塊也是支持,我會繼續幫助大家解決問題!

memcpy和memmove函數是相同的匯編代碼,都支持內存重疊時的復制,這個匯編代碼我認為寫的比較雜亂,大體流程如下:
- 判斷src源始緩沖區和dst目的緩沖區是否存在重疊:
- 如果dst地址小于等于src地址,或dst地址大于等于src+len地址,表示沒有重疊,進行從低到高地址復制;
- 如果dst地址大于src地址,且dst地址小于src+len地址,表示有重疊,進行從高到低地址復制。
- CopyUp從低到高地址復制:
- 如果len長度小于32,就用MovDword或MovByte指令復制。
- 如果len長度小于128:
- 如果當前CPU支持SSE2指令,就用MovdqXmmword指令復制。
- 如果當前CPU不支持SSE2指令,就用RepMovsd指令復制。
- 如果len長度大于等于128:
- 如果當前CPU支持增強的快速字符串,就用RepMovsb指令復制。
- 如果當前CPU不支持增強的快速字符串,就用MovdqXmmword或RepMovsd或Palign指令復制。
- CopyDown從低到高地址復制:
- 如果len長度小于32,就用MovDword或MovByte指令復制。
- 如果len長度大于等于32:
- 如果當前CPU支持SSE2指令,就用MovdqXmmword指令復制。
- 如果當前CPU不支持SSE2指令,就用RepMovsd指令復制。
memcpy函數匯編代碼源文件通常在“C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.37.32822\crt\src\x64\memcpy.asm”,
以下是匯編代碼的詳解:
page ,132
title memcpy - Copy source memory bytes to destination
;***
;memcpy.asm - contains memcpy and memmove routines
;
; Copyright (c) Microsoft Corporation. All rights reserved.
;
;Purpose:
; memcpy() copies a source memory buffer to a destination buffer.
; Overlapping buffers are not treated specially, so propagation may occur.
; memmove() copies a source memory buffer to a destination buffer.
; Overlapping buffers are treated specially, to avoid propagation.
;
;*******************************************************************************
.xlist
include vcruntime.inc
.list
.xmm
M_EXIT macro
ret ; _cdecl return
endm ; M_EXIT
PALIGN_memcpy macro d
MovPalign&d&:
movdqa xmm1,xmmword ptr [esi-d]
lea esi, byte ptr [esi-d]
align @WordSize
PalignLoop&d&:
movdqa xmm3,xmmword ptr [esi+10h]
sub ecx,30h
movdqa xmm0,xmmword ptr [esi+20h]
movdqa xmm5,xmmword ptr [esi+30h]
lea esi, xmmword ptr [esi+30h]
cmp ecx,30h
movdqa xmm2,xmm3
palignr xmm3,xmm1,d
movdqa xmmword ptr [edi],xmm3
movdqa xmm4,xmm0
palignr xmm0,xmm2,d
movdqa xmmword ptr [edi+10h],xmm0
movdqa xmm1,xmm5
palignr xmm5,xmm4,d
movdqa xmmword ptr [edi+20h],xmm5
lea edi, xmmword ptr [edi+30h]
jae PalignLoop&d&
lea esi, xmmword ptr [esi+d]
endm ; PALIGN_memcpy
CODESEG
extrn __isa_available:dword
extrn __isa_enabled:dword
extrn __favor:dword
page
;***
;memcpy - Copy source buffer to destination buffer
;
;Purpose:
; memcpy() copies a source memory buffer to a destination memory buffer.
; This routine does NOT recognize overlapping buffers, and thus can lead
; to propagation.
; For cases where propagation 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 propagation.
; For cases where propagation 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 <Sysmemmove> ; 設置本函數名稱為Sysmemmove。
else ; MEM_MOVE
_MEM_ equ <Sysmemcpy> ; 設置本函數名稱為Sysmemcpy。
endif ; MEM_MOVE
% public _MEM_ ; memcpy或memmove函數聲明。
_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 ; 保存edi到棧。
push esi ; 保存esi到棧。
; size param/4 prolog byte #reg saved
.FPO ( 0, 3 , $-_MEM_ , 2, 0, 0 )
mov esi,[esp + 010h] ; 設置esi為src地址。
mov ecx,[esp + 014h] ; 設置ecx為len長度,單位為字節。
mov edi,[esp + 0Ch] ; 設置edi為dst地址。
;
; 檢查源始緩沖區和目的緩沖區是否重疊:
; 如果 (dst <= src) 或 (dst >= src + len) 則
; 沒有重疊,執行從低到高地址復制
; 否則
; 有重疊,執行從高到低地址復制
;
mov eax,ecx ; 設置eax為ecx,也就是len長度。
mov edx,ecx ; 設置edx為ecx,也就是len長度。
add eax,esi ; 設置eax為esi+eax,也就是src+len地址。
cmp edi,esi ; 減法比較edi和esi,也就是dst地址和src地址。
jbe short CopyUp ; 如果edi無符號小于等于esi,也就是dst地址無符號小于等于src地址,表示src與dst緩沖區沒有重疊,進行從低到高地址復制。
cmp edi,eax ; 減法比較edi和eax,也就是dst地址和src+len地址。
jb CopyDown ; 如果edi無符號小于eax,也就是dst地址無符號小于src+len地址,表示src與dst緩沖區有重疊,進行從高到低地址復制。
; 如果edi無符號大于等于eax,也就是dst地址無符號大于等于src+len地址,表示src與dst緩沖區沒有重疊,進行從低到高地址復制。
CopyUp: ; 從低到高地址復制。
cmp ecx, 020h ; 減法比較ecx和32,也就是len和32。
jb CopyUpDwordMov ; 如果ecx無符號小于32,也就是len無符號小于32,就進行從低到高地址MovDword或MovByte指令復制的源始地址未對齊目的地址未對齊的0~31字節復制。
cmp ecx, 080h ; 減法比較ecx和128,也就是len和128。
jae CopyUpLargeMov ; 如果ecx無符號大于等于128,也就是len無符號大于等于128,就進行從低到高地址Sse2或RepMovsb指令復制的源始地址未對齊目的地址未對齊的大于等于128字節復制。
bt __isa_enabled, __ISA_AVAILABLE_SSE2 ; 檢測當前CPU是否支持SSE2指令集。
jc XmmCopySmallTest ; 如果當前CPU支持SSE2指令集,就進行從低到高地址MovdqXmmword指令復制的源始地址未對齊目的地址未對齊的0~127字節復制。
jmp Dword_align ; 如果當前CPU不支持SSE2指令集,就進行從低到高地址RepMovsd指令復制的源始地址未對齊目的地址未對齊的大于等于4字節復制。
CopyUpLargeMov: ; 從低到高地址Sse2或RepMovsb指令復制的源始地址未對齊目的地址未對齊的大于等于128字節復制。
bt __favor, __FAVOR_ENFSTRG ; 檢測當前CPU是否支持增強的快速字符串(Enhanced Fast Strings Rep Movsb/Stosb、ERMSB,通過cpuid.7.0.ebx:D9指令獲取,該特性執行rep movsb可以非常快)。
jnc CopyUpSSE2Check ; 如果當前CPU不支持增強的快速字符串,就進行從低到高地址Sse2指令復制的源始地址未對齊目的地址未對齊的大于等于128字節復制。
rep movsb ; 如果當前CPU支持增強的快速字符串,就進行RepMovsb指令復制。
mov eax,[esp + 0Ch] ; 設置本函數返回值為最初的dst地址。
pop esi ; 從棧恢復esi。
pop edi ; 從棧恢復edi。
M_EXIT ; 本函數返回。
;
; Check if source and destination are equally aligned.
;
CopyUpSSE2Check: ; 從低到高地址Sse2指令復制的源始地址未對齊目的地址未對齊的大于等于128字節復制。
mov eax,edi ; 設置eax為edi,也就是dst地址。
xor eax,esi ; 設置eax為eax與esi異或,也就是src地址與dst地址異或。
test eax,15 ; 檢測異或后的低4位是否為0。
jne AtomChk ; 如果不為0,表示src地址與dst地址不能同時16字節對齊,就進行Atom復制。
; 如果為0,表示src地址與dst地址可以同時16字節對齊,就可以判斷是否使用xmm進行復制。
bt __isa_enabled, __ISA_AVAILABLE_SSE2 ; 檢測當前CPU是否支持SSE2指令集。
jc XmmCopy ; 如果當前CPU支持SSE2指令集,就進行從低到高地址MovdqXmmword指令復制的源始地址未對齊目的地址未對齊的大于等于128字節復制。
; 如果當前CPU不支持SSE2指令集,就進行Atom復制。
AtomChk: ; 進行Atom復制。
bt __favor, __FAVOR_ATOM ; 檢測當前CPU是否支持Atom。
jnc Dword_align ; 如果當前CPU不支持Atom,就進行從低到高地址RepMovsd指令復制的源始地址未對齊目的地址未對齊的大于等于4字節復制。
test edi, 3 ; 判斷edi的低2位dst是否為0,也就是dst地址是否4字節對齊。
jne Dword_align ; 如果edi的低2位不為0,表示dst地址未4字節對齊,就進行從低到高地址RepMovsd指令復制的源始地址未對齊目的地址未對齊的大于等于4字節復制。
test esi, 3 ; 判斷esi的低2位dst是否為0,也就是src地址是否4字節對齊。
jne Dword_align_Ok ; 如果esi的低2位不為0,表示src地址未4字節對齊,就進行從低到高地址RepMovsd指令復制的源始地址未對齊目的地址已4字節對齊的任意字節復制。
; 如果當前CPU支持Atom,且dst地址已4字節對齊,且src地址已4字節對齊,就進行從低到高地址Palign指令復制。
; A software pipelining vectorized memcpy loop using PALIGN instructions 這個Palign指令復制目前我還沒看懂。
; (1) copy the first bytes to align dst up to the nearest 16-byte boundary
; 4 byte align -> 12 byte copy, 8 byte align -> 8 byte copy, 12 byte align -> 4 byte copy
PalignHead4:
bt edi, 2
jae PalignHead8
mov eax, dword ptr [esi]
sub ecx, 4
lea esi, byte ptr [esi+4]
mov dword ptr [edi], eax
lea edi, byte ptr [edi+4]
PalignHead8:
bt edi, 3
jae PalignLoop
movq xmm1, qword ptr [esi]
sub ecx, 8
lea esi, byte ptr [esi+8]
movq qword ptr [edi], xmm1
lea edi, byte ptr [edi+8]
;(2) Use SSE palign loop
PalignLoop:
test esi, 7
je MovPalign8
bt esi, 3
jae MovPalign4
PALIGN_memcpy 12
jmp PalignTail
PALIGN_memcpy 8
jmp PalignTail
PALIGN_memcpy 4
;(3) Copy the tailing bytes.
PalignTail:
cmp ecx,10h
jb PalignTail4
movdqu xmm1,xmmword ptr [esi]
sub ecx, 10h
lea esi, xmmword ptr [esi+10h]
movdqa xmmword ptr [edi],xmm1
lea edi, xmmword ptr [edi+10h]
jmp PalignTail
PalignTail4:
bt ecx, 2
jae PalignTail8
mov eax, dword ptr [esi]
sub ecx,4
lea esi, byte ptr [esi+4]
mov dword ptr [edi], eax
lea edi, byte ptr [edi+4]
PalignTail8:
bt ecx, 3
jae PalignTailLE3
movq xmm1, qword ptr [esi]
sub ecx,8
lea esi, byte ptr [esi+8]
movq qword ptr [edi], xmm1
lea edi, byte ptr [edi+8]
PalignTailLE3:
mov eax, dword ptr TrailingUpVec[ecx*4]
jmp eax
; The algorithm for forward moves is to align the destination to a dword
; boundary and so we can move dwords with an aligned destination. This
; occurs in 3 steps.
;
; - move x = ((4 - Dest & 3) & 3) bytes
; - move y = ((L-x) >> 2) dwords
; - move (L - x - y*4) bytes
;
Dword_align: ; 從低到高地址RepMovsd指令復制的源始地址未對齊目的地址未對齊的大于等于4字節復制。
test edi,11b ; 邏輯與比較edi和3,也就是dst地址的低2位。
jz short Dword_align_Ok ; 如果edi的低2位為0,表示dst地址已4字節對齊,就進行從低到高地址RepMovsd指令復制的源始地址未對齊目的地址已4字節對齊的任意字節復制。
; 如果edi的低2位不為0,表示dst地址未4字節對齊,需要進行dst地址4字節對齊。
Dword_up_align_loop: ; 從低到高地址RepMovsd指令復制的目的地址4字節對齊。
mov al, byte ptr [esi] ; 設置al為esi地址的1字節數據。
mov byte ptr [edi], al ; 設置edi地址的1字節數據為al。
dec ecx ; 設置ecx遞減1。
add esi, 1 ; 設置esi遞增1。
add edi, 1 ; 設置edi遞增1。
test edi, 11b ; 邏輯與比較edi和3,也就是dst地址的低2位。
jnz Dword_up_align_loop ; 如果edi的低2位不為0,表示dst地址沒有4字節對齊,還需要繼續進行4字節對齊。
; 如果edi地低2位為0,表示dst地址已4字節對齊。
Dword_align_Ok: ; 從低到高地址RepMovsd指令復制的源始地址未對齊目的地址已4字節對齊的任意字節復制。
mov edx, ecx ; 設置edx為ecx。
cmp ecx, 32 ; 減法比較ecx與32。
jb CopyUpDwordMov ; 如果ecx小于32,表示len長度小于32字節,就進行從低到高地址MovDword或MovByte指令復制的源始地址未對齊目的地址未對齊的0~31字節復制。
shr ecx,2 ; 設置ecx右移2位,也就是計算剩余dword的復制個數。
rep movsd ; 將esi地址進行dword字符串復制到edi地址,ecx為dword的復制個數。
and edx,11b ; 設置edx為len長度的低2位,也就是rep movsd復制后剩余的0~3字節len長度。
jmp dword ptr TrailingUpVec[edx*4] ; 進行從低到高地址MovByte指令復制的源始地址未對齊目的地址未對齊的0~3字節復制。
;
; 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 possible
; 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
ByteCopyUp:
jmp dword ptr TrailingUpVec[ecx*4+16] ; process just bytes
;-----------------------------------------------------------------------------
align @WordSize
TrailingUpVec dd TrailingUp0, TrailingUp1, TrailingUp2, TrailingUp3 ; 從低到高地址MovByte指令復制的源始地址未對齊目的地址未對齊的0~3字節跳轉表。
align @WordSize
TrailingUp0: ; 從低到高地址MovByte指令復制的源始地址未對齊目的地址未對齊的0字節復制。
mov eax,[esp + 0Ch] ; 設置本函數返回值為最初的dst地址。
pop esi ; 從棧恢復esi。
pop edi ; 從棧恢復edi。
; 空閑備用行。
M_EXIT ; 本函數返回。
align @WordSize
TrailingUp1: ; 從低到高地址MovByte指令復制的源始地址未對齊目的地址未對齊的1字節復制。
mov al,[esi] ; 設置al為esi地址的1字節數據。
; 空閑備用行。
mov [edi],al ; 設置edi地址的1字節數據為al。
mov eax,[esp + 0Ch] ; 設置本函數返回值為最初的dst地址。
pop esi ; 從棧恢復esi。
pop edi ; 從棧恢復edi。
M_EXIT ; 本函數返回。
align @WordSize
TrailingUp2: ; 從低到高地址MovByte指令復制的源始地址未對齊目的地址未對齊的2字節復制。
mov al,[esi] ; 設置al為esi地址的1字節數據。
; 空閑備用行。
mov [edi],al ; 設置edi地址的1字節數據為al。
mov al,[esi+1] ; 設置al為esi+1地址的1字節數據。
mov [edi+1],al ; 設置edi+1地址的1字節數據為al。
mov eax,[esp + 0Ch] ; 設置本函數返回值為最初的dst地址。
pop esi ; 從棧恢復esi。
pop edi ; 從棧恢復edi。
M_EXIT ; 本函數返回。
align @WordSize
TrailingUp3: ; 從低到高地址MovByte指令復制的源始地址未對齊目的地址未對齊的3字節復制。
mov al,[esi] ; 設置al為esi地址的1字節數據。
; 空閑備用行。
mov [edi],al ; 設置edi地址的1字節數據為al。
mov al,[esi+1] ; 設置al為esi+1地址的1字節數據。
mov [edi+1],al ; 設置edi+1地址的1字節數據為al。
mov al,[esi+2] ; 設置al為esi+2地址的1字節數據。
mov [edi+2],al ; 設置edi+2地址的1字節數據為al。
mov eax,[esp + 0Ch] ; 設置本函數返回值為最初的dst地址。
pop esi ; 從棧恢復esi。
pop edi ; 從棧恢復edi。
M_EXIT ; 本函數返回。
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
align @WordSize
CopyDown: ; 從高到低地址復制。
; inserting check for size. For < 16 bytes, use dwords without checking for alignment
lea esi, [esi+ecx] ; 設置esi為esi+ecx,也就是src結束地址。
lea edi, [edi+ecx] ; 設置edi為edi+ecx,也就是dst結束地址。
cmp ecx, 32 ; 減法比較ecx和32。
jb CopyDownSmall ; 如果ecx無符號小于32,表示len長度小于32,就進行從高到低地址MovDword或MovByte指令復制的源始地址未對齊目的地址未對齊的0~31字節復制。
bt __isa_enabled, __ISA_AVAILABLE_SSE2 ; 檢測當前CPU是否支持SSE2指令集。
jc XmmMovLargeAlignTest ; 如果當前CPU支持SSE2指令集,就進行從高到低地址MovdqXmmword指令復制的源始地址未對齊目的地址未對齊的大于等于16字節復制。
; 如果當前CPU不支持SSE2指令集,就進行從高到低地址RepMovsd指令復制的源始地址未對齊目的地址未對齊的大于等于4字節復制。
; See if the destination start is dword aligned
test edi,11b ; 邏輯與比較edi和3。
jz CopyDownAligned ; 如果為0,表示dst地址低2位為0,表示dst地址已4字節對齊,就進行從高到低地址RepMovsd指令復制的源始地址未對齊目的地址已4字節對齊的任意字節復制。
CopyDownNotAligned: ; 從高到低地址RepMovsd指令復制的源始地址未對齊目的地址未對齊的大于等于4字節復制。
mov edx,edi ; 設置edx為edi,也就是dst地址。
and edx, 11b ; 設置edx為edx邏輯與3,也就是dst地址的低2位。
sub ecx, edx ; 設置ecx為ecx減edx,也就是len長度減dst地址4字節對齊的長度。
CopyDownAlignLoop:
mov al, byte ptr [esi-1] ; 設置al為esi-1地址的1字節數據。
mov byte ptr[edi-1], al ; 設置edi-1地址的1字節數據為al。
dec esi ; 設置esi為esi-1。
dec edi ; 設置edi為edi-1。
sub edx, 1 ; 設置edx為edx-1。
jnz CopyDownAlignLoop ; 如果edx不為0,表示dst地址未4字節對齊,繼續進行4字節對齊。
; 如果edx為0,表示dst地址已4字節對齊,進行從高到低地址RepMovsd指令復制的源始地址未對齊目的地址已4字節對齊的任意字節復制。
CopyDownAligned: ; 從高到低地址RepMovsd指令復制的源始地址未對齊目的地址已4字節對齊的任意字節復制。
cmp ecx,32 ; 減法比較ecx和32。
jb CopyDownSmall ; 如果ecx無符號小于32,表示len長度小于32,就進行從高到低地址MovDword或MovByte指令復制的源始地址未對齊目的地址未對齊的0~31字節復制。
mov edx, ecx ; 設置edx為ecx。
shr ecx,2 ; 設置ecx為ecx無符號邏輯右移2位,也就是ecx除以4,表示RepMovsd指令復制Dword個數。
and edx,11b ; 設置edx為edx邏輯與3,也就是len長度的低2位。
sub esi, 4 ; 設置esi為esi-4,也就是src-4地址,因為要進行從高到低地址RepMovsd指令復制。
sub edi, 4 ; 設置edi為edi-4,也就是dst-4地址,因為要進行從高到低地址RepMovsd指令復制。
std ; 設置RepMovsd指令的方向為從高到低地址。
rep movsd ; 進行從高到低地址RepMovsd指令復制。
cld ; 設置RepMovsd指令的方向為從低到高地址。
jmp dword ptr TrailingDownVec[edx*4]; 進行從高到低地址MovByte指令復制的源始地址未對齊目的地址未對齊的0~3字節復制。
;-----------------------------------------------------------------------------
align @WordSize
TrailingDownVec dd TrailingDown0, TrailingDown1, TrailingDown2, TrailingDown3 ; 從高到低地址MovByte指令復制的源始地址未對齊目的地址未對齊的0~3字節跳轉表。
align @WordSize
TrailingDown0: ; 從高到低地址MovByte指令復制的源始地址未對齊目的地址未對齊的0字節復制。
mov eax,[esp + 0Ch] ; 設置本函數返回值為最初的dst地址。
; 空閑備用行。
pop esi ; 從棧恢復esi。
pop edi ; 從棧恢復edi。
M_EXIT ; 本函數返回。
align @WordSize
TrailingDown1: ; 從高到低地址MovByte指令復制的源始地址未對齊目的地址未對齊的1字節復制。
mov al,[esi+3] ; 設置al為esi+3地址的1字節數據。
; 空閑備用行。
mov [edi+3],al ; 設置edi+3地址的1字節數據為al。
mov eax,[esp + 0Ch] ; 設置本函數返回值為最初的dst地址。
pop esi ; 從棧恢復esi。
pop edi ; 從棧恢復edi。
M_EXIT ; 本函數返回。
align @WordSize
TrailingDown2: ; 從高到低地址MovByte指令復制的源始地址未對齊目的地址未對齊的2字節復制。
mov al,[esi+3] ; 設置al為esi+3地址的1字節數據。
; 空閑備用行。
mov [edi+3],al ; 設置edi+3地址的1字節數據為al。
mov al,[esi+2] ; 設置al為esi+2地址的1字節數據。
mov [edi+2],al ; 設置edi+2地址的1字節數據為al。
mov eax,[esp + 0Ch] ; 設置本函數返回值為最初的dst地址。
pop esi ; 從棧恢復esi。
pop edi ; 從棧恢復edi。
M_EXIT ; 本函數返回。
align @WordSize
TrailingDown3: ; 從高到低地址MovByte指令復制的源始地址未對齊目的地址未對齊的3字節復制。
mov al,[esi+3] ; 設置al為esi+3地址的1字節數據。
; 空閑備用行。
mov [edi+3],al ; 設置edi+3地址的1字節數據為al。
mov al,[esi+2] ; 設置al為esi+2地址的1字節數據。
mov [edi+2],al ; 設置edi+2地址的1字節數據為al。
mov al,[esi+1] ; 設置al為esi+1地址的1字節數據。
mov [edi+1],al ; 設置edi+1地址的1字節數據為al。
mov eax,[esp + 0Ch] ; 設置本函數返回值為最初的dst地址。
pop esi ; 從棧恢復esi。
pop edi ; 從棧恢復edi。
M_EXIT ; 本函數返回。
; Copy overlapping buffers using XMM registers
XmmMovLargeAlignTest: ; 從高到低地址MovdqXmmword指令復制的源始地址未對齊目的地址未對齊的大于等于16字節復制。
test edi, 0Fh ; 邏輯與比較edi和15。
jz XmmMovLargeLoop ; 如果為0,表示edi地址的低4位為0,表示dst地址已16字節對齊,就進行從高到低地址MovdqXmmword指令復制的源始地址未對齊目的地址已16字節對齊的任意字節復制。
; 如果不為0,表示edi地址的低4位不為0,表示dst地址未16字節對齊,就進行16字節對齊。
XmmMovAlignLoop:
dec ecx ; 設置ecx為ecx-1。
dec esi ; 設置esi為esi-1。
dec edi ; 設置edi為edi-1。
mov al, [esi] ; 設置al為esi地址的1字節數據。
mov [edi], al ; 設置edi地址的1字節數據為al。
test edi, 0Fh ; 檢測edi地址的低4位是否為0。
jnz XmmMovAlignLoop ; 如果edi地址的低4位不為0,表示edi地址未16字節對齊,就繼續進行16字節對齊。
; 如果edi地址的低4位為0,表示edi地址已16字節對齊,就進行從高到低地址MovdqXmmword指令復制的源始地址未對齊目的地址已16字節對齊的任意字節復制。
XmmMovLargeLoop: ; 從高到低地址MovdqXmmword指令復制的源始地址未對齊目的地址已16字節對齊的任意字節復制。
cmp ecx, 128 ; 減法比較ecx和128。
jb XmmMovSmallTest ; 如果ecx無符號小于128,就進行從高到低地址MovdqXmmword指令復制的源始地址未對齊目的地址已16字節對齊的0~127字節復制。
sub esi, 128 ; 設置esi為esi-128,也就是src-128地址。
sub edi, 128 ; 設置edi為edi-128,也就是dst-128地址。
movdqu xmm0, xmmword ptr[esi] ; 設置xmm0為esi地址的16字節數據。
movdqu xmm1, xmmword ptr[esi+16] ; 設置xmm1為esi+16地址的16字節數據。
movdqu xmm2, xmmword ptr[esi+32] ; 設置xmm2為esi+32地址的16字節數據。
movdqu xmm3, xmmword ptr[esi+48] ; 設置xmm3為esi+48地址的16字節數據。
movdqu xmm4, xmmword ptr[esi+64] ; 設置xmm4為esi+64地址的16字節數據。
movdqu xmm5, xmmword ptr[esi+80] ; 設置xmm5為esi+80地址的16字節數據。
movdqu xmm6, xmmword ptr[esi+96] ; 設置xmm6為esi+96地址的16字節數據。
movdqu xmm7, xmmword ptr[esi+112] ; 設置xmm7為esi+112地址的16字節數據。
movdqu xmmword ptr[edi], xmm0 ; 設置edi地址的16字節數據為xmm0。
movdqu xmmword ptr[edi+16], xmm1 ; 設置edi+16地址的16字節數據為xmm1。
movdqu xmmword ptr[edi+32], xmm2 ; 設置edi+32地址的16字節數據為xmm2。
movdqu xmmword ptr[edi+48], xmm3 ; 設置edi+48地址的16字節數據為xmm3。
movdqu xmmword ptr[edi+64], xmm4 ; 設置edi+64地址的16字節數據為xmm4。
movdqu xmmword ptr[edi+80], xmm5 ; 設置edi+80地址的16字節數據為xmm5。
movdqu xmmword ptr[edi+96], xmm6 ; 設置edi+96地址的16字節數據為xmm6。
movdqu xmmword ptr[edi+112], xmm7 ; 設置edi+112地址的16字節數據為xmm7。
sub ecx, 128 ; 設置ecx為ecx-128,也就是len長度-128。
test ecx, 0FFFFFF80h ; 邏輯與比較ecx和4294967168。
jnz XmmMovLargeLoop ; 如果不為0,表示len長度的高25位不為0,表示len長度大于等于128,就繼續進行從高到低地址MovdqXmmword指令復制。
; 如果為0,表示len長度的高25位為0,表示len長度小于128,就進行從高到低地址MovdqXmmword指令復制的源始地址未對齊目的地址已16字節對齊的0~127字節復制。
XmmMovSmallTest: ; 從高到低地址MovdqXmmword指令復制的源始地址未對齊目的地址已16字節對齊的0~127字節復制。
cmp ecx, 32 ; 減法比較ecx和32。
jb CopyDownSmall ; 如果ecx無符號小于32,就進行從高到低地址MovDword或MovByte指令復制的源始地址未對齊目的地址未對齊的0~31字節復制。
XmmMovSmallLoop:
sub esi, 32 ; 設置esi為esi-32,也就是src-32地址。
sub edi, 32 ; 設置edi為edi-32,也就是dst-32地址。
movdqu xmm0, xmmword ptr[esi] ; 設置xmm0為esi地址的16字節數據。
movdqu xmm1, xmmword ptr[esi+16] ; 設置xmm1為esi+16地址的16字節數據。
movdqu xmmword ptr[edi], xmm0 ; 設置edi地址的16字節數據為xmm0。
movdqu xmmword ptr[edi+16], xmm1 ; 設置edi+16地址的16字節數據為xmm1。
sub ecx, 32 ; 設置ecx為ecx-32,也就是len長度-32。
test ecx, 0FFFFFFE0h ; 邏輯與比較ecx和4294967264。
jnz XmmMovSmallLoop ; 如果不為0,表示len長度的高27位不為0,表示len長度大于等于32,就繼續進行從高到低地址MovdqXmmword指令復制。
; 如果為0,表示len長度的高27位為0,表示len長度小于32,就進行從高到低地址MovDword或MovByte指令復制的源始地址未對齊目的地址未對齊的0~31字節復制。
CopyDownSmall: ; 從高到低地址MovDword或MovByte指令復制的源始地址未對齊目的地址未對齊的0~31字節復制。
test ecx, 0FFFFFFFCh ; 邏輯與比較ecx和4294967292。
jz CopyDownByteTest ; 如果為0,表示len長度的高30位為0,表示len長度小于4,就進行從高到低地址MovByte指令復制的源始地址未對齊目的地址未對齊的0~3字節復制。
; 如果不為0,表示len長度的高30位不為0,表示len長度大于等于4,就進行從高到低地址MovDword指令復制。
CopyDownDwordLoop:
sub edi, 4 ; 設置edi為edi-4。
sub esi, 4 ; 設置esi為esi-4。
mov eax, [esi] ; 設置eax為esi地址的4字節數據。
mov [edi], eax ; 設置edi地址的4字節數據為eax。
sub ecx, 4 ; 設置ecx為ecx-4,也就是len長度-4。
test ecx, 0FFFFFFFCh ; 邏輯與比較ecx和4294967292。
jnz CopyDownDwordLoop ; 如果不為0,表示len長度的高30位不為0,表示len長度大于等于4,就繼續進行從高到低地址MovDword指令復制。
; 如果為0,表示len長度的高30位為0,表示len長度小于4,就進行從高到低地址MovByte指令復制的源始地址未對齊目的地址未對齊的0~3字節復制。
CopyDownByteTest: ; 從高到低地址MovByte指令復制的源始地址未對齊目的地址未對齊的0~3字節復制。
test ecx, ecx ; 邏輯與比較ecx和ecx。
jz CopyDownReturn ; 如果為0,表示len長度為0,就進行函數返回。
CopyDownByteLoop:
sub edi, 1 ; 設置edi為edi-1。
sub esi, 1 ; 設置esi為esi-1。
mov al, [esi] ; 設置al為esi地址的1字節數據。
mov [edi], al ; 設置edi地址的1字節數據為al。
sub ecx, 1 ; 設置ecx為ecx-1。
jnz CopyDownByteLoop ; 如果不為0,表示len長度不為0,就繼續進行從高到低地址MovByte指令復制。
CopyDownReturn:
mov eax,[esp + 0Ch] ; 設置本函數返回值為最初的dst地址。
; 空閑備用行。
pop esi ; 從棧恢復esi。
pop edi ; 從棧恢復edi。
M_EXIT
; Using XMM registers for non-overlapping buffers
align 16
XmmCopy: ; 從低到高地址MovdqXmmword指令復制的源始地址未對齊目的地址未對齊的大于等于128字節復制。src地址與dst地址可以同時16字節對齊。
mov eax, esi ; 設置eax為esi,也就是src地址。
and eax, 0Fh ; 設置eax為eax邏輯與15,也就是計算src地址是否16字節對齊。
; eax = src and dst alignment (src mod 16)
test eax, eax ; 檢測eax是否等于0。
jne XmmCopyUnaligned ; 如果eax不等于0,表示src地址未16字節對齊,就進行從低到高地址MovdqXmmword指令復制的源始地址未對齊目的地址未對齊的大于等于128字節復制。
; in:
; edi = dst (16 byte aligned)
; esi = src (16 byte aligned)
; ecx = len is >= (128 - head alignment bytes)
; do block copy using SSE2 stores
XmmCopyAligned: ; 從低到高地址MovdqXmmword指令復制的源始地址已16字節對齊目的地址已16字節對齊的任意字節復制。
mov edx, ecx ; 設置edx為ecx,也就是剩余長度。
and ecx, 7Fh ; 設置ecx為ecx邏輯與127,也就是movdq xmmword復制后的剩余長度。
shr edx, 7 ; 設置edx為edx邏輯右移7位,也就是movdq xmmword的復制個數。
je XmmCopySmallTest ; 如果edx為0,表示movdq xmmword的復制個數為0,就進行從低到高地址MovdqXmmword指令復制的源始地址未對齊目的地址未對齊的0~127字節復制。
align 16
XmmCopyLargeLoop:
movdqa xmm0,xmmword ptr [esi] ; 設置xmm0為esi地址的16字節數據。
movdqa xmm1,xmmword ptr [esi + 10h]; 設置xmm1為esi+16地址的16字節數據。
movdqa xmm2,xmmword ptr [esi + 20h]; 設置xmm2為esi+32地址的16字節數據。
movdqa xmm3,xmmword ptr [esi + 30h]; 設置xmm3為esi+48地址的16字節數據。
movdqa xmmword ptr [edi],xmm0 ; 設置esi地址的16字節數據為xmm0。
movdqa xmmword ptr [edi + 10h],xmm1; 設置esi+16地址的16字節數據為xmm1。
movdqa xmmword ptr [edi + 20h],xmm2; 設置esi+32地址的16字節數據為xmm2。
movdqa xmmword ptr [edi + 30h],xmm3; 設置esi+48地址的16字節數據為xmm3。
movdqa xmm4,xmmword ptr [esi + 40h]; 設置xmm4為esi+64地址的16字節數據。
movdqa xmm5,xmmword ptr [esi + 50h]; 設置xmm5為esi+80地址的16字節數據。
movdqa xmm6,xmmword ptr [esi + 60h]; 設置xmm6為esi+96地址的16字節數據。
movdqa xmm7,xmmword ptr [esi + 70h]; 設置xmm7為esi+112地址的16字節數據。
movdqa xmmword ptr [edi + 40h],xmm4; 設置esi+64地址的16字節數據為xmm4。
movdqa xmmword ptr [edi + 50h],xmm5; 設置esi+80地址的16字節數據為xmm5。
movdqa xmmword ptr [edi + 60h],xmm6; 設置esi+96地址的16字節數據為xmm6。
movdqa xmmword ptr [edi + 70h],xmm7; 設置esi+112地址的16字節數據為xmm7。
lea esi,[esi + 80h] ; 設置esi為esi+128。
lea edi,[edi + 80h] ; 設置edi為edi+128。
dec edx ; 設置edx遞減1。
jne XmmCopyLargeLoop ; 如果edx不為0,表示movdq xmmword的剩余復制個數不為0,就繼續循環movdq xmmword復制。
; 如果edx為0,表示movdq xmmword的剩余復制個數為0,就進行從低到高地址MovdqXmmword指令復制的源始地址未對齊目的地址未對齊的0~127字節復制。
XmmCopySmallTest: ; 從低到高地址MovdqXmmword指令復制的源始地址未對齊目的地址未對齊的0~127字節復制。
test ecx, ecx ; 比較ecx和ecx。
je CopyUpReturn ; 如果ecx等于0,表示沒有剩余長度,本函數返回。
; ecx = length (< 128 bytes)
mov edx, ecx ; 設置edx為剩余長度ecx。
shr edx, 5 ; 設置edx右移5位,也就是edx除以32,計算xmmword的復制個數。
test edx, edx ; 比較edx和edx。
je CopyUpDwordMov ; 如果edx等于0,表示xmmword的復制個數為0,就進行從低到高地址MovDword或MovByte指令復制的源始地址未對齊目的地址未對齊的0~31字節復制。
; 如果edx不等于0,表示xmmword的復制個數不為0,就進行movdq xmmword復制。
align 16
XmmCopySmallLoop:
movdqu xmm0, xmmword ptr [esi] ; 復制esi地址的16字節數據到xmm0。
movdqu xmm1, xmmword ptr [esi + 10h] ; 復制esi+16地址的16字節數據到xmm1。
movdqu xmmword ptr [edi], xmm0 ; 復制xmm0的16字節數據到edi地址。
movdqu xmmword ptr [edi + 10h], xmm1 ; 復制xmm1的16字節數據到edi+16地址。
lea esi, [esi + 20h] ; 設置esi地址遞增32。
lea edi, [edi + 20h] ; 設置edi地址遞增32。
dec edx ; 設置edx遞減1。
jne XmmCopySmallLoop ; 如果edx不等于0,則繼續循環復制xmmword數據。
; 如果edx等于0,則進行從低到高地址MovDword或MovByte指令復制的源始地址未對齊目的地址未對齊的0~31字節復制。
CopyUpDwordMov: ; 從低到高地址MovDword或MovByte指令復制的源始地址未對齊目的地址未對齊的0~31字節復制。esi為src地址,edi為dst地址,ecx為len長度。
and ecx, 1Fh ; 將剩余長度ecx與31做邏輯與運算。
je CopyUpReturn ; 如果ecx的低5位為0,表示沒有剩余長度,本函數返回。
CopyUpDwordTest:
mov eax, ecx ; 設置eax為剩余長度ecx。
shr ecx, 2 ; 設置ecx右移2位,也就是ecx除以4,計算dword的復制個數。
je CopyUpByteTest ; 如果dword的復制個數為0,則使用byte進行復制。
CopyUpDwordLoop:
mov edx, dword ptr [esi] ; 設置edx為esi地址的dword數據。
mov dword ptr [edi], edx ; 設置edi地址的dword數據為edx。也就是將src地址的dword數據復制到dst地址。
add edi, 4 ; 設置edi地址遞增4。
add esi, 4 ; 設置esi地址遞增4。
sub ecx, 1 ; 設置ecx遞減1。
jne CopyUpDwordLoop ; 如果ecx不等于0,則繼續循環復制dword數據。
; 如果ecx等于0,則對剩余長度進行復制byte數據。
CopyUpByteTest:
mov ecx, eax ; 設置ecx為剩余長度eax。
and ecx, 03h ; 將剩余長度ecx與3做邏輯與運算。
je CopyUpReturn ; 如果ecx的低2位為0,表示沒有剩余長度,本函數返回。
CopyUpByteLoop:
mov al, byte ptr [esi] ; 設置al為esi地址的byte數據。
mov byte ptr [edi], al ; 設置esi地址的byte數據為al。也就是將src地址的byte數據復制到dst地址。
inc esi ; 設置esi地址遞增1。
inc edi ; 設置edi地址遞增1。
dec ecx ; 設置ecx遞減1。
jne CopyUpByteLoop ; 如果ecx不等于0,則繼續循環復制byte數據。
; 如果ecx等于0,則數據已經全部復制完畢,本函數返回。
align 16
CopyUpReturn: ; 本函數返回。
mov eax,[esp + 0Ch] ; 設置本函數返回值為最初的dst地址。
pop esi ; 從棧恢復esi。
pop edi ; 從棧恢復edi。
M_EXIT ; 本函數返回。
; dst addr is not 16 byte aligned
align 16
XmmCopyUnaligned: ; 從低到高地址MovdqXmmword指令復制的源始地址未對齊目的地址未對齊的大于等于128字節復制。src地址與dst地址可以同時16字節對齊。
mov edx, 010h ; 設置edx為16。
sub edx, eax ; 設置edx為edx減eax,eax為src地址邏輯與15,也就是計算src地址進行16字節對齊需要復制多少字節。
sub ecx, edx ; 設置ecx為ecx減edx,也就是src地址進行16字節對齊后的剩余長度。
push ecx ; 保存ecx到棧。
mov eax, edx ; 設置eax為edx,也就是src地址進行16字節對齊需要復制多少字節。
mov ecx, eax ; 設置ecx為eax,也就是src地址進行16字節對齊需要復制多少字節。
and ecx, 03h ; 設置ecx為ecx邏輯與3,也就是進行從低到高地址MovdqXmmword指令復制的源始地址16字節對齊目的地址16字節對齊的MovDword指令復制后的的剩余長度。
je XmmAlignDwordTest ; 如果為0,表示進行mov dword復制的剩余長度為0,就進行mov dword復制。
; 如果不為0,表示進行mov dword復制的剩余長度不為0,就進行從低到高地址MovdqXmmword指令復制的源始地址16字節對齊目的地址16字節對齊的MovDword指令復制后的剩余長度1~3字節復制。
XmmAlignByte: ; 從低到高地址MovdqXmmword指令復制的源始地址16字節對齊目的地址16字節對齊的MovDword指令復制后的剩余長度1~3字節復制。
mov dl, byte ptr [esi] ; 設置dl為esi地址的1字節數據。
mov byte ptr [edi], dl ; 設置edi地址的1字節數據為dl。
inc esi ; 設置esi地址遞增1。
inc edi ; 設置edi地址遞增1。
dec ecx ; 設置ecx遞減1。
jne XmmAlignByte ; 如果ecx不為0,則繼續循環復制byte數據。
; 如果ecx為0,表示進行mov dword復制的剩余長度為0,則進行從低到高地址MovdqXmmword指令復制的源始地址16字節對齊目的地址16字節對齊的MovDword指令復制。
XmmAlignDwordTest: ; 從低到高地址MovdqXmmword指令復制的源始地址16字節對齊目的地址16字節對齊的MovDword指令復制。
shr eax, 2 ; 設置eax為eax邏輯右移2位,也就是計算src地址進行16字節對齊需要復制多少字節的進行mov dword復制的剩余個數。
je XmmAlignAdjustCnt ; 如果eax為0,表示src地址進行16字節對齊需要復制多少字節的進行MovDword指令復制的剩余個數為0,就進行從低到高地址MovdqXmmword指令復制的源始地址16字節對齊目的地址16字節對齊完畢。
; 如果eax不為0,就進行src地址進行16字節對齊需要復制多少字節的進行MovDword指令復制。
XmmAlignDwordLoop:
mov edx, dword ptr [esi] ; 設置edx為esi地址的4字節數據。
mov dword ptr [edi], edx ; 設置edi地址的4字節數據為edx。
lea esi, [esi+4] ; 設置esi地址遞增4。
lea edi, [edi+4] ; 設置edi地址遞增4。
dec eax ; 設置eax遞減一。
jne XmmAlignDwordLoop ; 如果eax不為0,就繼續循環復制dword數據。
XmmAlignAdjustCnt: ; 從低到高地址MovdqXmmword指令復制的源始地址16字節對齊目的地址16字節對齊完畢。
pop ecx ; 從棧恢復ecx。
jmp XmmCopyAligned ; 進行從低到高地址MovdqXmmword指令復制的源始地址已16字節對齊目的地址已16字節對齊的任意字節復制。
_MEM_ endp
end

浙公網安備 33010602011771號