Page 1 of 1

Custom bootloader trouble

Posted: Sun Mar 20, 2011 10:14 am
by bytbox
I wrote a custom bootloader - and it works. By which I mean, if my kernel is

Code: Select all

void kmain() {
        unsigned char *videoram = (unsigned char *)0xb8000;
        videoram[0]='H';
        videoram[2]='i';
}
The word "Hi" appears on the screen.

However, if I start using global variables...

Code: Select all

char h = 'H';
void kmain() {
        unsigned char *videoram = (unsigned char *)0xb8000;
        videoram[0]=h;
        videoram[2]='i';
}
Now the 'H' doesn't appear (it's blank), but the 'i' still does. Presumably, something's being put in the wrong location of memory (or being requested /from/ the wrong location of memory). My linker script is almost exactly the same as the one in the "bare bones" tutorial:

Code: Select all

ENTRY (loader)

SECTIONS {
        . = 0x00100000;

        .text : {
                *(.text)
        }

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

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

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

        /DISCARD/ : {
                *(.comment)
        }
}
I didn't bother putting a multiboot header in my loader.asm.

Code: Select all

global loader           ; making entry point visible to linker
extern kmain            ; kmain is defined elsewhere
 
; reserve initial kernel stack space
STACKSIZE equ 0x4000                  ; that's 16k.
 
loader:
        mov esp, stack+STACKSIZE           ; set up the stack
        call kmain                       ; call kernel proper
        cli
hang:
        hlt                                ; halt machine should kernel return
        jmp   hang

section .bss
align 4
stack:
        resb STACKSIZE                     ; reserve 16k stack on a doubleword boundary
I have verified that the global variable values do appear in the kernel image.

Any idea what sort of thing could be causing this?

(My code is at github.com/bytbox/wyvern if I left something important out.)

Re: Custom bootloader trouble

Posted: Sun Mar 20, 2011 10:29 am
by Tosi
Do you have a cross compiler, and if so, which versions?

Re: Custom bootloader trouble

