Wojciech Gac
Wojciech Gac

Reputation: 1576

String length counter in NASM

everyone. I wrote a program in NASM calculating length of a string supplied as a variable:

section .data
    ; str1 db '12345678901'
    str1 db '123456789012'

section .text
    global _start

_start:
    mov eax, str1
    mov ecx, -1

.loop:
    inc ecx
    cmp byte [eax + ecx], 0
    jne .loop

.done:
    mov eax, 1
    mov ebx, ecx
    int 80h

When I run the program with the first string (commented in this listing) it returns the correct value 11. With the second string it's 13 - 1 more than it should be. I have no idea why it is so. It's assembled on a 64-bit machine. I tried inspecting it with GDB, but I don't see the point...

Upvotes: 1

Views: 4462

Answers (3)

Antonin GAVREL
Antonin GAVREL

Reputation: 11259

Instead of sub and neg you may use mov -1 in ecx: and then not

xor al, al      ; the byte that the scan will compare to is zero

mov ecx, -1     ; underfow will set the maximum number of bytes

cld             ; CLD (STD) clears (sets) the Direction flag, data goes onwards (backwards).
repne scasb     ; while [rdi] != al, keep scanning
; The REPNZ prefix (which is more readable in the REPNE form) repeats the scas as long as the comparison is false (REPeat while Not Equal) and ECX > 0. It also decrements ECX automatically in every iteration. ECX has been initialized to the longest possible string so that it doesn't terminate the loop early.

not ecx         ; Since ECX counts down from 0xffffffff (also known as -1), the resulting length will be -1-ECX
sub ecx, 1      ; len--

mov eax, ecx    ; ret = len

ret

Upvotes: 1

user2513931
user2513931

Reputation:

The fastest way to calculate a string's length is to use the scasb instruction:

xor   rax,rax      ;so all of ax is 0 for return value
mov   ecx,0x03fff  ;limit scan length
cld
repne scasb
sub   ecx,0x03fff  ;sub by the scan length
neg   ecx
dec   ecx          ;minus one for rep going too far by one
mov   eax,ecx      ;C functions return in ax register

The 0x3fff is my limiting value so that the scasb doesn't go too far in case of a string that's not 0 terminated. You can set it to any value you like, in fact many libraries use ecx at its max of 0xffffffff. But you must always be sure the strings you give it are 0 terminated! If not, it will return the limit value as the string's length (if it doesn't fault first).

Upvotes: 1

Michael
Michael

Reputation: 58507

str1 db '123456789012'
....    
cmp byte [eax + ecx], 0

Your string has no NUL terminator. Change it to str1 db '123456789012',0.

Upvotes: 4

Related Questions