Today’s puzzle is about some code behaving horribly wrong.
Recently, I was working on some operating system project and hacking on the code to switch between privileged and non-privileged mode. I could switch modes successfully and intercept traps when in non-privileged mode.
Then I wanted to check whether I could handle timer interrupts correctly, so I added this to my non-privileged code, to give the timer interrupt a chance to fire:
volatile int i; for (i=0; i<10000; i++);
Timer interrupts were handled correctly and eventually returned to the non-privileged code – but the delay code turned into an infinite loop!
I changed to loop to count only to 10, and I changed it to count down instead of up, but the result remained the same. I looked at the generated assembly. It looked like this:
movl $10, 0xfc(%ebp) // i = 10 jmp 1f // goto 1 2: movl 0xfc(%ebp), %eax // %eax = i decl %eax // %eax-- movl %eax,0xfc(%ebp) // i = %eax 1: movl 0xfc(%ebp), %eax // %eax = i testl %eax, %eax // if (%eax > 0) jg 2b // goto 2
It looked fine. On every timer interrupt, I dumped %eax, and it was stuck at 10. I debugged my pusha/popa code to save and restore registers between modes, and it was okay. I debugged my flag handing code, and flags were fine.
Then I replaced my C code with the generated assembly code and added instructions that copied the value of %eax before the “decl” into %ebx, and after the “decl” into %ecx and added a trap instruction right after that to have privileged mode print out the values of the three registers.
movl $10, 0xfc(%ebp) // i = 10 jmp 1f // goto 1 2: movl 0xfc(%ebp), %eax // %eax = i movl %eax, %ebx // value before decl %eax // %eax-- movl %eax, %ecx // value after TRAP movl %eax,0xfc(%ebp) // i = %eax 1: movl 0xfc(%ebp), %eax // %eax = i testl %eax, %eax // if (%eax > 0) jg 2b // goto 2
The result was %eax = %ebx = %ecx = 10. This is when I understood what was going on.
Please share your comments below. :-)