memcpy memcopy 的實現

 

先是VC中的實現直接字符:

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; //不能對void* 直接加1,因爲unknown size
                src 
= (char *)src + 1;
        
}

        
return(ret);
}

 

void * __cdecl memmove (void * dst, const void * src, size_t count)
{
        
void * ret = dst;

        
if (dst <= src || (char *)dst >= ((char *)src + count)) {
                
/*
                 * Non-Overlapping Buffers
                 * copy from lower addresses to higher addresses
                 */

                
while (count--) {
                        
*(char *)dst = *(char *)src;
                        dst 
= (char *)dst + 1;
                        src 
= (char *)src + 1;
                
}
        
}
        
else {
                
/*
                 * Overlapping Buffers
                 * copy from higher addresses to lower addresses
                 */

                dst 
= (char *)dst + count - 1;
                src 
= (char *)src + count - 1;

                
while (count--) {
                        
*(char *)dst = *(char *)src;
                        dst 
= (char *)dst - 1;
                        src 
= (char *)src - 1;
                
}
        
}

        
return(ret);
}

 

引用別人的:

Intel 80386以上支持的指令集中MOVSD指令和REP指令配合將DWORD32bit)在內存間移動,即在一個時鐘週期copy四個字節,整整比MOVSB8bit)指令快了四倍。但是使用MOVSD移動到的目的內存地址必須是32bit對齊的(DWORD-aligned)。簡單說明從低位到高位的內存copy如下。

L爲要拷貝的總字節數,Dest爲目的起始地址,X爲從Dest開始沒有DWORD-aligned的字節數,Y爲要拷貝的DWORD個數,Z爲剩餘的沒有DWORD-aligned字節數。那麼有公式如下:

 

X = (4 – Dest & 3 ) & 3 (bytes)   //低兩位爲0的地址是DWORD-aligned

Y = (L – X) >> 2 (DWORDs)     //整除以4DWORD個數

Z = (L – X – Y * 4) (bytes)

 

總結一下,對大段的內存移動,用memmove將是非常優化的,相反若用c寫的code會降低四倍效率,這就是爲什麼要用ASM直接實現的原因。

 

下面是ASM版本的實現:

memcpy: 

/*-----------------------------------------------------------------------* 
  *   filename   -   memcpy.cas 
  * 
  *   function(s) 
  *                 memcpy   -   copy   a   block   of   n   bytes   from   src   to   dst 
  *-----------------------------------------------------------------------*/ 
#pragma   inline 
#include   <asmrules.h> 
#include   <mem.h> 

#undef   memcpy                                     /*   not   an   intrinsic   */ 

/*-----------------------------------------------------------------------* 

Name                         memcpy   -   copy   a   block   of   n   bytes   from   src   to   dst 

Usage                       void   *memcpy(void   *dst,   const   void   *src,   size_t   n); 

Prototype   in         mem.h   &   string.h 

Description           memcpy   copies     a   block   of   n     bytes   from   src   to     dst. 
                                No   overlap   checking   is   performed. 

Return   value         memcpy   returns   dst 

*------------------------------------------------------------------------*/ 

#if   defined(__FARFUNCS__) 
#include   <_farfunc.h> 
#endif 

#if           1               /*   No   overlap   checking   version   */ 

void   *   _FARFUNC   memcpy(void   *dst,   const   void   *src,   size_t   n) 
{ 
#if   !(LDATA) 
                _ES   =   _DS; 
#endif 
#if           defined(__LARGE__)   ||     defined(__COMPACT__) 
asm           mov           dx,ds                       /*   save   ds   */ 
#endif 
asm           LES_           di,   dst 
asm           LDS_           si,   src 
asm           mov           cx,n 
asm           shr           cx,1 
asm           cld 
asm           rep           movsw 
asm           jnc           cpy_end 
asm           movsb 
cpy_end: 
#if           defined(__LARGE__)   ||   defined(__COMPACT__) 
                asm           mov           ds,dx                       /*   restore   */ 
#endif 
                return(dst); 
} 

