strcpy汇编源码:
strcpy proc \
dst:ptr byte, \
src:ptr byte
OPTION PROLOGUE:NONE, EPILOGUE:NONE
push edi ; preserve edi
mov edi,[esp+8] ; edi points to dest string
jmp short copy_start
strcpy endp
copy_start::
mov ecx,[esp+0ch] ; ecx -> sorc string
test ecx,3 ; test if string is aligned on 32 bits
je short main_loop_entrance
src_misaligned: ; simple byte loop until string is aligned
mov dl,byte ptr [ecx]
add ecx,1
test dl,dl
je short byte_0
mov [edi],dl
add edi,1
test ecx,3
jne short src_misaligned
jmp short main_loop_entrance
main_loop: ; edx contains first dword of sorc string
mov [edi],edx ; store one more dword
add edi,4 ; kick dest pointer
main_loop_entrance:
mov edx,7efefeffh
mov eax,dword ptr [ecx] ; read 4 bytes
add edx,eax
xor eax,-1
xor eax,edx
mov edx,[ecx] ; it's in cache now
add ecx,4 ; kick dest pointer
test eax,81010100h
je short main_loop
; found zero byte in the loop
; main_loop_end:
test dl,dl ; is it byte 0
je short byte_0
test dh,dh ; is it byte 1
je short byte_1
test edx,00ff0000h ; is it byte 2
je short byte_2
test edx,0ff000000h ; is it byte 3
je short byte_3
jmp short main_loop ; taken if bits 24-30 are clear and bit
; 31 is set
byte_3:
mov [edi],edx
mov eax,[esp+8] ; return in eax pointer to dest string
pop edi
ret
byte_2:
mov [edi],dx
mov eax,[esp+8] ; return in eax pointer to dest string
mov byte ptr [edi+2],0
pop edi
ret
byte_1:
mov [edi],dx
mov eax,[esp+8] ; return in eax pointer to dest string
pop edi
ret
byte_0:
mov [edi],dl
mov eax,[esp+8] ; return in eax pointer to dest string
pop edi
ret
改成C++代码 大致是下面这样:
char* MyStrcpy(char* Dest ,const char* Source)
{
char* tmpDest = Dest;
const char* tmpSource = Source;
int iTmp;
while( int(tmpSource) & 0x3 )
{
*tmpDest++ = *tmpSource++;
if( *Source == 0 )
{
return Dest;
}
}
while( true )
{
iTmp = *(int*)tmpSource;
if( ((iTmp+0x7efefeff) ^ (~iTmp)) & 0x81010100 )
{
if( (iTmp & 0x000000FF) == 0 )
{
*tmpDest = *tmpSource;
}
else if( (iTmp & 0x0000FF00) == 0 )
{
*(short*)tmpDest = *(short*)tmpSource;
}
else if( (iTmp & 0x00FF0000) == 0 )
{
*(short*)tmpDest = *(short*)tmpSource;
tmpDest += 2;
*tmpDest = 0; // tmpSource += 2; *tmpDest = *tmpSource;
}
else if( (iTmp & 0xFF000000) == 0 )
{
*(int*)tmpDest = *(int*)tmpSource;
}
// break;
return Dest;
}
else
{
*(int*)tmpDest = iTmp;
tmpSource += 4;
tmpDest += 4;
}
}
return Dest;
}
简单strcpy代码是这样:
char* MyStrcpy2(char* Dest ,const char* Source)
{
char* tmpDest = Dest;
while( *Dest++ = *Source++ );
return tmpDest;
}
总的来说,系统里带的strcpy代码是根据32位系统的特点,把一个字节一个字节的复制,变成以四个字节(32Bit)为单位的复制,这样可以减少指令的执行次数.
代码里对字符串结束的判断十分高明也是值得学习的地方,判断原理我也说不太明白(要是让我解释,可能还要研究很久)还是你自己研究吧.
上面的二个函数我是用 VC2005 , Windows XP(32位) 测试的.