Making PE multiboot-compliant

My old poor boot loader broke once again. Or should I say it was inherently broken and simply yet another bug manifested its existence? Anyway, I won’t fix anything in that boot loader anymore. It’s simply not worth any effort. So, farewell, my old boot loader! Let’s use GRUB, at least it won’t crash randomly, it has many useful features, and in general it’s better.

But wait! If I want GRUB to load my kernel, the kernel image must be multiboot-compliant. Almost every “roll your own operating system” talks about how you can make your kernel bootable by GRUB (aka multiboot-compliant). But they assume that the format of the kernel image is ELF. And mine kernel is not ELF, it’s PE. This makes things more complicated.

Of course, a solution exists. Sadly, this one, which is unfortunately pretty bad (look at these hardcoded values and think a while about problems they’ll cause), is, barring using GNU linker with a contrived script defining exact order of sections and what not, actually the only one I’ve heard of. Clearly, we need something better.

Let’s think a while about the structure of a PE file. What’s the first structure in the file? It’s the MZ header, which doesn’t contain anything important – only the first word and the last doubleword matters – as long as we don’t mind that DOS won’t run our executable. So, what we have there is basically 58 bytes of free space. Multiboot header is 48 bytes long in worst case. So, we can stash the multiboot header into the MZ header and everybody will be happy. The important thing is that we have to leave e_cblp field intact – not because it contains anything relevant, but simply for multiboot header has to be doubleword aligned.

This time I won’t provide a code which does the thing, but rather a general hints how the code should look like (what should be overwritten by what and the like). It should be easy to write a program which processes the image in the given way (yeah, this is the drawback of the idea – it requires separate program to process the executable. Fortunately, it’s possible to make it a post-build step in most IDEs) in your language of choice. Oh, I forgot one important thing: file alignment and section alignment have to be equal or else the kernel won’t run or will behave abnormally! Check your linker’s documentation for details about changing file or section alignment (by default they’re 512 and 4096 respectively).

So we’re starting overwriting from the fifth byte, as previous shouldn’t be modified (the first two are magic number, if they’re changed, our file won’t be a valid PE anymore). Magic number, flags (sixteenth bit must be set, or else GRUB will complain about the format) and checksum aren’t causing much trouble – they don’t depend on the image (i.e. they won’t change as the image grows larger or something), so it’s as simple as just writing 12 bytes (because it’s actually writing 12 bytes, heh).

Now, the funny part begins – physical multiboot header address. We can either hardcode it (not recommended), or read the image base from the PE optional header and add four to it (because multiboot header begins at fifth byte, and fifth byte is the one with address 4). Next thing is the start of things to be loaded, which must be less than or equal to the previous value. Putting image base here will do the trick. Next thing is more interesting – we have to find the physical address of the end of (initialized) data! Again, fields inside optional header come to the rescue – image base + base of data + size of initialized data (I’m unsure here, but so far it works for me just fine; perhaps the better way is to read all section headers and calculate this according to the values found there). Next thing is the physical address of the end of uninitialized data section. I’ve put image base + size of image (yes, it’s from optional header, too) here, but again I’m not sure whether it’s the best thing to do. And, finally, the last thing – address of entry point. Yeah, image base + address of entry point from optional header.

So we made our image multiboot-compliant, utilizing some unused space and without hardcoding anything. Surely it won’t work with some files, but as long as the kernel is just a simple PE (i.e. built without linker-switch-or-script-magic, just with default or almost default – remember, the file and section alignment! – settings), it’ll work. If you know how the idea can be improved, you have some valuable infos, or anything else, then don’t hesitate and write a comment – they’re appreciated, as always.

~ - autor: Fanael w dniu Czerwiec 24, 2010.

Dodaj komentarz

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Zmień )

Twitter picture

You are commenting using your Twitter account. Log Out / Zmień )

Facebook photo

You are commenting using your Facebook account. Log Out / Zmień )

Connecting to %s

 
Follow

Otrzymuj każdy nowy wpis na swoją skrzynkę e-mail.