#else                       /*   Overlap   checking   version           */ 

void   *   _FARFUNC   memcpy(void   *dst,   const   void   *src,   size_t   n) 
{ 
                movmem(src,dst,n); 
                return(dst); 
} 
#endif 


memmove: 

/*-----------------------------------------------------------------------* 
  *   filename   -   movmem.cas 
  * 
  *   function(s) 
  *                 movmem     -   move   a   block   of   bytes 
  *                 memmove   -   move   a   block   of   bytes 
  *-----------------------------------------------------------------------*/ 
#pragma   inline 
#include   <asmrules.h> 
#include   <mem.h> 

/*-----------------------------------------------------------------------* 

Name                         movmem   -   move   a   block   of   bytes 

Usage                       void   movmem(void   *src,   void   *dst,   unsigned   len); 

Prototype   in         mem.h 

Description           movmem   copies   a   block   of   len     bytes   from   src   to   dst.   If   the 
                                source   and     destination   arrays   overlap,   the     copy   direction 
                                is   chosen   so   that   the   data   is   always   copied   correctly. 

Return   value         There   is   no   return   value 

*------------------------------------------------------------------------*/ 
#if   defined(__FARFUNCS__) 
#include   <_farfunc.h> 
#endif 

void   _FARFUNC   movmem(const   void   *src,   void   *dst,   unsigned   len) 
{ 
#if           LDATA 
#if           !defined(__HUGE__) 
                asm           push         ds 
#endif 
                if             (((void   huge   *)src)   <   ((void   huge   *)dst)) 
#else 
                _ES   =   _DS; 
                if             (src   <   dst) 
#endif 
                {               /*   travel   backward,   need   to   adjust   ptrs   later   */ 
                                asm           std 
                                asm           mov           ax,   1 
                } 
                else 
                {               /*   travel   forward,   no   need   to   adjust   ptrs   */ 
                                asm           cld 
                                asm           xor           ax,   ax 
                } 

asm           LDS_         si,   src 
asm           LES_         di,   dst 
asm           mov           cx,   len 

asm           or             ax,   ax 
asm           jz             movit 
asm           add           si,   cx     /*   backward   move,   adjust   ptrs   to   end-1   */ 
asm           dec           si 
asm           add           di,   cx 
asm           dec           di 
movit: 
asm           test         di,   1 
asm           jz             isAligned 
asm           jcxz         done 
asm           movsb 
asm           dec           cx 
isAligned: 
asm           sub           si,   ax     /*   compensate   for   word   moves   */ 
asm           sub           di,   ax 
asm           shr           cx,   1 
asm           rep           movsw 
asm           jnc           noOdd 
asm           add           si,   ax     /*   compensate   for   final   byte   */ 
asm           add           di,   ax 
asm           movsb 
noOdd: 
done: 
asm           cld 

#if           defined(__LARGE__)   ||     defined(__COMPACT__) 
                asm           pop           ds 
#endif 
} 


/*-----------------------------------------------------------------------* 

Name                         memmove   -   move   a   block   of   bytes 

Usage                       void   memmove(void   *dst,   const   void   *scr,   unsigned   len); 

Prototype   in         mem.h 

Description           memmove   copies   a   block   of   len     bytes   from   src   to   dst.   If   the 
                                source   and     destination   arrays   overlap,   the     copy   direction 
                                is   chosen   so   that   the   data   is   always   copied   correctly. 

Return   value         dst 

*------------------------------------------------------------------------*/ 
void   *_CType   _FARFUNC   memmove(   void   *dst,   const   void   *src,   size_t   n   ) 
{ 
        movmem(   (void   *)src,   dst,   n   ); 
        return(   dst   ); 
} 

 

 

發佈了10 篇原創文章 · 獲贊 1 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章