Kernel Crashes due to compiler optimization
Kernel Crashes due to compiler optimization
Hello,
i686-elf-gcc -c print.c -o print.o -std=gnu99 -ffreestanding -Os -Wall -Wextra
By using the above -OS or -O2 or any flag optimisation, the following causing the crash
Puts(){
Putc ();
Here the compiler compiling Putc as Jmp Putc instead of Call Putc
}
So i removed optimization flag and complied , then everything went well but the code size of Kernel changed massively.
Any Suggestions on this optimizing and achieving call instruction instead Jmp @ Putc
i686-elf-gcc -c print.c -o print.o -std=gnu99 -ffreestanding -Os -Wall -Wextra
By using the above -OS or -O2 or any flag optimisation, the following causing the crash
Puts(){
Putc ();
Here the compiler compiling Putc as Jmp Putc instead of Call Putc
}
So i removed optimization flag and complied , then everything went well but the code size of Kernel changed massively.
Any Suggestions on this optimizing and achieving call instruction instead Jmp @ Putc
Re: Kernel Crashes due to compiler optimization
I suspect that the crash, in this case, is caused not by a GCC bug, but by PEBKAC.
Re: Kernel Crashes due to compiler optimization
And why jumping to Putc() should be bad? Did you write some crappy inline assembly code in Putc()?yerri07 wrote: By using the above -OS or -O2 or any flag optimisation, the following causing the crash
Puts(){
Putc ();
Here the compiler compiling Putc as Jmp Putc instead of Call Putc
}
So i removed optimization flag and complied , then everything went well but the code size of Kernel changed massively.
Any Suggestions on this optimizing and achieving call instruction instead Jmp @ Putc
Re: Kernel Crashes due to compiler optimization
No inline assembly , here comes another one , Watch @c00013e4, this occurred even without O flag. Declaring the function prototypes with cdecl and any , would solve the issue?
c00013a9 <GotoXY>:
c00013a9: 80 3d 22 26 00 c0 50 cmpb $0x50,0xc0002622
c00013b0: 55 push %ebp
c00013b1: 89 e5 mov %esp,%ebp
c00013b3: 8b 55 08 mov 0x8(%ebp),%edx
c00013b6: 8b 45 0c mov 0xc(%ebp),%eax
c00013b9: 77 06 ja c00013c1 <DebugGotoXY+0x18>
c00013bb: 88 15 22 26 00 c0 mov %dl,0xc0002622
c00013c1: 80 3d 21 26 00 c0 19 cmpb $0x19,0xc0002621
c00013c8: 77 05 ja c00013cf <DebugGotoXY+0x26>
c00013ca: a2 21 26 00 c0 mov %al,0xc0002621
c00013cf: 0f b6 05 21 26 00 c0 movzbl 0xc0002621,%eax
c00013d6: 89 45 0c mov %eax,0xc(%ebp)
c00013d9: 0f b6 05 22 26 00 c0 movzbl 0xc0002622,%eax
c00013e0: 89 45 08 mov %eax,0x8(%ebp)
c00013e3: 5d pop %ebp
c00013e4: e9 75 fd ff ff jmp c000115e <UpdateCur>
c00013a9 <GotoXY>:
c00013a9: 80 3d 22 26 00 c0 50 cmpb $0x50,0xc0002622
c00013b0: 55 push %ebp
c00013b1: 89 e5 mov %esp,%ebp
c00013b3: 8b 55 08 mov 0x8(%ebp),%edx
c00013b6: 8b 45 0c mov 0xc(%ebp),%eax
c00013b9: 77 06 ja c00013c1 <DebugGotoXY+0x18>
c00013bb: 88 15 22 26 00 c0 mov %dl,0xc0002622
c00013c1: 80 3d 21 26 00 c0 19 cmpb $0x19,0xc0002621
c00013c8: 77 05 ja c00013cf <DebugGotoXY+0x26>
c00013ca: a2 21 26 00 c0 mov %al,0xc0002621
c00013cf: 0f b6 05 21 26 00 c0 movzbl 0xc0002621,%eax
c00013d6: 89 45 0c mov %eax,0xc(%ebp)
c00013d9: 0f b6 05 22 26 00 c0 movzbl 0xc0002622,%eax
c00013e0: 89 45 08 mov %eax,0x8(%ebp)
c00013e3: 5d pop %ebp
c00013e4: e9 75 fd ff ff jmp c000115e <UpdateCur>
-
- Member
- Posts: 5586
- Joined: Mon Mar 25, 2013 7:01 pm
Re: Kernel Crashes due to compiler optimization
Your kernel is not crashing due to compiler optimization.
Most likely, you have written bad code without realizing it. Show us the code that's crashing and we can try to figure out what's wrong.
Most likely, you have written bad code without realizing it. Show us the code that's crashing and we can try to figure out what's wrong.
Re: Kernel Crashes due to compiler optimization
If anything, the optimizing code paths of a compiler are even more well-tested than the non-optimizing ones. I second Octocontrabass here -- most likely enabling optimization unveiled a problem with your code, but the problem is still with your code, not the compiler. (That's just hugely unlikely.)
Every good solution is obvious once you've found it.
Re: Kernel Crashes due to compiler optimization
Hi,
There's a chance that language design and/or compiler design are partially responsible for "programmer error not detected at compile time". For a simple example; maybe various warnings (that perhaps should've been enabled by default but aren't) haven't been explicitly enabled.
Cheers,
Brendan
That's probably a perfectly valid tail call optimisation.yerri07 wrote:Here the compiler compiling Putc as Jmp Putc instead of Call Putc
The problem/s are likely to be caused by undefined behaviour and/or other forms of "programmer error"; but what caused "programmer error"?Solar wrote:If anything, the optimizing code paths of a compiler are even more well-tested than the non-optimizing ones. I second Octocontrabass here -- most likely enabling optimization unveiled a problem with your code, but the problem is still with your code, not the compiler. (That's just hugely unlikely.)
There's a chance that language design and/or compiler design are partially responsible for "programmer error not detected at compile time". For a simple example; maybe various warnings (that perhaps should've been enabled by default but aren't) haven't been explicitly enabled.
Cheers,
Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Re: Kernel Crashes due to compiler optimization
A topical StackOverflow answer regarding the use of compiler warnings...
Every good solution is obvious once you've found it.
Re: Kernel Crashes due to compiler optimization
Solar wrote:A topical StackOverflow answer regarding the use of compiler warnings...
Thank you for the link , but i haven't recieved any warnings compile and linking process went good
Re: Kernel Crashes due to compiler optimization
Hi,
Maybe it would help if I "de-optimised" the compiler's code:
The original disassembly, just with some tidying up (whitespace, etc):
Without the tail call optimisation:
Without instruction re-ordering:
A guess at the original C:
That looks buggy to me, so here's a guess at what the original code should have been:
Of course we have no idea how many bugs are in your original C source code, because you haven't provided any.
Cheers,
Brendan
Maybe it would help if I "de-optimised" the compiler's code:
The original disassembly, just with some tidying up (whitespace, etc):
Code: Select all
c00013a9 <GotoXY>:
cmpb $0x50,0xc0002622
push %ebp
mov %esp,%ebp
mov 0x8(%ebp),%edx
mov 0xc(%ebp),%eax
ja .L1
mov %dl,0xc0002622
.L1:
cmpb $0x19,0xc0002621
ja .L2
mov %al,0xc0002621
.L2:
movzbl 0xc0002621,%eax
mov %eax,0xc(%ebp)
movzbl 0xc0002622,%eax
mov %eax,0x8(%ebp)
pop %ebp
jmp c000115e <UpdateCur>
Code: Select all
c00013a9 <GotoXY>:
cmpb $0x50,0xc0002622
push %ebp
mov %esp,%ebp
mov 0x8(%ebp),%edx
mov 0xc(%ebp),%eax
ja .L1
mov %dl,0xc0002622
.L1:
cmpb $0x19,0xc0002621
ja .L2
mov %al,0xc0002621
.L2:
movzbl 0xc0002621,%eax
mov %eax,0xc(%ebp)
movzbl 0xc0002622,%eax
mov %eax,0x8(%ebp)
call c000115e <UpdateCur>
pop %ebp
ret
Code: Select all
c00013a9 <GotoXY>:
push %ebp
mov %esp,%ebp
mov 0x8(%ebp),%edx
mov 0xc(%ebp),%eax
cmpb $0x50,0xc0002622
ja .L1
mov %dl,0xc0002622
.L1:
cmpb $0x19,0xc0002621
ja .L2
mov %al,0xc0002621
.L2:
movzbl 0xc0002621,%eax
mov %eax,0xc(%ebp)
movzbl 0xc0002622,%eax
mov %eax,0x8(%ebp)
call c000115e <UpdateCur>
pop %ebp
ret
Code: Select all
int currentX;
int currentY;
void GotoXY(int x, int y) {
if(currentX <= 80) {
currentX = x;
}
if(currentY <= 25) {
currentY = y;
}
UpdateCur(currentX, currentY);
}
Code: Select all
int currentX;
int currentY;
void GotoXY(int x, int y) {
if(x < 80) {
currentX = x;
}
if(y < 25) {
currentY = y;
}
UpdateCur(currentX, currentY);
}
Cheers,
Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
-
- Member
- Posts: 5586
- Joined: Mon Mar 25, 2013 7:01 pm
Re: Kernel Crashes due to compiler optimization
I suspect the BrokenThorn tutorial code is crashing because you've made a mistake somewhere when you tried to translate it from MSVC to GCC.
You might have better luck with a tutorial specifically written to use GCC, or taking a break to improve your background knowledge before you try to tackle something as ambitious as developing an operating system.
You might have better luck with a tutorial specifically written to use GCC, or taking a break to improve your background knowledge before you try to tackle something as ambitious as developing an operating system.
- iocoder
- Member
- Posts: 208
- Joined: Sun Oct 18, 2009 5:47 pm
- Libera.chat IRC: iocoder
- Location: Alexandria, Egypt | Ottawa, Canada
- Contact:
Re: Kernel Crashes due to compiler optimization
Hi,
Thank you for posting the code. According to what I see now, the code makes a lot of checks to make sure that null pointer exceptions and out-of-range references do not occur. That's really nice. However, there is one line of code that really stopped me.
This line of code is strange. I don't know how your i686-gcc compiler doesn't report a warning at this line. This line should cause a warning even without -Wall and -Wextra!
This line of code,.... Well I don't really know how to express my feelings towards it... but it is really strange
It is like seeing an atom of Lithium (Li, with only 3 electrons) in a world full of Uranium
Despite all of these awkward feelings towards this strange line, it really touched me. The line, if you look at it very closely, is like a small child in a green garden. It is really cute and I have seen all my beautiful childhood when I looked at the line. But wait! my childhood wasn't beautiful. I still can't forget that creepy, awful day when... Sorry did you check stdarg.h before you use it in your operating system? Is it written by your or someone else? Are you sure about its behaviour? Is it deterministic?
First of all, without even looking at the context of va_arg here, your explicit cast from (char) to (int) with va_arg() is very dangerous. The manual itself says it very clearly: random errors will occur if promotions are not compatible with the passed type. The word "promotions" here refer to the promotions that are done by gcc-compiled code when a function is called. Types that are passed to that function are promoted. For example, on my machine, (char) parameters are promoted to (int) before the function is called (simply by movsbl instruction). For that reason, gcc should throw a warning at this point, because your assumption about argument-passing promotions as done by gcc is wrong.
Furthermore, it throws the same warning at places with the same risky use of va_arg(). For example, at line 261, the passed type is (char) so you simply used va_arg() with (char)... However, the compiler should tell you the whole point:
OK. I will pass 'char'... and I will ignore this silly warning... What on earth will happen? we always happily cast a (char) to (int) even when it is the Christmas day! Recent research on the origins of Java programmers suggests that their ancestors heavily used such awkward constructs and their programs worked well (to them). So what about gcc? Here comes the second note...
OK iocoder, that's easy... my compiler doesn't give me the same warning that appears to you, so it might be handling va_arg() differently, in a way that doesn't abort the program.
Me: OK dude, even if we assume that this random behavior is deterministic (how can this be?), I am sure the tape on Turing machine will get damaged if we run this program on it (and you can't replace the tape because it doesn't have boundaries).
Why? Let's look at the code again:
You assume that the passed type is char. In this case, you will ignore whatever that argument holds except the lowest significant byte. So, if for example, I pass this:
The va_arg (args, char) thing will evaluate to 0x78 with (char) type. You then convert this to integer, hoping that gods will return back the missed 0x123456 when the character is converted to an integer. You then convert the integer to char pointer and use it to retrieve the passed string!
I am not saying that this bug (I am not even sure if it is the actual bug that crashes your OS, because the behavior of va_arg is random in this case, so it might even be working correctly. But it is still a bug, because it will behave differently (in an unwanted manner) if I compile your OS with my gcc) is why your OS crashes, but my argument here is that such holes in a program are why it crashes. The compiler is an innocent child that is not intelligent enough to understand the reality of our awkward world.
My suggestion is to try to debug your code a component by component. We don't know exactly in which component the bug is hiding. The compiler itself might be buggy. However, the compiler is well tested. Is your program well tested?
You could also post the code of the other parts of your kernel that you suspect they have the bug. I love it when someone gives me code to fix and it is challenging to me. But, you must learn how to find the bug by yourself. Our answers here are just guidelines that help you understand what is going on.
Best of luck!
Thank you for posting the code. According to what I see now, the code makes a lot of checks to make sure that null pointer exceptions and out-of-range references do not occur. That's really nice. However, there is one line of code that really stopped me.
This line of code is strange. I don't know how your i686-gcc compiler doesn't report a warning at this line. This line should cause a warning even without -Wall and -Wextra!
This line of code,.... Well I don't really know how to express my feelings towards it... but it is really strange
It is like seeing an atom of Lithium (Li, with only 3 electrons) in a world full of Uranium
Despite all of these awkward feelings towards this strange line, it really touched me. The line, if you look at it very closely, is like a small child in a green garden. It is really cute and I have seen all my beautiful childhood when I looked at the line. But wait! my childhood wasn't beautiful. I still can't forget that creepy, awful day when... Sorry did you check stdarg.h before you use it in your operating system? Is it written by your or someone else? Are you sure about its behaviour? Is it deterministic?
Now let's see what type is passed to the innocent va_arg:TFM wrote: If there is no next argument, or if type is not compatible with the
type of the actual next argument (as promoted according to the default
argument promotions), random errors will occur.
Code: Select all
/*** address of ***/
case 's': {
int c = (int) va_arg (args, char);
char str[64];
strcpy (str,(const char*)c);
DebugPuts (str);
i++; // go to next character
break;
}
Furthermore, it throws the same warning at places with the same risky use of va_arg(). For example, at line 261, the passed type is (char) so you simply used va_arg() with (char)... However, the compiler should tell you the whole point:
Can you see it? The compiler tells us the truth. It doesn't lie like us (not because it is honest, but because it is dumb (or dump?)). A passed character will always be promoted to an integer, so you should use va_arg() with 'int', not 'char', according to the first note.gcc wrote: <your file>: In function <your function>:
<your file>:<the line>:<unsurprisingly, the column>:
warning: ‘char’ is promoted to ‘int’ when passed through ‘...’
char c = (char) va_arg(args, char);
^
note: (so you should pass ‘int’ not ‘char’ to ‘va_arg’)
note: if this code is reached, the program will abort
OK. I will pass 'char'... and I will ignore this silly warning... What on earth will happen? we always happily cast a (char) to (int) even when it is the Christmas day! Recent research on the origins of Java programmers suggests that their ancestors heavily used such awkward constructs and their programs worked well (to them). So what about gcc? Here comes the second note...
How innocent! Did you like it? I will make your program abort if this code is reached! You know what, If I compile and execute va_arg(args, char) on my x86_64 machine (using gcc), the program gives illegal instruction exception!gcc wrote: <your file>: In function <your function>:
<your file>:<the line>:<unsurprisingly, the column>:
warning: ‘char’ is promoted to ‘int’ when passed through ‘...’
char c = (char) va_arg(args, char);
^
note: (so you should pass ‘int’ not ‘char’ to ‘va_arg’)
note: if this code is reached, the program will abort
OK iocoder, that's easy... my compiler doesn't give me the same warning that appears to you, so it might be handling va_arg() differently, in a way that doesn't abort the program.
Me: OK dude, even if we assume that this random behavior is deterministic (how can this be?), I am sure the tape on Turing machine will get damaged if we run this program on it (and you can't replace the tape because it doesn't have boundaries).
Why? Let's look at the code again:
Code: Select all
int c = (int) va_arg (args, char);
....
strcpy (str,(const char*)c);
Code: Select all
printf("%s", 0x12345678);
I am not saying that this bug (I am not even sure if it is the actual bug that crashes your OS, because the behavior of va_arg is random in this case, so it might even be working correctly. But it is still a bug, because it will behave differently (in an unwanted manner) if I compile your OS with my gcc) is why your OS crashes, but my argument here is that such holes in a program are why it crashes. The compiler is an innocent child that is not intelligent enough to understand the reality of our awkward world.
My suggestion is to try to debug your code a component by component. We don't know exactly in which component the bug is hiding. The compiler itself might be buggy. However, the compiler is well tested. Is your program well tested?
You could also post the code of the other parts of your kernel that you suspect they have the bug. I love it when someone gives me code to fix and it is challenging to me. But, you must learn how to find the bug by yourself. Our answers here are just guidelines that help you understand what is going on.
Best of luck!
Re: Kernel Crashes due to compiler optimization
I tried above code cause another strange execution happened when i have a code to print functions in assembly and called the function from the c file(linked both files) , the first two instructions are not executed and but when i place a call to print the message with in the assembly file it executes correctly . So i gave a try compiling the above tutorial code.
see the disassembly of the code (push edi) in the image, the stack doesn't changed after the execution.
I will provide you the image that caused the strange execution.
1. After stepping the instruction
2.Before steeping the instruction
see the disassembly of the code (push edi) in the image, the stack doesn't changed after the execution.
I will provide you the image that caused the strange execution.
1. After stepping the instruction
2.Before steeping the instruction
Re: Kernel Crashes due to compiler optimization
Octocontrabass wrote:I suspect the BrokenThorn tutorial code is crashing because you've made a mistake somewhere when you tried to translate it from MSVC to GCC.
You might have better luck with a tutorial specifically written to use GCC, or taking a break to improve your background knowledge before you try to tackle something as ambitious as developing an operating system.
Thank you for the reply. Yes i believe i wiil be improved when i ran into these situations , and i learnt a lot while implementing , because of the wonderful support of the Series Editor Brokenthorn. And now i am feeling the support of Osdev forum too.
I learnt a lot while implementing rather studying.
Thank you all for the suggestions