Day 38: After 6 days, I have problems that I can't understand at all
source link: https://jvns.ca/blog/2013/12/06/day-38-after-7-days/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Day 38: After 6 days, I have problems that I can't understand at all
tl;dr: I expect NUMS[2]
to equal NUMS[keycode]
when keycode ==
2
. This doesn’t appear to be the case, and I don’t understand how
this is possible.
I’m trying to set up keycode handling in my kernel, and I’m having a strange problem with array indexing that I can’t really fathom at all (except “something is wrong”).
When I run this code, and press 1
several times, it prints |2C |2C |2C |2C |2C |2C |2C |2C |2C
.
I am expecting it to print |2C2|2C2|2C2|2C2|2C2|2C2|2C2|2C2|2C2|
.
Here is the code:
// some imports removed
static NUMS: &'static [u8] = bytes!("01234567890");
#[no_mangle]
pub unsafe fn _interrupt_handler_kbd() {
let keycode: u8 = inb(0x60);
if (keycode == 2 || keycode == 3) {
stdio::putc(NUMS[2]); // should be '2'. It is.
stdio::putc(65 + keycode); // should be 'C' (keycode = 2), because 'A' is 65
stdio::putc(NUMS[keycode]); // should be '2', BUT IT ISN'T. IT IS SOMETHING ELSE. HOW IS THIS HAPPENING.
stdio::putc(124); /// this is '|', just as a delimiter.
}
outb(0x20, 0x20); // Tell the interrupt handler that we're done.
}
To summarize:
- the
2
is printed byputc(NUMS[2])
- the
C
is printed byputc(65 + keycode)
. This implies thatkeycode == 2
, since 65 is ‘A’ - the blank space is printed by
putc(NUMS[keycode])
. I would expect this to print2
. But no.
For bonus points, if I replace if (keycode == 2 || keycode == 3) {
with if(keycode == 2) {
, then it prints
|2C2|2C2|2C2|2C2|2C2|2C2|2C2|2C2|2C2|
, which is right. I think this
is because of a compiler optimization replacing keycode
with 2
.
If you have qemu
and a nightly build of rust
installed, you can
run this code by doing
git clone [email protected]:jvns/rustboot.git
cd rustboot
git checkout origin/compiler-nonsense
git submodule init
git submodule update
make run
Some hypotheses:
- There’s something wrong with the Rust compiler
- There’s something wrong with the stack and how I’m calling
_interrupt_handler_kbd
- ?????????
I also can’t yet find the address of _interrupt_handler_kbd
to look
at the assembly to debug. It’s in the symbol table of the original
object file (main.o
), but after linking it’s not in main.bin
, so I
can’t set a breakpoint in gdb.
Edit: Brian Mastenbrook suggested to link using ELF and then use objcopy to create a binary, and that somehow magically fixed the problem (this commit). If anyone can explain why, I would be Extremely Interested.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK