c-OS开发,浮点除法问题导致NaN



如果我的问题没有以最好的方式格式化,我会提前道歉,我是这里提问的新手。

最近,我对学习操作系统开发很感兴趣,在C中遇到了一些关于浮点除法的奇怪问题。即使是像4.0f / 2.0f这样简单的东西也会给我一个NaN结果。我怀疑这可能与编译器有关,但我不知道如何验证,我非常感谢帮助解决这个问题,因为我已经做了几个小时了,在谷歌搜索方面几乎没有进展。项目的Github,如果你想构建它:https://github.com/AsherBearce/ToyOperatingSystem

我的项目的相关部分如下:

内核/kernelmain.c:/strong>

#include "screen.h"
void main(){   
enableCursor(1, 14);
clearScreen();
double a = 4.0f;
double b = 2.0f;
double c = a / b;
double ans = 2.0f;
//Division is the ONLY operation that isn't yielding the correct results, in fact c turns out to be NaN!
if (c == 2.0f){ 
char string[] = "Hardcoded values were correctn";
print(string);
}
char out[] = "End output";
print(out);
while (1){
}
}

引导/引导扇区.asm

org 0x7c00
bits 16
mov ax, HELLO_MSG ;Print a simple hello message :D
call _printString
xor ax, ax
;Here, we'll load the kernel into RAM
call LoadKernel
;Enter protected mode
call EnterProtMode
EnterProtMode:
cli ;Disable interrupts
lgdt [gdt_pointer] ;Load the GDT register with the start address of the GDT
mov eax, cr0
or al, 1 ;Set PE (protection enable) bit in CR0
mov cr0, eax
jmp 08h:Stage2 ;Jump to stage 2
LoadKernel:
mov bx, KERNEL_OFFSET ;Load the kernel offset into bx
mov dh, 16 ;Load 16 sectors 
mov dl, [BOOT_DRIVE] ;The disk to read from
call diskload ;Load the kernel
ret
bits 32
KERNEL_OFFSET equ 0x1000
BOOT_DRIVE: db 0
Stage2:
mov ax, DATA_SEG
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov ebp, 0x90000
mov esp, ebp
;Kernel entry here
jmp KERNEL_OFFSET ;Call the kernel finally
%include 'boot/printUtils.asm'
%include 'boot/gdt.asm'
%include 'boot/diskload.asm'
HELLO_MSG: db "Booted successfully, loading kernel.", 0
times 510 - ($ - $$) db 0
dw 0xaa55

生成文件

BOOTOUTPUT = boot.bin
OSOUTPUT = os.bin
SRCS = $(shell find . -name '*.c')
CINC = $(shell find . -name '*.h')
COBJS = $(patsubst %.c, %.o, $(SRCS))
OBJDIR = build
#Final step in the build process
$(OSOUTPUT): kernel.bin $(BOOTOUTPUT)
cat $(BOOTOUTPUT) kernel.bin > $(OSOUTPUT)
#Assemble the boot sector code
$(BOOTOUTPUT): boot/bootsector.asm
nasm -f bin boot/bootsector.asm -o $(BOOTOUTPUT)
#Compile all the kernel C files
%.o:%.c $(CINC)
gcc -m32 -ffreestanding -fno-pie -fno-stack-protector -nostdlib -c $< -o $@
#Assemble the IRQ code
irq.o: kernel/irq.asm
nasm kernel/irq.asm -f elf32 -o irq.o
#Assemble the kernel entry code
kernelEntry.o: boot/kernelEntry.asm
nasm boot/kernelEntry.asm -f elf32 -o kernelEntry.o
#Link all the .o files with the kernel entry
kernel.bin: kernelEntry.o irq.o $(COBJS)
ld -melf_i386 -o kernel.bin -Ttext 0x1000 $^ --oformat binary
run: 
qemu-system-x86_64 -fda $(OSOUTPUT)
clean:
rm -f *.bin *.o $(COBJS)

编辑:我决定包括kernelmain.c 的反汇编


kernelmain.o:     file format elf32-i386

