wcscpy in x86 Assembly

This procedure, wcscpy_asm, copies a wchar_t (16-bit) string from the source to the destination and returns the destination pointer.

TITLE 'extern "C" wchar_t *wcscpy_asm(wchar_t *destination, const wchar_t *source);'
.686

.model FLAT

PUBLIC  _wcscpy_asm

_SEG  SEGMENT
_wcscpy_asm PROC NEAR

	mov  edi, DWORD PTR [esp+8] ; source
	mov  ecx, 0FFFFFFFFh
	xor  eax, eax
	cld
	repne scasw
	xor  ecx, 0FFFFFFFFh

	mov  esi, DWORD PTR [esp+8] ; source
	mov  edi, DWORD PTR [esp+4] ; destination
	rep movsw

	mov  eax, DWORD PTR [esp+4] ; destination
	ret  0

_wcscpy_asm ENDP
_SEG  ENDS
END

This procedure, wcscpy2_asm, copies a wchar_t (16-bit) string from the source to the destination and returns a pointer to the end of the destination so that another string can be concatenated.

The default behavior of wcscpy is to return the destination buffer but as is obvious below, it is much more useful to return the end of the text in the destination.

TITLE 'extern "C" wchar_t *wcscpy2_asm(wchar_t *destination, const wchar_t *source);'
.686

.model FLAT

PUBLIC  _wcscpy2_asm

_SEG  SEGMENT
_wcscpy2_asm PROC NEAR

	mov  edi, DWORD PTR [esp+8] ; source
	mov  ecx, 0FFFFFFFFh
	xor  eax, eax
	cld
	repne scasw
	mov  eax, DWORD PTR [esp+4] ; destination
	xor  ecx, 0FFFFFFFFh
	shl  ecx, 1
	add  eax, ecx
	sub  eax, 2
	shr  ecx, 1

	mov  esi, DWORD PTR [esp+8] ; source
	mov  edi, DWORD PTR [esp+4] ; destination
	rep movsw

	ret  0

_wcscpy2_asm ENDP
_SEG  ENDS
END

This example C++ code uses this function.

#include <stdlib.h>

extern "C" wchar_t * wcscpy2_asm(wchar_t *destination, const wchar_t *source);

wchar_t str[100], *end;
int length;

end = wcscpy2_asm(str, L"How ");
end = wcscpy2_asm(end, L"now ");
end = wcscpy2_asm(end, L"brown ");
end = wcscpy2_asm(end, L"cow!");

length = end - str;

// or simply

length = wcscpy2_asm(wcscpy2_asm(wcscpy2_asm(wcscpy2_asm(str, L"How "), L"now "), L"brown "), L"cow!") - str;

// str == L"How now brown cow!"
// length == 18

Here is another implementation of the above version that returns the end of the text in the destination but without using the string primitive instructions. It might be faster.

TITLE 'extern "C" wchar_t *wcscpy2_alt_asm(wchar_t *destination, const wchar_t *source);'

.686

.model FLAT

PUBLIC	_wcscpy2_alt_asm

_WCSCPY2_ALT	SEGMENT
_wcscpy2_alt_asm PROC NEAR

	mov  edx, DWORD PTR [esp+8] ; source
	mov  cx, WORD PTR [edx]
	test cx, cx
	mov  eax, DWORD PTR [esp+4] ; destination
	je   SHORT label2
	
label1:

	mov  WORD PTR [eax], cx
	add  edx, 2
	xor  ecx, ecx
	mov  cx, WORD PTR [edx]
	add  eax, 2
	test cx, cx
	jne  SHORT label1
	
label2:

	mov  WORD PTR [eax], 0

	ret  0
	
_wcscpy2_alt_asm ENDP
_WCSCPY2_ALT	ENDS
END