Posted: Sun Mar 20, 2011 10:52 am
by bytbox
Tosi wrote:Do you have a cross compiler, and if so, which versions?
Erm...
$ gcc --version
gcc (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5
$ ld --version
GNU ld (GNU Binutils for Ubuntu) 2.20.51-system.20100908


And I'm using -m32, and linking with -melf_i386

Which I guess doesn't quite count as a cross-compiler, but it's always worked for previous experiments (using grub+multiboot rather than a custom-made bootloader).

Re: Custom bootloader trouble

Posted: Sun Mar 20, 2011 10:54 am
by Chandra
Here's a little help.

Use -S switch with gcc to output the resultant assembly file of the kernel.
gcc -c kernel.c -S kernel.s

Explore the assembly file kernel.s to see if the global variable h is actually in the data section and contains the byte value 72. If it is there, then make sure you load proper sectors from the disk. Also make sure your linker doesn't shuffle things around.
If it isn't there, things will be interesting..........

Re: Custom bootloader trouble

Posted: Sun Mar 20, 2011 11:03 am
by bytbox
Chandra wrote:Here's a little help.

Use -S switch with gcc to output the resultant assembly file of the kernel.
gcc -c kernel.c -S kernel.s
I'm assuming you meant gcc -S kernel.c -o kernel.s :P
Explore the assembly file kernel.s to see if the global variable h is actually in the data section and contains the byte value 72. If it is there, then make sure you load proper sectors from the disk. Also make sure your linker doesn't shuffle things around.
If it isn't there, things will be interesting..........
h is indeed in there, with byte value 72. I have no reason to think I'm not loading the proper sectors from the disk, but I'll have my bootloader "grep" for byte value 72 and tell me where it is placing it in memory when I have more time.

A question about linker scripts - how does the program know where it's being loaded in memory?

Assembly output was:

Code: Select all

        .file   "kmain.c"
.globl h
        .data
        .type   h, @object
        .size   h, 1
h:
        .byte   72
        .text
.globl kmain
        .type   kmain, @function
kmain:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        movq    %rsp, %rbp
        .cfi_offset 6, -16
        .cfi_def_cfa_register 6
        movq    $753664, -8(%rbp)
        movzbl  h(%rip), %eax
        movl    %eax, %edx
        movq    -8(%rbp), %rax
        movb    %dl, (%rax)
        movq    -8(%rbp), %rax
        addq    $2, %rax
        movb    $105, (%rax)
        leave
        ret
        .cfi_endproc
.LFE0:
        .size   kmain, .-kmain
        .ident  "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5"
        .section        .note.GNU-stack,"",@progbits
(Thanks for the help, BTW.)

Re: Custom bootloader trouble

Posted: Sun Mar 20, 2011 11:15 am
by Chandra
bytbox wrote:I'm assuming you meant gcc -S kernel.c -o kernel.s
No, I meant gcc -c kernel.c -S kernel.s, which gives same result BTW.
bytbox wrote:A question about linker scripts - how does the program know where it's being loaded in memory?
The program doesn't know where it is being loaded in memory. You should know that and you should load the program in memory where it was intended to run (unless you are loading position independent code).
Does this linker script helps?

Code: Select all

OUTPUT_FORMAT("elf32-i386")   /* Replace this to match your target output */
ENTRY(loader)
phys = 0x00100000;
SECTIONS
{
  .text phys : AT(phys) {
    code = .;
    *(.text)
    *(.rodata)
    . = ALIGN(4096);
  }
  .data : AT(phys + (data - code))
  {
    data = .;
    *(.data)
    . = ALIGN(4096);
  }
  .bss : AT(phys + (bss - code))
  {
    bss = .;
    *(.bss)
    . = ALIGN(4096);
  }
  end = .;
}

Re: Custom bootloader trouble

Posted: Sun Mar 20, 2011 7:20 pm
by bytbox
Does this linker script helps?
Nope.

Using objdump -s, it seems that the issue is that the linker expects the .text section to be loaded starting exactly at 0x10000, but since I'm simply copying the executable into 0x10000 and jmp'ing to it, the elf headers take up space and displace the rest of the executable.

This seems to mean that my bootloader must process the ELF headers and do actual work, rather than simply dump the kernel into memory. Any way around this? (Setting -oformat=binary doesn't seem to have any effect.)

Re: Custom bootloader trouble

Posted: Sun Mar 20, 2011 7:25 pm
by Casm
bytbox wrote:
Does this linker script helps?
Nope.

Using objdump -s, it seems that the issue is that the linker expects the .text section to be loaded starting exactly at 0x10000, but since I'm simply copying the executable into 0x10000 and jmp'ing to it, the elf headers take up space and displace the rest of the executable.

This seems to mean that my bootloader must process the ELF headers and do actual work, rather than simply dump the kernel into memory. Any way around this? (Setting -oformat=binary doesn't seem to have any effect.)
The assembly code from which you call the kernel function needs to be ORGed to 0x10000, or wherever else it is you are going to load it.

Also, you will need to parse the ELF file when you load it - either that or use a flat binary. The ELF header is there for a reason, and that reason is to tell you where different parts of the file need to be loaded.

Re: Custom bootloader trouble

Posted: Sun Mar 20, 2011 7:32 pm
by Jezze
Yeah it sounds like you are executing the ELF headers. If you don't want to care about parsing them the offset is probably 4096 so you could jump to 0x10000 + 4096 and it should work.

Another way would be to compile the program as a pure binary without elf headers. Don't remember what flags you would use but you can always look it up.

Re: Custom bootloader trouble

Posted: Sun Mar 20, 2011 8:25 pm
by bytbox
Oof... got it. Generating a flat binary kernel and loading into the right place (rather than one sector off).

Is there any significant advantage to using ELF (or other actual format) over flat binary?

Re: Custom bootloader trouble

Posted: Sun Mar 20, 2011 9:14 pm
by Chandra
bytbox wrote:Is there any significant advantage to using ELF (or other actual format) over flat binary?
There are lots of advantages, that's why ELF format is in use. Did you look at the elf specifications?

Re: Custom bootloader trouble

Posted: Sun Mar 20, 2011 10:26 pm
by Jezze
Actually using ELF for the kernel is not as important as having ELF for modules or user programs where it probably is mandatory if you wan't modern features like relocation of object files and instruction independent code. Linking a module to the kernel could be done by using a symbol table. It might not better, I'm just saying.