Search code examples
assemblyx86operating-systemvirtualboxosdev

OS Halting on Compare Strings


I'm attempting to create an Operating System, I don't know every in and out of assembly language, I am mainly learning as I go. Here is the problem, I built a simple function to compare two strings (eax and ebx) the problem is that when I run the code to do this my system doesn't execute anything after the call... What did I do wrong?

compare:
    xor ecx, ecx
    .by_char:
        mov dh, [eax+ecx]
        mov dl, [ebx+ecx]
        cmp dh, dl
        inc ecx
        je .zero_test
        stc
        jmp .done
    .zero_test:
        cmp dh, 0
        je .done
        jmp .by_char
    .done:
        ret

For reference here is the code I am calling this function from:

start:
    mov esp, stack
    mov si, msg_welcome
    call print

    mov eax, msg_welcome
    mov ebx, msg_diskerr
    call compare

    jc j_aa
    jmp j_bb 

    j_aa:
        mov si, msg_strnequ
        jmp part_b

    j_bb:
        mov si, msg_strrequ

    part_b:
        call print

        mov eax, msg_booting
        mov ebx, msg_booting
        call compare

        jc j_cc
        jmp j_dd

        j_cc:
            mov si, msg_strnequ
            jmp part_c

        j_dd:
            mov si, msg_strrequ

    part_c:
        call print
        jmp halt

halt:
    hlt
    jmp halt

Here is where I am defining my variables:

bss:
    msg_welcome: db "Welcome To Hypr Byte!", 10, 13, 10, 13, 0
    msg_nokernl: db "FATAL: Missing or Corrupted Kernel. System Halted...", 10, 13, 10, 13, 0
    msg_diskerr db "FATAL: An error occured while attempting to read the disk. Please go to https://www.instinct-loop.xyz/hypr/help to recieve support...", 0
    msg_bterror db "Uh oh! An error occured while attempting to boot. Please go to https://www.instinct-loop.xyz/hypr/help to recieve support...", 0
    msg_booting db "Attempting to load the kernel...", 10, 13, 10, 13, 0
    msg_kreturn db "Oops! The kernel ran into a fatal error... System Halted!", 0

    msg_strnequ db "Strings are Not Equal!", 10, 13, 0
    msg_strrequ db "Strings are Equal!", 10, 13, 0

Solution

  • my OS is 16 bit, but when I try to use 16 bit registers in my compare function it tells me that I am giving it an invalid effective address.

    16-bit addressing modes can only use [bx|bp + si|di + constant] or a subset of that. Using 32-bit addressing modes is a valid workaround if you can't just pass pointers in si and di for addr modes like [si] and [di] like a normal person.

    But only if you zero-extend the 16-bit addresses into the full 32-bit register, otherwise high garbage can lead to a segment limit violation. In real mode, segments implicitly have a 64k limit; offset > 65535 will fault.

    You're probably not actually crashing VirtualBox itself, but you could be crashing the virtual guest machine with a triple fault or something.

    mov eax, msg_welcome does write the full register with the zero-extended address, unlike mov si, msg_welcome


    Your loop will always exit after the first iteration, because inc ecx / je .zero_test falls through. INC clears ZF because incrementing ECX from 0 to 1 leaves ECX != 0.

    Presumably you should inc before cmp/je if you want je to read flags set by cmp.

    I'm not sure where your code would actually fault. Use a debugger to find out, e.g. by running it inside BOCHS instead of VirtualBox. BOCHS has a debugger built-in which understands segmentation, unlike attaching GDB to qemu or virtualbox as a GDB-remote.


    Your loop is pretty inefficient, BTW. You can use cmp dl, [di] or something and put a jne at the bottom. If you break out of the loop with a cmp/jcc, you can put a test dl,dl/jnz as the loop branch at the bottom.

    You should never write a jcc over a jmp, just write a JCC with the opposite condition that falls through. And here you can fall through to a RET instead of a jmp .done. (The one exception is if you have to jump farther than -128..+127 bytes, and you're targeting an ancient CPU that doesn't support JCC rel16, only short JCC rel8.)

    On an AMD CPU (no partial-register renaming), mov dh, [mem] has a false dependency on mov dl, [mem], so there's extra latency for merging the load values before your cmp can run. That's another reason for using a cmp-with-mem instead of 2 loads.