Custom bootloader trouble

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
bytbox
Posts: 11
Joined: Mon May 10, 2010 8:01 pm

Custom bootloader trouble

Post 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.)
Tosi
Member
Member
Posts: 255
Joined: Tue Jun 15, 2010 9:27 am
Location: Flyover State, United States
Contact:

Re: Custom bootloader trouble

Post by Tosi »

Do you have a cross compiler, and if so, which versions?
bytbox
Posts: 11
Joined: Mon May 10, 2010 8:01 pm

Re: Custom bootloader trouble

Post 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).
User avatar
Chandra
Member
Member
Posts: 487
Joined: Sat Jul 17, 2010 12:45 am

Re: Custom bootloader trouble

Post 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..........
Programming is not about using a language to solve a problem, it's about using logic to find a solution !
bytbox
Posts: 11
Joined: Mon May 10, 2010 8:01 pm

Re: Custom bootloader trouble

Post 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.)
User avatar
Chandra
Member
Member
Posts: 487
Joined: Sat Jul 17, 2010 12:45 am

Re: Custom bootloader trouble

Post 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 = .;
}
Programming is not about using a language to solve a problem, it's about using logic to find a solution !
bytbox
Posts: 11
Joined: Mon May 10, 2010 8:01 pm

Re: Custom bootloader trouble

Post 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.)
Casm
Member
Member
Posts: 221
Joined: Sun Oct 17, 2010 2:21 pm
Location: United Kingdom

Re: Custom bootloader trouble

Post 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.
Last edited by Casm on Sun Mar 20, 2011 7:35 pm, edited 2 times in total.
User avatar
Jezze
Member
Member
Posts: 395
Joined: Thu Jul 26, 2007 1:53 am
Libera.chat IRC: jfu
Contact:

Re: Custom bootloader trouble

Post 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.
Fudge - Simplicity, clarity and speed.
http://github.com/Jezze/fudge/
bytbox
Posts: 11
Joined: Mon May 10, 2010 8:01 pm

Re: Custom bootloader trouble

Post 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?
User avatar
Chandra
Member
Member
Posts: 487
Joined: Sat Jul 17, 2010 12:45 am

Re: Custom bootloader trouble

Post 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?
Programming is not about using a language to solve a problem, it's about using logic to find a solution !
User avatar
Jezze
Member
Member
Posts: 395
Joined: Thu Jul 26, 2007 1:53 am
Libera.chat IRC: jfu
Contact:

Re: Custom bootloader trouble

Post 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.
Fudge - Simplicity, clarity and speed.
http://github.com/Jezze/fudge/
Post Reply