【问题标题】:OS Halting on Compare Strings操作系统在比较字符串时停止
【发布时间】:2019-07-11 10:56:47
【问题描述】:

我正在尝试创建一个操作系统,我不了解汇编语言的所有内容,我主要是边走边学。这就是问题所在,我构建了一个简单的函数来比较两个字符串(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

【问题讨论】:

  • 您的操作系统是 16 位还是 32 位? - 因为这个mov si, msg_welcome 加载一个16 位指针,而这个mov eax, msg_welcome 加载一个32 位指针。
  • @500-InternalServerError 我相信您可能会遇到问题,我的操作系统是 16 位的,但是当我尝试在比较函数中使用 16 位寄存器时,它告诉我我给它一个无效的有效地址。
  • inc ecx 之后执行je .zero_test 不是一个好主意,因为它会修改标志。你正在用它测试ecx==0。不应该直接导致你的问题。 PS:在尝试编写操作系统之前学习使用调试器。
  • @Jester 感谢您的提示和信息,将考虑获取调试器并移动了增量语句,但是当我运行操作系统时,它崩溃了 VirtualBox。
  • @Jester 当我说它使虚拟盒崩溃时,我的意思是虚拟盒提醒我它在模拟系统时遇到错误并不得不退出。

标签: assembly x86 operating-system virtualbox osdev


【解决方案1】:

我的操作系统是 16 位的,但是当我尝试在比较函数中使用 16 位寄存器时,它告诉我我给它一个无效的有效地址。

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

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

您可能实际上并没有使 VirtualBox 本身崩溃,但您可能会因为三重故障或其他原因导致虚拟客户机崩溃。

mov eax, msg_welcome 确实使用零扩展地址写入完整的寄存器,这与mov si, msg_welcome 不同


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

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

我不确定您的代码实际上会在哪里出错。使用调试器找出,例如通过在 BOCHS 而不是 VirtualBox 中运行它。 BOCHS 内置了一个可以理解分段的调试器,这与将 GDB 附加到 qemu 或 virtualbox 作为 GDB-remote 不同。


顺便说一句,您的循环效率很低。您可以使用cmp dl, [di] 或其他东西,并在底部放置jne。如果您使用 cmp/jcc 跳出循环,则可以将 test dl,dl/jnz 作为循环分支放在底部。

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

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

【讨论】:

  • 我根据您和其他人告诉我的情况得出了这个结论,谢谢!
  • 循环应该立即退出,因为je 不会跳转,然后代码就会执行stc; jmp .done; ret
  • @Jester:哦,对了,那么 IDK 发生了什么。我只在 JMP (/facepalm) 上查看了 JCC,并且对解开那些废话不感兴趣。我在想 JMP 回到了内部循环的顶部。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-11
  • 1970-01-01
  • 2013-03-24
  • 1970-01-01
  • 2016-10-11
  • 2020-11-09
相关资源
最近更新 更多