; C string.h implementations global memcmp global memcpy global memset global strcmp global stpcpy global strcpy global strlen global strncpy ; return eax(, edx) parameters stack scratch eax ecx edx preserved ebx esi edi ebp esp ; int memcmp(const void s1[], const void s2[], size_t n); memcmp: mov ecx, [esp+12] jecxz .z ; return 0 if n is 0 push esi push edi mov esi, [esp+12] mov edi, [esp+16] mov edx, ecx shr ecx, 2 jz .ld repe cmpsd ; find non-matching dwords jne .f2 .ld: and edx, 3 jz .sz ; none left, so all matched mov al, byte [esi+0] sub al, byte [edi+0] jnz .f dec edx jz .sz mov al, byte [esi+1] sub al, byte [edi+1] jnz .f dec edx jz .sz mov al, byte [esi+2] sub al, byte [edi+2] jmp .f ; last byte .sz: ; no non-matching bytes pop edi pop esi .z: xor eax, eax ret .f: ; diff in al movsx eax, al pop edi pop esi ret .f2: ; found non-matching dword at ESI-4 <-> EDI-4 mov eax, [esi-4] mov ecx, [edi-4] sub al, cl jnz .d shr eax, 8 ; ESI-3 shr ecx, 8 sub al, cl jnz .d shr eax, 8 ; ESI-2 shr ecx, 8 sub al, cl jnz .d shr eax, 8 ; ESI-1 shr ecx, 8 sub al, cl .d: movsx eax, al pop edi pop esi ret ; void *memcpy(void dest[], const void src[], size_t n); memcpy: mov ecx, [esp+12] jecxz .none push esi push edi mov edi, [esp+12] mov esi, [esp+16] mov edx, ecx shr ecx, 2 jz .dword_done rep movsd .dword_done: test edx, 2 jz .word_done movsw .word_done: test edx, 1 jz .done movsb .done: pop edi pop esi .none: mov eax, [esp+4] ret ; void *memset(void s[], int c, size_t n); memset: mov ecx, [esp+12] jecxz .none push edi mov edi, [esp+8] mov eax, [esp+12] mov ah, al mov edx, eax shl eax, 16 mov ax, dx mov edx, ecx shr ecx, 2 jz .dword_done rep stosd .dword_done: test edx, 2 jz .word_done stosw .word_done: test edx, 1 jz .done stosb .done: pop edi .none: mov eax, [esp+4] ret ; int strcmp(const char *s1, const char *s2); strcmp: push esi push edi mov esi, [esp+12] mov edi, [esp+16] xor ecx, ecx jmp .l_inner .l: inc ecx .l_inner: xor eax, eax or al, [esi+ecx] jz .s1_end or ah, [edi+ecx] jz .s2_end sub al, ah jz .l ; equal .done: movsx eax, al pop edi pop esi ret .s1_end: mov ah, [edi+ecx] .s2_end: sub al, ah jmp .done ; char *stpcpy(char *restrict dst, const char *restrict src); stpcpy: push esi push edi mov edi, [esp+12] mov esi, [esp+16] xor ecx, ecx .l: xor eax, eax or al, [esi+ecx] mov [edi+ecx], al jz .done inc ecx jmp .l .done: lea eax, [edi+ecx] pop edi pop esi ret ; char *strcpy(char *restrict dst, const char *restrict src); strcpy: push esi push edi mov edi, [esp+12] mov esi, [esp+16] xor ecx, ecx .l: xor eax, eax or al, [esi+ecx] mov [edi+ecx], al jz .done inc ecx jmp .l .done: mov eax, [esp+12] pop edi pop esi ret ; size_t strlen(const char *s); strlen: push edi mov edi, [esp+8] xor eax, eax mov ecx, -1 repne scasb ; find AL in EDI not ecx lea eax, [ecx-1] pop edi ret ; char *strncpy(char dst[restrict .dsize], const char *restrict src, size_t dsize); strncpy: push esi push edi mov edi, [esp+12] mov esi, [esp+16] mov ecx, [esp+20] jecxz .done .l: xor eax, eax or al, [esi] jz .src_empty stosb inc esi loop .l jmp .done .src_empty: rep stosb .done: mov eax, [esp+12] pop edi pop esi ret