So I'm writing a C kernel (which runs in protected mode) and I'm dabbling with floating point numbers. First, I wrote this C program to make sure that nothing goes wrong (runs on my physical machine, not as part of the kernel) that used a for
loop to increment a float
value by 1.0f
every time and display the result which worked as expected:
#include <stdio.h>
int main() {
float numba;
for(int i = 0; i < 100; i++) {
numba = numba + 1.0f;
printf("%d\n", (unsigned int)numba);
}
}
1
2
3
4
...
99
100
Considering that I cannot use printf
in my kernel, I had to implement that in some other way :P. Using the pixel drawing routine:
void putPixel(MODEINFOBLOCK mib, unsigned int x, unsigned int y, unsigned int color);
... I can make a perfect diagonal line. How? By incrementing the for
loop's counter and numba
, I am able to use them as the X and Y coordinates for the routine:
float numba;
for(int i = 0; i < 100; i++) {
numba = numba + 1.0f;
putPixel(mib, i, (unsigned int)numba, 0xFFFFFF);
}
However, I get this when I run the kernel:
Apparently it is giving me numba = 0
every time and therefore it doesn't work as expected:
By looking at the kernel's disassembly, I didn't notice anything very suspicious:
1ef: 83 c4 10 add esp,0x10
1f2: bb 00 00 00 00 mov ebx,0x0
1f7: d9 44 24 08 fld DWORD PTR [esp+0x8]
1fb: d8 05 f4 10 10 00 fadd DWORD PTR ds:0x1010f4
201: d9 54 24 08 fst DWORD PTR [esp+0x8]
205: 83 ec 0c sub esp,0xc
208: 68 ff ff ff 00 push 0xffffff
20d: d9 7c 24 1e fnstcw WORD PTR [esp+0x1e]
211: 0f b7 44 24 1e movzx eax,WORD PTR [esp+0x1e]
216: 80 cc 0c or ah,0xc
219: 66 89 44 24 1c mov WORD PTR [esp+0x1c],ax
21e: d9 6c 24 1c fldcw WORD PTR [esp+0x1c]
222: df 7c 24 10 fistp QWORD PTR [esp+0x10]
226: d9 6c 24 1e fldcw WORD PTR [esp+0x1e]
22a: ff 74 24 10 push DWORD PTR [esp+0x10]
22e: 53 push ebx
22f: 81 ec 18 01 00 00 sub esp,0x118
235: be 40 1c 10 00 mov esi,0x101c40
23a: b9 46 00 00 00 mov ecx,0x46
23f: 89 e7 mov edi,esp
241: f3 a5 rep movs DWORD PTR es:[edi],DWORD PTR ds:[esi]
243: e8 2c 01 00 00 call 0x374
248: 83 c3 01 add ebx,0x1
24b: 81 c4 30 01 00 00 add esp,0x130
251: 83 fb 64 cmp ebx,0x64
254: 75 a1 jne 0x1f7
256: e8 0c 00 00 00 call 0x267
25b: e8 0d 00 00 00 call 0x26d
260: 83 c4 10 add esp,0x10
263: 5b pop ebx
264: 5e pop esi
265: 5f pop edi
As you can see, the kernel is using FPU instructions. However, the program doesn't for some reason.
And the question is... Why does this happen? Is there something with FPUs in protected mode?
NOTE: This is literally my first time dealing with FP numbers, so I KNOW the answer for this question will seem obvious for y'all (I hope.)
numba
not initialized.
// float numba;
float numba = 0.0f;
for(int i = 0; i < 100; i++) {
numba = numba + 1.0f;
putPixel(mib, i, (unsigned int)numba, 0xFFFFFF);
}