; -*- asm -*-

; @@PLEAC@@_NAME
Nasm

; @@PLEAC@@_WEB
http://nasm.sourceforge.net/


; @@PLEAC@@_1.0
; strlen (C calling convention)
;   input:
;     s  : pointer to const ASCIIZ string (address at esp+4).
;   algo:
;     use formulae "(x-1) & ~x = 2^first_bit(x) - 1" found in glibc code
;     but used differently. 0xfefefeff allow decrementing all byte of
;     a dword, the first null byte disable carry so the string must be
;     checked in little endian only.
strlen:
        mov eax,[esp+4]         ; get s value
.align: cmp byte [eax],0        ; realign pointer on dword boundaries
        jz .end
        inc eax
        test al,3
        jnz .align
.loop:  mov edx,[eax]           ; test 4 bytes at one time
        lea ecx,[edx+0xfefefeff]
        not edx
        and edx,ecx
        add eax,byte 4
        test edx,0x80808080     ; if one of the byte is null
        jz .loop
.final: shr edx,8               ; check first lo byte
        inc eax
        jnc .final
        sub eax, byte 5         ; realign pointer to null char
.end:   sub eax,[esp+4]
        ret


; strcpy (C calling convention)
;   input:
;     dest : pointer to destination ASCIIZ string (address at esp+4).
;     src  : pointer to source ASCIIZ string (address at esp+8).
;   algo:
;     see strlen above for algorithm.
strcpy:
        mov ecx,[esp+8]                 ; get src
        mov edx,[esp+4]                 ; get dest
.align: mov al,[ecx]
        inc ecx
        mov [edx],al                    ; copy one byte to align source ptr
        inc edx
        test al,al
        jz .ret
        test cl,3
        jnz .align
        mov [esp+8],ebx                 ; ok save ebx as it may be used by gcc
        jmp short .start                ; start is inside the loop.
.loop:  mov [edx],ebx
        add edx,byte 4
.start: mov eax,[ecx]                   ; get dword and search for a null byte
        lea ebx,[eax+0xfefefeff]
        not eax
        and eax,ebx
        sub ebx,0xfefefeff              ; restore ebx to dword read
        add ecx,byte 4
        test eax,0x80808080             ; one of the byte is null?
        jz .loop
.final: mov [edx],bl                    ; search thorugh ebx itself
        ror ebx,8                       ; slow but compact
        inc edx
        test ebx,0xff000000
        jnz .final
        mov ebx,[esp+8]                 ; restore ebx value
.ret:   mov eax,[esp+4]                 ; strcpy should return dest
        ret