section .data
format db '%d', 0x0a, 0
section .text
global ft_strlen
ft_strlen:
push ebp
mov ebp, esp
mov ecx, [ebp + 8]
mov eax, 0
loop:
mov cl, [ecx + eax]
inc eax
cmp cl, 0
jne loop
mov esp, ebp
pop ebp
ret
When I use the CL register the program works properly but when I use AL it gives me an infinite loop. And when I use BL it gives me a SEGV.
Actually it's so weird because three of them are 8-bit registers.
When I use
cl
register the program works properly but when I useal
it gives me an infinite loop
Both options are equally wrong but the effect they have is mostly coincidential!
In mov cl, [ecx + eax]
, ECX is the base address of the string and EAX is the offset into the string. You should not be loading the byte from the string into CL since CL is the lowest 8 bits of the larger ECX register, and similarly you should not be loading the byte into AL since AL is the lowest 8 bits of the larger EAX register.
and when I use
bl
it gives me a SEGV.
Using BL only becomes an option, once you preserve its pre-existing value (on the stack). That's because EBX is "call-preserved" in the standard calling conventions. Compiler-generated code calling your function will assume EBX still has the same value after their call
. Your options are to save/restore EBX somewhere, or not modify it or any parts of it.
If you use a debugger to see where the segfault happens, for this case you should see it happening somewhere after your function returns. This is typically a sign you've violated the calling convention somehow, stepping on your caller's toes. The other two bugs, AL or CL, are likely producing crashes in your own function where you can see the bad address.
actually it's so weird because three of them are 8bit registers.
The x86 architecture has no separate 8-bit registers. What we perceive as 8-bit registers is always part of a larger register. See How do AX, AH, AL map onto EAX? for the details, which apply equally to AL, BL, CL, and DL.
ft_strlen:
mov ecx, [esp+4] ; Base
xor eax, eax ; Offset
.loop:
movzx edx, byte [ecx + eax]
inc eax
test dl, dl
jnz .loop
dec eax ; Don't include zero-terminator
ret
Your code was including the zero-terminator in the returned count. Usually we don't do that.
If you want to know how much space to allocate for a copy, that would save you the trouble of adding 1
to the return value. But give the function a different name to avoid confusion with the C standard library strlen
function which doesn't include the terminator. And be sure to document in comments any ways your function is different from standard functions that do similar things, when you're doing it intentionally. If this was unintentional, just change the code to make it an implementation of C's strlen
.