16 位汇编中的几个字符串出现意外行为

问题描述 投票:0回答:1

我正在尝试使用 NASM 和 QEMU 在 16 位汇编中创建一个简单的命令行。到目前为止,一切正常,直到我再添加一根字符串。

当我添加另一个字符串时,程序不会显示应有的所有内容。

当我添加最后一个

msgHelpEcho
字符串时,它会显示提示而不是像这样的
">"
" >"
,或者当我输入 help 时,它会正确显示前几个命令,但最后一个命令总是被切成两半或丢失,或转入空白处“ ”。

过去几天我一直在寻找原因,发现将字符串的声明移动到代码中的另一行会更改输出,但它仍然不正确。 提前致谢!这是代码:

org 0x8000 ; the program starts from 8000
bits 16 ; the program is 16-bit

; si - for read and write strings
; di - for comparing commands

section .text

global _start

_start:
    call cls ; clear screen

; this is the start of the kernel
mov si, titleString ; print the title string
call printStr

mov si, newLine
call printStr

main:
    mov si, prompt ; this is the char befor the UI
    call printStr

    ; here the kernel asks for user input
    mov di, readBuffer
    call getInput

    ; here we split the input in to caommand and arguments
    mov si, readBuffer
    call splitCommand

    ; here are the commands
    mov si, readBuffer
    cmp byte [si], 0 ; to see if there is a blank line
    je main

    mov si, command
    mov di, cmdclear
    call cmpUI
    jc cls

    mov si, command ; this is the help command
    mov di, cmdHelp
    call cmpUI
    jc .help

    mov si, command ; this is for the echo command
    mov di, cmdEcho
    call cmpUI
    jc .echo

    mov si, command ; this is for the shutdown command
    mov di, cmdShutdown
    call cmpUI
    jc .shutdown

    mov si, badCmd ; if all command aren't triggered then print no such command
    call printStr
    jmp main

    .shutdown:
        ; turn off the system
        mov ax, 0x5307
        mov bx, 0x0001
        int 0x15
        jmp .shutdown

    .help:
        mov si, msgHelp ; help text
        call printStr

        ;mov si, msgHelpHelp ; -help
        ;call printStr

        ;mov si, msgHelpExit ; -shutdown
        ;call printStr

        ;mov si, msgHelpClear ; -clear
        ;call printStr

        jmp main

    .echo:
        mov si, arguments
        call printStr

        mov si, newLine
        call printStr

        jmp main

    jmp main ; infinite loop

printStr:
    mov ah, 0x0e ; Move 0x0e in ah to use interupts
    mov al, [si] ; Move the first char of the string in al
    psloop:
        int 0x10 ; 0x10 is interrupt for print
        inc si ; incrementing the si stack index
        mov al, [si] ; moving the new char from the string in the si stack to al
        cmp al, 0 ; comparing al to 0
        jne psloop ; is al is not 0 loop back
        ret
    ret

getInput:
    xor cl, cl

    .loop:
        mov ah, 0x00 ; this is for the interrupt
        int 0x16 ; this interrupt is for reading the next char

        cmp al, 0x08 ; if backspace is pressed
        je .backspace

        cmp al, 0x0d ; if enter is pressed
        je .done

        cmp cl, 0x3f ; if 63 chars are entered
        je .loop

        mov ah, 0x0e ; when something is entered print it
        int 0x10

        stosb ; put the char in the buffer
        inc cl
        jmp .loop

    .backspace:
        cmp cl, 0 ; if it is the beginning of the string
        je .loop

        dec di
        mov byte [di], 0 ; delete the char
        dec cl ; decrement counter as well

        mov ah, 0x0e
        mov al, 0x08
        int 0x10 ; backspace on the screen

        mov al, ' '
        int 0x10 ; blank char out

        mov al, 0x08
        int 0x10 ; backspace again

        jmp .loop

    .done:
        mov al, 0 ; null the terminal
        stosb

        mov ah, 0x0e
        mov al, 0x0d
        int 0x10
        mov al, 0x0a
        int 0x10 ; new line

        ret

cls:
    pusha ; push the stack
    mov al, 0x03 ; this is for the interrupt
    mov ah, 0x00 ; this is also for the interrupt
    int 0x10 ; this interrupt clears all the junk the BIOS prints
    popa ; pop the stack
    ret

cmpUI:
    .loop:
        mov al, [si] ; grab a byte from si
        mov bl, [di] ; grab a byte from di
        cmp al, bl
        jne .notequal

        cmp al, 0 ; are both bytes null
        je .done

        inc di
        inc si
        jmp .loop

    .notequal:
        clc ; not equal, clear the carry flag
        ret

    .done:
        stc ; equal, set the carry flag
        ret

splitCommand:
    mov cx, 0
    mov di, command

    .find_space:
        lodsb ; take a byte from si and put it in al
        cmp al, ' '
        je .found_space
        stosb ; take a byte from al and put it in di
        inc cx
        test al, al
        jnz .find_space
        jmp .done

    .found_space:
        mov di, arguments

    .copy_arguments:
        lodsb
        stosb
        test al, al
        jnz .copy_arguments

    .done:
        ret

section .data

; commands
cmdHelp db 'help', 0 ; this is for the help command
cmdShutdown db 'shutdown', 0 ; this is for shutting down the computer
cmdEcho db 'echo', 0 ; this is for the echo command
cmdclear db 'clear', 0 ; clear the screen

readBuffer times 64 db 0 ; the buffer for the read UI
prompt db '>', 0 ; this is the char before the read UI
titleString db 'Command line', 13, 10, 0 ; this is the string

; help texts
msgHelp db 'The available commands are:', 13, 10, 0 ; this is the message from the help command
msgHelpHelp db '-help     - displays all the commands', 13, 10, 0
msgHelpExit db '-shutdown - shuts down the computer', 13, 10, 0
msgHelpClear db '-clear    - clear the screen', 13, 10, 0
msgHelpEcho db '-echo     - echos the text after it', 13, 10, 0

newLine db ' ', 13, 10, 0 ; new line
badCmd db 'No such command.', 13, 10, 0 ; when there is no such command

section .bss

command resb 16 ; buffer to store command
arguments resb 64 ; buffer to store arguments

这是我使用的引导加载程序:

ORG 0x7C00
BITS 16

main:
    hlt

load_and_execute_kernel:
    mov ah, 0x02
    mov al, 1
    mov ch, 0
    mov dh, 0
    mov dl, 0x80
    mov bx, 0x8000
    mov cx, 0x0002
    int 0x13

    jmp 0x8000 ;jump to entry point of kernel...
    
times 510-($-$$) db 0
dw 0AA55h
assembly x86 nasm x86-16 qemu
1个回答
0
投票

更改引导加载程序以加载另一个扇区并且它可以工作!

ORG 0x7C00
BITS 16

main:
    hlt

load_and_execute_kernel:
    mov ah, 0x02
    mov al, 2
    mov ch, 0
    mov dh, 0
    mov dl, 0x80
    mov bx, 0x8000
    mov cx, 0x0002
    int 0x13

    jmp 0x8000 ;jump to entry point of kernel...
    
times 510-($-$$) db 0
dw 0AA55h
© www.soinside.com 2019 - 2024. All rights reserved.