assemblyx86-16string-comparisonosdev16-bit

Assembly 16bit real mode - CMPS return always 0


I want to make a small operating system in 16 bit assembly. In this code I'm creating a sort of 'terminal' where I take the user input and if the input is shutdown then start the function to shut everything down otherwise nothing happens and the loop resumes (for now, later I'll create other functions so if the command is not 'shutdown' then other checks will start to see if it's another command)

the code:

bits 16


section .kernel
global _start_kernel

_start_kernel:
    mov ax, 0x3
    int 10h

    commandLoop:
        mov si, user
        call print

        mov di, input_string
        call input

        mov si, input_string
        call print

        ifCommandShutdown:
            cld
            mov si, C_shutdown
            mov di, input_string
            mov cx, CL_shutdown
            cmpsb
            jz thenCommandShutdown

        elseCommandShutdown:
            call newLine
            jmp commandLoop

        thenCommandShutdown:
            call shutdown

    exit:
        cli
        hlt

%include "lib/console.asm"
%include "lib/system.asm"

user: db "user >> ", 0
input_string:

;- Commands Variables ------------------------------+
;                                                   |
C_shutdown:  db "shutdown", 0 ;                     |
C_reboot:    db "reboot"  , 0 ;                     |
;                                                   |
CL_shutdown: db $ - C_shutdown ;                    |
CL_reboot:   db $ - C_reboot   ;                    |
;                                                   |
;---------------------------------------------------+

times 512-($-$$) db 0

console.asm:

print:
    mov ah, 0x0e
    characterLoop:
        lodsb
        or al, al
        jz break
        int 10h

    jmp characterLoop

    break:
        ret

input:
    mov ah, 0x0
    int 16h

    ifKeyIsEnter:
        cmp al, 0x0D
        jz enterIsPressed
    elseEnterKey:
        stosb
        mov ah, 0x0e
        int 10h
    jmp input

    enterIsPressed:
        mov al, 0x0
        stosb
        call newLine
        ret

newLine:
    mov ah, 0x0e
    mov al, 13
    int 10h

    mov al, 10
    int 10h

    ret

system.asm:

shutdown:
    mov ax, 0x1000
    mov ax, ss
    mov sp, 0xf000
    mov ax, 0x5307
    mov bx, 0x0001
    mov cx, 0x0003
    int 0x15

There isn't errors when I compile but in qemu it always shutdown


Solution

  • cmps returns always 0

    Seeing how you laid out memory (forgetting to allocate room for the input):

    input_string:
    C_shutdown:  db "shutdown", 0
    

    the input just overwrites the very text that you will be comparing to. Obviously the one-character compare cmpsb then will always find a match.

    Since it is the full word 'shutdown' that you want to verify and seeing your code:

    cld
    mov si, C_shutdown
    mov di, input_string
    mov cx, CL_shutdown
    cmpsb
    

    where you try to setup a count in CX, you should prepend the repe (RepeatWhileEqual) prefix to the cmpsb instruction.
    Currently loading the count is wrong in that you load it with the address of the byte-sized variable CL_shutdown, where you need the actual contents of that variable. But it would be better to define these lengths as equates:

    user:         db    "user >> ", 0
    input_string: times 20 db 0
    C_shutdown:   db    "shutdown", 0
    CL_shutdown:  equ   $ - C_shutdown
    C_reboot:     db    "reboot"  , 0
    CL_reboot:    equ   $ - C_reboot
    

    The code to compare then becomes (assuming DS and ES have been setup correctly and equal to each other):

    cld
    mov  si, C_shutdown     ; DS:SI
    mov  di, input_string   ; ES:DI
    mov  cx, CL_shutdown
    repe cmpsb
    jz   thenCommandShutdown
    

    shutdown:
      mov ax, 0x1000
      mov ax, ss
      mov sp, 0xf000
    

    An additional error is in shutdown. The mov ax, 0x1000 mov ax, ss instructions make no sense (loading AX twice). This should read:

    mov  ax, 0x1000
    mov  ss, ax
    mov  sp, 0xF000