Disassembly of section .text:
00000000 <main>:
0:   f3 0f 1e fb             endbr32 
4:   8d 4c 24 04             lea    0x4(%esp),%ecx
8:   83 e4 f0                and    $0xfffffff0,%esp
b:   ff 71 fc                pushl  -0x4(%ecx)
e:   55                      push   %ebp
f:   89 e5                   mov    %esp,%ebp
11:   51                      push   %ecx
12:   83 ec 54                sub    $0x54,%esp
15:   e8 fc ff ff ff          call   16 <main+0x16>
1a:   83 ec 08                sub    $0x8,%esp
1d:   6a 0e                   push   $0xe
1f:   6a 01                   push   $0x1
21:   e8 fc ff ff ff          call   22 <main+0x22>
26:   83 c4 10                add    $0x10,%esp
29:   e8 fc ff ff ff          call   2a <main+0x2a>
2e:   e8 fc ff ff ff          call   2f <main+0x2f>
33:   dd 05 00 00 00 00       fldl   0x0
39:   dd 5d f0                fstpl  -0x10(%ebp)
3c:   dd 05 08 00 00 00       fldl   0x8
42:   dd 5d e8                fstpl  -0x18(%ebp)
45:   dd 45 f0                fldl   -0x10(%ebp)
48:   dc 75 e8                fdivl  -0x18(%ebp)
4b:   dd 5d e0                fstpl  -0x20(%ebp)
4e:   dd 05 08 00 00 00       fldl   0x8
54:   dd 5d d8                fstpl  -0x28(%ebp)
57:   dd 45 e0                fldl   -0x20(%ebp)
5a:   dd 05 08 00 00 00       fldl   0x8
60:   df e9                   fucomip %st(1),%st
62:   dd d8                   fstp   %st(0)
64:   7a 56                   jp     bc <main+0xbc>
66:   dd 45 e0                fldl   -0x20(%ebp)
69:   dd 05 08 00 00 00       fldl   0x8
6f:   df e9                   fucomip %st(1),%st
71:   dd d8                   fstp   %st(0)
73:   75 47                   jne    bc <main+0xbc>
75:   c7 45 ac 48 61 72 64    movl   $0x64726148,-0x54(%ebp)
7c:   c7 45 b0 63 6f 64 65    movl   $0x65646f63,-0x50(%ebp)
83:   c7 45 b4 64 20 76 61    movl   $0x61762064,-0x4c(%ebp)
8a:   c7 45 b8 6c 75 65 73    movl   $0x7365756c,-0x48(%ebp)
91:   c7 45 bc 20 77 65 72    movl   $0x72657720,-0x44(%ebp)
98:   c7 45 c0 65 20 63 6f    movl   $0x6f632065,-0x40(%ebp)
9f:   c7 45 c4 72 72 65 63    movl   $0x63657272,-0x3c(%ebp)
a6:   c7 45 c8 74 0a 00 00    movl   $0xa74,-0x38(%ebp)
ad:   83 ec 0c                sub    $0xc,%esp
b0:   8d 45 ac                lea    -0x54(%ebp),%eax
b3:   50                      push   %eax
b4:   e8 fc ff ff ff          call   b5 <main+0xb5>
b9:   83 c4 10                add    $0x10,%esp
bc:   c7 45 cc 45 6e 64 20    movl   $0x20646e45,-0x34(%ebp)
c3:   c7 45 d0 6f 75 74 70    movl   $0x7074756f,-0x30(%ebp)
ca:   c7 45 d4 75 74 00 00    movl   $0x7475,-0x2c(%ebp)
d1:   83 ec 0c                sub    $0xc,%esp
d4:   8d 45 cc                lea    -0x34(%ebp),%eax
d7:   50                      push   %eax
d8:   e8 fc ff ff ff          call   d9 <main+0xd9>
dd:   83 c4 10                add    $0x10,%esp
e0:   eb fe                   jmp    e0 <main+0xe0>

在浏览了各种资源后,我在OSdev上找到了这个论坛页面:forum.osdev.org/viewtopic.php?f=1&t=21813,描述了首先检查FPU,然后初始化它的过程。事实证明,无论出于何种原因,我的目标平台都没有FPU,我猜这就是未定义行为的原因。

最新更新