Page 1 of 2

Multiboot Kernel

Posted: Sun Apr 29, 2007 2:35 pm
by Bughunter
This is my first attempt at a kernel in C, before I used ASM for a long time (and used it for OS dev). I moved on to C last year and it was time to try a kernel in it :)

I've followed the 'basickernel.pdf' from osdever.net and Tim Robinson's documents about C kernels.

I'm using a native GNU/Linux environment to build my kernel.

When trying to boot my kernel with GRUB; it says: "Invalid or unsupported executable format".

I've ran objdump against all object files and against the final executable, they are all in the ELF format. So, the AOUT kludge should not be needed (according to what I've read when searching for a solution at this forum).

Also, GRUB's "mbchk" tool says all test passed and that the multiboot header was found at offset 4096 in the final executable.

In the attachments I'm including the output of 'objdump -x'. If anyone needs more information regarding the problem or wants to view source codes, please ask.

EDIT: "mbchk" says "Address fields is turned off." (I'm using ELF though)

Posted: Sun Apr 29, 2007 4:41 pm
by Pyrofan1
Are you sure you're linking it properly?

Posted: Sun Apr 29, 2007 4:43 pm
by mystran
Your trying to load at address zero. GRUB won't allow that. Load to 1MB instead.

Posted: Sun Apr 29, 2007 4:49 pm
by Bughunter
Pyrofan1 wrote:Are you sure you're linking it properly?
Not sure but it I copied it pretty much from tutorials so it should be fine. Do you want to see my linker script?
mystran wrote:Your trying to load at address zero. GRUB won't allow that. Load to 1MB instead.
How can I change this? In the linker script? In my multiboot stub?

Posted: Sun Apr 29, 2007 5:15 pm
by mystran
bughunter wrote:
Pyrofan1 wrote:Are you sure you're linking it properly?
Not sure but it I copied it pretty much from tutorials so it should be fine. Do you want to see my linker script?
mystran wrote:Your trying to load at address zero. GRUB won't allow that. Load to 1MB instead.
How can I change this? In the linker script? In my multiboot stub?
In linker script. Here's the script I use:

Code: Select all

OUTPUT_FORMAT("elf32-i386")
ENTRY(start)

load_address = 0x100000; /* at 1M */

SECTIONS
{
    . = load_address;

    .text :
    {
        *(.multiboot.header)    /* must be within 8k, so put first */

        *(.text)
        *(.rodata*)
    }

    .data : {
        data = .;
        *(.data)
    }

    .bss : {
        bss = .;
        *(.bss)
        *(COMMON)
    }

    _kernel_end = .;
}
The .multiboot.header is a special section defined in my boot.S since I don't like the idea of relying on order of parameters on command line. You don't need it if you don't mind having to but the file with the multiboot header first on your linker command line..

Posted: Sun Apr 29, 2007 5:18 pm
by Assembler
bughunter wrote: Do you want to see my linker script?
Better for you
bughunter wrote: How can I change this? In the linker script? In my multiboot stub?
something like that :

Code: Select all

OUTPUT_FORMAT("elf32-i386")
ENTRY(entry)
virt = 0xC0000000; /* 3 GB */
phys = 0x100000; /* 1 MB */
SECTIONS
{   .text virt : AT(phys)
    {   code = .;
        *(.text)
        . = ALIGN(4096); 
    }
    .data :  AT(phys + (data - code))
    {   data = .;
         *(.data)
         . = ALIGN(4096); 
    }
    .bss :  AT(phys + (bss - code))
    {   bss = .;
        *(.bss)
        *(COMMON)
        . = ALIGN(4096); 
    }
    end = .; 
}
For higher kernel

Code: Select all

ENTRY (start)

SECTIONS
{
    . = 0x00100000;

    .text :
    {
        *(.text)
    }

    .rodata ALIGN (0x1000) :
    {
        *(.rodata)
    }

    .data ALIGN (0x1000) :
    {
        *(.data)
    }

    .bss :
    {
        _sbss = .;
        *(COMMON)
        *(.bss)
        _ebss = .;
    }
}
For lower kernel

Posted: Sun Apr 29, 2007 5:38 pm
by Bughunter
Assembler wrote: For lower kernel
I used exactly that one.

@mystran: the multiboot header is found at 4kB (says "mbchk"). By the way, I'd like to define my multiboot header just like yours, how can I define it in my assembly file (I'm using NASM)?

