Search code examples
assemblyx86nasm

Assembly program to compare strings not giving correct output


I'm trying to write an assembly program that compares two strings and outputs whether they're equal or not, I've tried to do this by increasing the index register one by one and comparing the characters.

But there seems to be a mistake in my code since I was expecting the output Equal

But the actual output was:

Equal
NotEqual

Code:

%include "asm_io.inc"
segment .data
str1: db "ThisIsSomeString", 0
str2: db "ThisIsSomeString", 0
msg_eq: db "Equal", 10, 0
msg_neq: db "NotEqual", 10, 0

segment .text
        global  asm_main
asm_main:
    mov esi, str1
    mov edi, str2
    xor edx, edx              ; to clear edx for index addressing
loop:
    mov al, [esi + edx]
    mov bl, [edi + edx]
    inc edx
    cmp al, bl
    jne not_equal
    cmp al, 0                 ; check if we're at the end of string
        je equal
    jmp loop
not_equal:
    mov eax, 4                ; system call number (sys_write = 4)
    mov ebx, 1                ; stdout = 1
    mov ecx, msg_neq          ; message to print
    int 0x80                  ; issue a system call
    jmp exit
equal:
    mov eax, 4
    mov ebx, 1
    mov ecx, msg_eq
    int 0x80
    jmp exit
exit:
    mov eax, 1                ; system call number (sys_exit = 1)
    mov ebx, 0                ; exit code
    int 0x80

Solution

  • You are not providing a length to sys_write. It takes the number of bytes to write in edx. It does not care that the string you are attempting to print is a nul-terminated string. You can solve the problem by saving the length of the messages you wish to output, e.g.

    segment .data
    str1: db "ThisIsSomeString", 0
    str2: db "ThisIsSomeString", 0
    msg_eq: db "Equal", 10, 0
    len_eq   equ $ - msg_eq
    msg_neq: db "NotEqual", 10, 0
    len_neq  equ $ - msg_neq
    

    In nasm the $ is the present stack address immediately before the current statement. So simply using $ - string_before where you declare your strings, you are able to save the length for later use with sys_write, e.g.

    segment .data
    str1: db "ThisIsSomeString", 0
    str2: db "ThisIsSomeString", 0
    msg_eq: db "Equal", 10, 0
    len_eq   equ $ - msg_eq
    msg_neq: db "NotEqual", 10, 0
    len_neq  equ $ - msg_neq
    
    segment .text
            global  _start
    _start:
    
        mov esi, str1
        mov edi, str2
        xor edx, edx              ; to clear edx for index addressing
    loop:
        mov al, [esi + edx]
        mov bl, [edi + edx]
        inc edx
        cmp al, bl
        jne not_equal
        cmp al, 0                 ; check if we're at the end of string
            je equal
        jmp loop
    not_equal:
        mov eax, 4                ; system call number (sys_write = 4)
        mov ebx, 1                ; stdout = 1
        mov ecx, msg_neq          ; message to print
        mov edx, len_neq          ; length in edx
        int 0x80                  ; issue a system call
        jmp exit
    equal:
        mov eax, 4
        mov ebx, 1
        mov ecx, msg_eq
        mov edx, len_eq           ; length in edx
        int 0x80
        jmp exit
    exit:
        mov eax, 1                ; system call number (sys_exit = 1)
        mov ebx, 0                ; exit code
        int 0x80
    

    (note: your %include "asm_io.inc" statement is not needed)

    Also note, I have replaced your asm_main with _start to compile and run on my box, just change it back as needed.

    Example Output

    $ ./bin/strcmp32
    Equal