strcpy的工作方式

strcpy函数的工作方式?
2025-05-19 22:33:56
推荐回答(1个)
回答1:

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位) 测试的.