Search code examples
assemblyx86masmmasm32irvine32

How to remove characters counting from the end of a string?


I have to remove a certain number of characters(let's say 3) from the end of a string. For this particular string it works when I find 'Z', and then make it point to W by sub edi, 3, and then storing the rest of the string with 0's.

INCLUDE Irvine32.inc

.data
source BYTE "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0

.code
main PROC

mov edi, OFFSET source
mov al, 'Z'                  ; search for Z
mov ecx, LENGTHOF source
cld
repne scasb       ; repeat while not equal
sub edi, 3         ; now points to W

mov al, 0         
rep stosb        ; stores all characters after W with 0.

mov edx, OFFSET source
call WriteString
call CrlF

exit
main ENDP
end main

However, I want to make this code work with different null terminated strings. For that purpose I tried finding 0(the end of the string), as my code shows below. But it doesn't work, It just outputs the whole string.

What should I do to ensure that the code still works even if the string is changed without having to change the search for the end of the string every time?

INCLUDE Irvine32.inc

.data
source BYTE "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0

.code
main PROC

mov edi, OFFSET source
mov al, '0'                  ; search for end of string
mov ecx, LENGTHOF source
cld
repne scasb       ; repeat while not equal
sub edi, 3         ; now points to W ??

mov al, 0         
rep stosb        ; stores all characters after W with 0.

mov edx, OFFSET source
call WriteString
call CrlF

exit
main ENDP
end main

Solution

  • The error is that you don't reset ECX with any value.

    You set ECX to the length of the data, in this case 27. Then you find Z, which is the 26th value, so in the end ECX will have value 1 and your rep stosb will write one 0 in the string. Then you print it and that first nul will stop printing.

    In the second one you're looking for 0 which is the last byte. Exiting the repne scasb ECX is zero, so rep stosb doesn't write anything.

    To fix this you can use

    mov edi, OFFSET source
    mov al, 0                  ; search for end of string
    mov ecx, LENGTHOF source
    cld
    repne scasb       ; repeat while not equal
    sub edi, 3         ; now points to W ??
    
    mov byte ptr [edi], 0     ; store a single nul since that's enough
    

    Do note that in the first one "stores all characters after W with 0" is not true. You would have to do ADD ECX, 3 after SUB EDI, 3 to do that.

    Do also note that '0' is the character 0, not the value 0.