Posted: Sun Apr 29, 2007 6:07 pm
by mystran
I have absolutely no idea about Nasm. I've never even had it installed on any system I've had.. but in Gas you'd do it like this:

Code: Select all

      .section .multiboot.header
Look at NASM documentation. I would guess it can't be too different.

Posted: Sun Apr 29, 2007 6:26 pm
by Bughunter
Yeah I was already thinking about porting it to GAS, this encourages me to do so, as I also don't like to rely on the order of specifying files on the command line.

Anyways, I figured out my error. I was building on one system, and then transferring the files by FTP to another machine. You might already know what's wrong... I wasn't setting the transfer type to binary (I used Linux' console FTP program). It now works!

Another question though:
I've also setup a Cygwin environment on my XP box, and when building my kernel with Cygwin (using a cross compiler targeted for i586-elf) the output is about 6kB. But when compiling it under native Linux (slackware + GCC 3.4.2 is what I used) the final output is about 10kB. Does anybody have an idea why this happens?

EDIT: The Cygwin GCC cross compiler version is 4.1.2

Posted: Mon Apr 30, 2007 2:32 am
by urxae
bughunter wrote:Yeah I was already thinking about porting it to GAS, this encourages me to do so, as I also don't like to rely on the order of specifying files on the command line.
It's easy in NASM too. My multiboot header starts with:

Code: Select all

SECTION mb-header ALIGN=4
I use a different section name, but the principle is the same. (The ALIGN=4 may not be needed, but I added it to be safe. It may be ELF-specific though)

Posted: Mon Apr 30, 2007 2:34 am
by mystran
bughunter wrote: Another question though:
I've also setup a Cygwin environment on my XP box, and when building my kernel with Cygwin (using a cross compiler targeted for i586-elf) the output is about 6kB. But when compiling it under native Linux (slackware + GCC 3.4.2 is what I used) the final output is about 10kB. Does anybody have an idea why this happens?
The 4.1.2 series GCC supposedly has much better optimizer, so maybe it can generate smaller code? The other possibility is that your native Linux compiler includes more symbols or something.. you could try playing with strip and see if it can bring the filesize down. Not that it should matter.

Posted: Mon Apr 30, 2007 3:35 am
by Bughunter
urxae wrote: It's easy in NASM too. My multiboot header starts with:

Code: Select all

SECTION mb-header ALIGN=4
I use a different section name, but the principle is the same. (The ALIGN=4 may not be needed, but I added it to be safe. It may be ELF-specific though)
Thanks, but I already ported it to GAS now :P I also liked GAS because then everyone with the binutils can assemble it.
mystran wrote: The 4.1.2 series GCC supposedly has much better optimizer, so maybe it can generate smaller code? The other possibility is that your native Linux compiler includes more symbols or something.. you could try playing with strip and see if it can bring the filesize down. Not that it should matter.
I don't think it should make _that_ much difference, as the test kernel I started with in C is just one or two functions. And I used '-s' already while compiling, but I'll try strip. Posting results here shortly.

EDIT: On Cygwin, using 'strip -s' on the compiled kernel resulted in 4688 bytes. On Slackware Linux it resulted in a kernel of 8648 bytes. Hmm? Big difference :?

Posted: Mon Apr 30, 2007 8:47 am
by Candy
That sounds a lot like page alignment of the first page in the file, where the Linux executable did do that (text + rodata at 0x1000, data + bss at 0x2000) and the Win-ish executable didn't (text+rodata right after headers, data and bss with a page delay).

Posted: Mon Apr 30, 2007 2:06 pm
by Bughunter
So how can it be fixed? In my linker script? I used one exactly the same as the second example given by Assembler.

Posted: Mon Apr 30, 2007 2:28 pm
by mystran
Don't bother. Extra 4k for the kernel size hardly matters, especially as it's only the disk-size, not the final loaded size (assuming Candy is correct). Plus if you really care about disk-size, then you can gzip the resulting binary (Grub loads those as well) at which point the difference probably reduces to insignificance.