Hello!
I've recently started learning assembly so I can begin writing full-fledged languages instead of wrappers. Today, while trying to learn the cmp function, and using je and jne, I've came upon a problem. I tried using cmp to compare two values, and then je and jne to jump to the two cases.

However , the only output it prints is "A is not equal to B", no matter what values I choose. Here is the code I wrote to so far :

section .data
    text1:  db 'A is equal to B',10
    text2:  db 'A is not equal to B',10
    text1s: equ $-text1
    text2s: equ $-text2
section .bss
    a:  resb 2
    as: equ $-a
    b:  resb 2
    bs: equ $-b
section .text
    global _start
    _start:
        mov eax,3
        mov ebx,1
        mov ecx,a
        mov edx,as
        int 80h

        mov eax,3
        mov ebx,1
        mov ecx,b
        mov edx,bs
        int 80h

        mov eax,[a]
        mov ebx,[b]
        cmp eax,ebx
        je truea
        jne falseb
    truea:
        mov eax,4
        mov ebx,1
        mov ecx,text1
        mov edx,text1s
        int 80h
        jmp endexit
    falseb:
        mov eax,4
        mov ebx,1
        mov ecx,text2
        mov edx,text2s
        int 80h
        jmp endexit
    endexit:
        mov eax,1
        mov ebx,1
        int 80h

As far as I can see, it just always goes to falseb. I'm using Linux, x86 version with nasm(using -f elf) and linking it with ld -s -o <name> <name.o>.

I'd really appreciate any post on what I've done wrong.

The problem isn't in the comparison, nor in the je or jne instructions; it is in the declarations for a and b. For each of those, you define them as a 2 reserved bytes; howvever, the mov eax, [a] instruction assumes that a is a doubleword (4 bytes), and as a result, it reads in the combined bytes of both a and b. The mov ebx, [b] is even worse, because once again, it expects a double word, and this time it loads b into the high word of ebx, and whatever garbage happens to be following b in the executable into the low word. You want to define both a and b as resd 1 instead.

Actually, there's still a serious problem with the program: while it will now seem to work, provided you use values no more than 3 digits long, it isn't actually doing what you think it is. The problem lies with how you are reading in the values, and what you are actually comparing. When you read in the value of a (for example), you are using the sys_read call (the system call where eax equals 3). This call reads in a string of a given size. Then, as the program is now, you are using that string value as the basis of a 32-bit comparison. This will seem fine if the value fits into 4 bytes (which means three digits and the hidden newline character), but it isn't really comparing the numeric values. It will, for example, read in and compare any set of three characters, whether they are digits or not.

To do what you want to do properly, you will want to read the string of digits into a buffer that is at least ten characters long (enough to hold a value of 2147483648, plus a newline), and then convert the value from a string of digits to an actual integer value. This isn't as very difficult thing to do, but there are no system calls for this purpose; you'll need to either use the C library function sscanf(), or else write your own conversion routine.

The problem isn't in the comparison, nor in the je or jne instructions; it is in the declarations for a and b. For each of those, you define them as a 2 reserved bytes; howvever, the mov eax, [a] instruction assumes that a is a doubleword (4 bytes), and as a result, it reads in the combined bytes of both a and b. The mov ebx, [b] is even worse, because once again, it expects a double word, and this time it loads b into the high word of ebx, and whatever garbage happens to be following b in the executable into the low word. You want to define both a and b as resd 1 instead.

Actually, there's still a serious problem with the program: while it will now seem to work, provided you use values no more than 3 digits long, it isn't actually doing what you think it is. The problem lies with how you are reading in the values, and what you are actually comparing. When you read in the value of a (for example), you are using the sys_read call (the system call where eax equals 3). This call reads in a string of a given size. Then, as the program is now, you are using that string value as the basis of a 32-bit comparison. This will seem fine if the value fits into 4 bytes (which means three digits and the hidden newline character), but it isn't really comparing the numeric values. It will, for example, read in and compare any set of three characters, whether they are digits or not.

To do what you want to do properly, you will want to read the string of digits into a buffer that is at least ten characters long (enough to hold a value of 2147483648, plus a newline), and then convert the value from a string of digits to an actual integer value. This isn't as very difficult thing to do, but there are no system calls for this purpose; you'll need to either use the C library function sscanf(), or else write your own conversion routine.

Thanks for helping, but after changing it into :

section .bss
    a:  resd 1
    as: equ $-a
    b:  resd 1
    bs: equ $-b

It still doesn't work. Regarding your second concern, I'm already well aware of this, but this was meant to be just a cmp test, not a comparison of numbers. Actually, I wanted to learn the cmp so I could do a loop, which would in turn enable me to read real numeric values, not only strings.

Could you provide further advice or clarification?

Sorry for double posting, but I can't edit my old one. I've got it all figured out by mixing some C with assembly, and compiling it with gcc.

Thanks for helping!

This article has been dead for over six months. Start a new discussion instead.