OS 停止比较字符串
OS Halting on Compare Strings
我正在尝试创建一个操作系统,我不知道汇编语言的每一个细节,我主要是边学边做。这是问题所在,我构建了一个简单的函数来比较两个字符串(eax
和 ebx
),问题是当我 运行 执行此操作的代码时,我的系统不执行任何操作通话后...我做错了什么?
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]
或其子集。如果您不能像普通人一样在 si
和 di
中为地址模式(如 [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 个负载的另一个原因。
我正在尝试创建一个操作系统,我不知道汇编语言的每一个细节,我主要是边学边做。这是问题所在,我构建了一个简单的函数来比较两个字符串(eax
和 ebx
),问题是当我 运行 执行此操作的代码时,我的系统不执行任何操作通话后...我做错了什么?
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]
或其子集。如果您不能像普通人一样在 si
和 di
中为地址模式(如 [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 个负载的另一个原因。