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: Select all
.text
.Ltext_offset:
Then each GOT address calculation is modified:
Code: Select all
call __x86.get_pc_thunk.bx
// addl $_GLOBAL_OFFSET_TABLE_, %ebx
addl $(.Ltext_offset - .), %ebx
Code: Select all
// leal .LC0@GOTOFF(%ebx), %eax
movl $(.LC0-.Ltext_offset), %eax
addl %ebx, %eax
Code: Select all
int foo;
void bar() {
m = foo;
...
foo = n;
}
Code: Select all
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;
...
}
Regards,
Dmitry