我正在尝试创建一个操作系统,我不了解所有的汇编语言,我主要是在学习中。这是问题所在,我构建了一个简单的函数来比较两个字符串(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
答案 0 :(得分:2)
我的操作系统是16位的,但是当我尝试在我的比较函数中使用16位的寄存器时,它告诉我给了它一个无效的有效地址。
16位寻址模式只能使用[bx|bp + si|di + constant]
或其子集。如果您不能像普通人一样,仅在si
和di
这样的addr模式下在[si]
和[di]
中传递指针,则使用32位寻址模式是一种有效的解决方法。
但仅当您将16位地址零扩展到完整的32位寄存器中时,否则高垃圾会导致违反段限制。在实模式下,段隐式具有64k的限制;偏移> 65535将会出错。
您可能实际上并没有使VirtualBox本身崩溃,但是您可能由于三重故障或某些原因而使虚拟客户机崩溃了。
mov eax, msg_welcome
确实使用零扩展地址写入完整寄存器,与mov si, msg_welcome
您的循环将始终在第一次迭代后退出,因为inc ecx
/ je .zero_test
会失败。 INC清除ZF,因为将ECX从0递增到1会使ECX!= 0。
如果您想让inc
读取cmp
设置的标志,大概应该在je
/ je
之前cmp
。
我不确定您的代码实际在哪里出错。使用调试器进行查找,例如通过在BOCHS而不是VirtualBox中运行它。 BOCHS具有内置的调试器,该调试器可以理解分段,这不同于将GDB作为GDB远程程序附加到qemu或virtualbox。
您的循环效率很低,顺便说一句。您可以使用cmp dl, [di]
之类的东西,然后在底部放置一个jne
。如果您使用cmp / jcc退出循环,则可以在底部将test dl,dl
/ jnz
作为循环分支。
永远不要在jcc
上写jmp
,而要写一个遇到相反情况的JCC。在这里,您可以使用RET而不是jmp .done
。 (一个例外是,如果您必须跳得比-128 .. + 127字节还要远,并且您要针对的是不支持JCC rel16,而仅支持短JCC rel8的古老CPU。)
在AMD CPU(无部分寄存器重命名)上,mov dh, [mem]
对mov dl, [mem]
的依赖是错误的,因此在cmp
运行之前,合并负载值会有额外的延迟。这是使用cmp-with-mem而不是2个负载的另一个原因。