如果我的问题没有以最好的方式格式化,我会提前道歉,我是这里提问的新手。
最近,我对学习操作系统开发很感兴趣,在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,我猜这就是未定义行为的原因。