OS 停止比较字符串

OS Halting on Compare Strings

我正在尝试创建一个操作系统,我不知道汇编语言的每一个细节,我主要是边学边做。这是问题所在,我构建了一个简单的函数来比较两个字符串(eaxebx),问题是当我 运行 执行此操作的代码时,我的系统不执行任何操作通话后...我做错了什么?

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

此处供参考的是我调用此函数的代码:

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

这里是我定义变量的地方:

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

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 位寻址模式只能使用 [bx|bp + si|di + constant] 或其子集。如果您不能像普通人一样在 sidi 中为地址模式(如 [si][di] 传递指针,则使用 32 位寻址模式是一个有效的解决方法。

但前提是您 zero-extend 将 16 位地址放入完整的 32 位寄存器,否则高垃圾会导致违反段限制。在实模式下,段隐含有 64k 的限制; offset > 65535 会出错。

您可能实际上并没有使 VirtualBox 本身崩溃,但您可能会因三重故障或其他原因使虚拟来宾计算机崩溃。

mov si, msg_welcome

不同,

mov eax, msg_welcome 确实使用 zero-extended 地址写入完整寄存器


您的循环将始终在第一次迭代后退出,因为 inc ecx / je .zero_test 失败了。 INC 清除 ZF,因为将 ECX 从 0 递增到 1 会使 ECX != 0.

如果您希望 je 读取由 cmp 设置的标志,那么您应该在 cmp/je 之前 inc

我不确定您的代码实际上会在哪里出错。使用调试器找出,例如通过 运行 在 BOCHS 中而不是 VirtualBox 中使用它。 BOCHS 有一个调试器 built-in 可以理解分段,这与将 GDB 作为 GDB-remote.

附加到 qemu 或 virtualbox 不同

顺便说一句,你的循环效率很低。你可以使用 cmp dl, [di] 之类的东西,然后在底部放一个 jne。如果你用cmp/jcc跳出循环,你可以在底部放一个test dl,dl/jnz作为循环分支。

你永远不应该在 jmp 上写一个 jcc,只要写一个 JCC 与失败的相反条件。在这里你可以通过 RET 而不是 jmp .done。 (一个例外是,如果您必须跳转超过 -128..+127 字节,并且您的目标是不支持 JCC rel16 的古老 CPU,仅短 JCC rel8。)

在 AMD CPU 上(没有 partial-register 重命名),mov dh, [mem]mov dl, [mem] 有错误的依赖,所以在你之前合并加载值会有额外的延迟cmp可以运行。这是使用 cmp-with-mem 而不是 2 个负载的另一个原因。