3

I am having troubles with the CMP instruction when comparing single words (2 bytes).
The following is my main.asm:

[org 0x7c00]

mov bx, HELLO_MSG
call print_string

mov bx, GOODBYE_MSG
call print_string

jmp $

%include "print_string.asm"

; Data
HELLO_MSG:
    db 'Hello, World!', 0
GOODBYE_MSG:
    db 'Goodbye!', 0

This is the print_string.asm file:

print_string:
    pusha
    mov ah, 0x0e
    loop:
        call print_char
        cmp word [bx], 0
        jne loop
    popa
    ret

print_char:
    mov al, [bx]
    int 0x10
    add bx, 1
    ret

This code prints out the following:

Hello World! Goodbye!Goodbye!

I know that when I add

db 0

in between the HELLO_MSG and the GOODBYE_MSG, the code will work as intended. Can anyone explain why CMP will only work when there are 4 bytes of 0 between the strings?

If anyone is interested in looking at the compiled output, here it is:

bb  23  7c  e8  08  00  bb  31  7c  e8  02  00  eb  fe  60  b4
0e  e8  07  00  83  3f  00  75  f8  61  c3  8a  07  cd  10  83           
c3  01  c3  48  65  6c  6c  6f  2c  20  57  6f  72  6c  64  21
00  47  6f  6f  64  62  79  65  21  00  00  00  00  00  00  00           
00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
*           
00  00  00  00  00  00  00  00  00  00  00  00  00  00  55  aa

The 55 aa at the end is added by me because I am using this code as a boot loader.

Sep Roland
  • 33,889
  • 7
  • 43
  • 76
John Doe
  • 397
  • 3
  • 18
  • 6
    You are doing `cmp word [bx],0` which compares 2 bytes starting at the address `bx` . You probably want to be comparing a single byte. `cmp byte [bx],0` – Michael Petch Apr 27 '17 at 01:29
  • I also suggest you properly set up the segment registers and stack etc. I give some tips in this Stackoverflow answer that has [general bootloader tips](http://stackoverflow.com/a/32705076/3857942) – Michael Petch Apr 27 '17 at 01:31
  • 1
    You may also want to use a register other than _BX_ for `print_string`. [_Int 10/AH=0Eh_](http://www.ctyme.com/intr/rb-0106.htm) uses _BH_ as the page number to write to. You probably want to set that to 0. That means you should use a register other than _BX_ as the string pointer. Maybe _SI_ instead. – Michael Petch Apr 27 '17 at 01:35
  • Another useful tidbit is to use BOCHS to debug bootloaders. It understands real mode and real mode addressing and can be a valuable tool to debug bootloader code. – Michael Petch Apr 27 '17 at 01:45
  • @MichaelPetch I am using QEMU, which is similar to BOCHS – John Doe Apr 27 '17 at 01:48
  • 2
    QEMU doesn't do real mode debugging very well (it uses GDB which isn't designed for real mode in mind). BOCHS has an internal debugger that is well suited for debugging bootloaders. So yes they do the same thing, but one tool is vastly better off with a debugger that would help you find issues like the one in my first comment. – Michael Petch Apr 27 '17 at 01:52
  • @MichaelPetch Your first suggestion works. But why? If you look at the compiled output, the first 2 bytes at line 4 are 0, which should theoretically make CMP evaluate it to be equal to 0. – John Doe Apr 27 '17 at 01:57
  • 1
    Line 4 starts with `00 47 6f` Each one of those values (separated by a space) is a single byte, not 2 bytes. `00` is a single byte of 0, not two bytes of 0 – Michael Petch Apr 27 '17 at 01:59

1 Answers1

5

The reason the CMP instruction is not working for single word comparison is because a word must contain 2 bytes. Since the compiled output shows that there is only 1 byte between the two messages, you will need to change the size of the CMP instruction from word to byte:

cmp byte [bx], 0

I made the mistake of assuming that the compiled output format arranged the bytes by 2. However, with the help of the following comment by Michael Petch:

Line 4 starts with 00 47 6f Each one of those values (separated by a space) is a single byte, not 2 bytes. 00 is a single byte of 0, not two bytes of 0

I was able to realize my mistake.

John Doe
  • 397
  • 3
  • 18