Today I was working on setting up interrupt handling for my OS and encountered a crazy g++ bug (or maybe I made a mistake?).
I set up IDT and ISRs entirely from .cpp files, here are a few screenshots:
Macros to generate an assembly entry for the isr
InterruptServiceRoutines class: (USED is __attribute__((used)), g++ seems to omit the symbol otherwise)
How I use it in my c++ code
(The NO_ERROR_CODE macro is the same as on the first screenshot, the only difference is that it does pushl 0 in the beginning)
As you can see in the third screenshot I have a stub, if I remove it the first defined interrupt handler turns into a NULL
So in this case if I remove the stub, the address of division_by_zero_entry (NOT HANDLER!) is 0x00000000, I see it in the
debugger as well. Every other isr has the correct address and I verified it multiple times. If I change the order around, any other
isr (like debug_handler) becomes NULL and division_by_zero_entry becomes a valid address!
With stub: (IDT table from Bochs debugger)
Without the stub the first entry becomes 0x0008:0x00000000
If you need any more information please let me know!
EDIT: Now that i'm trying to reproduce it I can't anymore... Any ideas why it happened before? I'm sure everything else was correct, because I was getting double faulted as expected. (from not remapping the PIC)
g++ bug?
Re: g++ bug?
My guess would be you were using inline assembly for your ISR stub. The optimizer may "optimize" the code in a way that results in strange bugs. If you continue with inline ASM, you will be constantly dealing with bugs. I recommend switching to using external assembly files. My ISR stub file is at https://github.com/NexSuite/NexNix/blob ... _stubs.asm. Feel free to use it however you wish. You could also use __attribute__((interrupt)) before the function name. I'm not sure if this is in g++.
Re: g++ bug?
Thanks, I might do something like this as wellnexos wrote:My guess would be you were using inline assembly for your ISR stub. The optimizer may "optimize" the code in a way that results in strange bugs. If you continue with inline ASM, you will be constantly dealing with bugs. I recommend switching to using external assembly files. My ISR stub file is at https://github.com/NexSuite/NexNix/blob ... _stubs.asm. Feel free to use it however you wish. You could also use __attribute__((interrupt)) before the function name. I'm not sure if this is in g++.
Re: g++ bug?
Couldn't agree more. This definitely.nexos wrote:...If you continue with inline ASM, you will be constantly dealing with bugs. I recommend switching to using external assembly files...
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
-
- Member
- Posts: 797
- Joined: Fri Aug 26, 2016 1:41 pm
- Libera.chat IRC: mpetch
Re: g++ bug?
I noticed at least for the code in the screenshots that the stubs are not inside of C functions. They are all basic inline assembly at global scope. Basic inline assembly has no optimizations applied to them, nor are they these stubs surrounded by C function prologue and epilogue.
I'm not fond of the interrupt attribute because it too is limited and has deficiencies. If you ever want your C code to access the contents of a register as they appeared at the time of the interrupt, there is currently no reliable way to do it with this mechanism. This would be handy if you were writing a software interrupt and needed access to the registers to determine what actions to take (ie: int 0x80 on Linux). Another example would be to allow an interrupt to dump all the register contents to the display for debug purposes.
I'm not fond of the interrupt attribute because it too is limited and has deficiencies. If you ever want your C code to access the contents of a register as they appeared at the time of the interrupt, there is currently no reliable way to do it with this mechanism. This would be handy if you were writing a software interrupt and needed access to the registers to determine what actions to take (ie: int 0x80 on Linux). Another example would be to allow an interrupt to dump all the register contents to the display for debug purposes.