Hello
I'm writing my own kernel, and after month of hitting the wall with my head I've found a way to
a) boot 64bit kernels from GRUB without assembly files
b) eliminate global offset table
I hope it will be useful for you.
My goal was to write 32bit code which deals with GRUB, creates page tables, GDT and other stuff in C++. Linker refuses to link 32bit and 64bit object files, but feels ok if you translate 32bit sources to assembly(with gcc -S), and them compile them as 64bit object files. The tool detects "#define MULTIBOOT_INTERFACE" line in source files and builds them with -m32 -S flags, then postprocesses assembly code and compiles the result into 64bit object files. Another problem is GOT with I don't want to see in my binary. This problem is solved during postprocessing stage.
During postprocessing stage I insert dummy section in file header:
Code:
.text
.Ltext_offset:
Also I remove .file directive because I dislike it, and #APP / #NOAPP lines - gcc wraps my inline assembly with them.
Then each GOT address calculation is modified:
Code:
call __x86.get_pc_thunk.bx
// addl $_GLOBAL_OFFSET_TABLE_, %ebx
addl $(.Ltext_offset - .), %ebx
Then each reference to GOT is replaced with address of label relative to .Ltext_offset:
Code:
// leal .LC0@GOTOFF(%ebx), %eax
movl $(.LC0-.Ltext_offset), %eax
addl %ebx, %eax
Upd: there is an unfixed problem with static variables:
Code:
int foo;
void bar() {
m = foo;
...
foo = n;
}
Please move all such variables into a static structure and get a pointer to this structure:
Code:
struct fb_parameters {
uint64 address = 0xB8000;
uint32 width = 80;
uint32 height = 24;
uint32 pitch = 0;
uint32 bpp = 0;
uint32 color = 0;
uint32 x = 0, w = 0;
static void (*putchar)(int);
};
static fb_parameters fb;
void print32 (const char *format, ...) {
auto f = &::fb;
...
}
There are still problems with instructions like movzbl, I'll fix them soon.
Regards,
Dmitry