-1

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:

reality

Apparently it is giving me numba = 0 every time and therefore it doesn't work as expected:

expectation (plzzz don't ask me how I took this screenshot :PP)

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.)

MARSHMALLOW
  • 1,315
  • 2
  • 12
  • 24
  • 9
    You never initialize `numba`. – Eric Postpischil Aug 04 '21 at 01:21
  • @EricPostpischil How do I initialize it ;-) – MARSHMALLOW Aug 04 '21 at 01:27
  • 3
    @MARSHMALLOW You're writing a kernel but don't know how to initialize a variable? – Brady Dean Aug 04 '21 at 01:29
  • Ok, I got it sorry ;-) – MARSHMALLOW Aug 04 '21 at 01:43
  • 2
    `gcc -O1 -Wall` even warns you `'numba' may be used uninitialized in this function [-Wmaybe-uninitialized]` https://godbolt.org/z/35K5cY1nW. Apparently with optimization disabled you don't get a warning, but the compiler can spot bugs like this for you. Hardly seems worth undeleting the question, since it's not like floating-point is actually relevant to the problem. Just that a stand-alone non-kernel program will often read 0 bytes from the stack for uninitialized local vars if this is the deepest the callstack has ever gotten. – Peter Cordes Aug 04 '21 at 03:03
  • 2
    I bet the uninitialized memory in this case happened to contain `0xff` bytes. That's `NaN`. So `numba` will remain `NaN` no matter how many times you add 1, and it looks like on x86, casting `NaN` to `unsigned int` yields 0. So that would explain how `numba` mysteriously fails to increment. – Nate Eldredge Aug 04 '21 at 05:31

1 Answers1

2

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);
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256