Page 2 of 2

Posted: Tue Mar 25, 2008 3:24 pm
by brickhead20
Ok, fair point.

I tried a longer string, and adding the '\0' worked.

Heres the assembly that I pinched for this

Code: Select all

[BITS 32]
global start           ; making entry point visible to linker
extern main             ; _main is defined elsewhere

; setting up the Multiboot header - see GRUB docs for details
MODULEALIGN equ  1<<0                   ; align loaded modules on page boundaries
MEMINFO     equ  1<<1                   ; provide memory map
FLAGS       equ  MODULEALIGN | MEMINFO  ; this is the Multiboot 'flag' field
MAGIC       equ    0x1BADB002           ; 'magic number' lets bootloader find the header
CHECKSUM    equ -(MAGIC + FLAGS)        ; checksum required

section .text
align 4
MultiBootHeader:
   dd MAGIC
   dd FLAGS
   dd CHECKSUM

; reserve initial kernel stack space
STACKSIZE equ 0x4000          ; that's 16k.

start:
   mov esp, stack+STACKSIZE           ; set up the stack
   push eax                           ; pass Multiboot magic number
   push ebx                           ; pass Multiboot info structure

   call  main                        ; call kernel proper
               hlt                    ; halt machine should kernel return

section .bss
align 32
stack:
   resb STACKSIZE      ; reserve 16k stack on a quadword boundary

Posted: Tue Mar 25, 2008 3:34 pm
by -m32
Ok, two things that may cause issues:

1) Your 'start:' appears AFTER your multiboot spec, yet you're using the linker to put start's offset at 0x100000. This would mean, the multiboot info is being loaded at 0x100000 - 6 if I'm not mistaken. So, it's not being loaded correctly.

2) You said you're using a binary output file from your linker, yet you don't have an AOUT kludge here. The AOUT kludge is required if you're using a flat binary kernel.

Try something like this:

Code: Select all


start:
   mov esp, stack+STACKSIZE           ; set up the stack
   push eax                           ; pass Multiboot magic number
   push ebx                           ; pass Multiboot info structure

   call  main                        ; call kernel proper
               hlt                    ; halt machine should kernel return 

ALIGN 4
MultiBootHeader:
   dd MAGIC
   dd FLAGS
   dd CHECKSUM

   ; + AOUT kludge if kernel is flat binary

Give it a try, hope it helps. Good luck!

Posted: Tue Mar 25, 2008 3:54 pm
by brickhead20
OK, I tried both, but it does not appear to be helping. The AOUT kludge should have been there, but I still get the same error 13.

Posted: Tue Mar 25, 2008 4:34 pm
by Wave

Code: Select all

.string "Your String"
will be null-terminated, so don't worry.

If you get an error from GRUB then something is wrong with your executable.

If you are really using binary you need to use the A.OUT kludge. However, your linker script doesn't define the output format, so it will be the default that ld was compiled with. OUTPUT_FORMAT("binary") will make it use binary. But ELF is nicer to work with, since you don't need the A.OUT kludge.

If you're using binary you need to specify the entry point in the A.OUT kludge. If it starts running from the start as it's now, the computer will try to run your multiboot header.

You should use a separate section for the multiboot header to ensure it's placed first in the file.

Posted: Tue Mar 25, 2008 4:37 pm
by -m32
I suspect that your 'binary' isn't flat binary then. Are you doing this in Windows? It could be a PE file

try

objcopy -R .note -R .comment -S -O binary <input_file> <output_file>

eg:
objcopy -R .note -R .comment -S -O binary kernel.o kernel.bin

and then use grub to boot the output file from objcopy.

I was able to recreate your problem with a PE output file.

Posted: Tue Mar 25, 2008 5:25 pm
by -m32
Do this:

Code: Select all

[BITS 32]
global start           ; making entry point visible to linker
extern main             ; _main is defined elsewhere

; setting up the Multiboot header - see GRUB docs for details
MODULEALIGN equ  1<<0                   ; align loaded modules on page boundaries
MEMINFO     equ  1<<1                   ; provide memory map
AOUT        equ   1<<16                ;<-------------------------------------- NOTE
FLAGS       equ  MODULEALIGN | MEMINFO | AOUT  ; this is the Multiboot 'flag' field  <----------------------------------
MAGIC       equ    0x1BADB002           ; 'magic number' lets bootloader find the header
CHECKSUM    equ -(MAGIC + FLAGS)        ; checksum required

section .text

; reserve initial kernel stack space
STACKSIZE equ 0x4000          ; that's 16k.

start:
   mov esp, stack+STACKSIZE           ; set up the stack
   push eax                           ; pass Multiboot magic number
   push ebx                           ; pass Multiboot info structure

   call  main                        ; call kernel proper
               hlt                    ; halt machine should kernel return

align 4
MultiBootHeader:
   dd MAGIC
   dd FLAGS
   dd CHECKSUM

   ; AOUT KLUDGE
   extern code, bss, end

   dd MultiBootHeader
   dd code
   dd bss
   dd end
   dd start

section .bss
align 32
stack:
   resb STACKSIZE      ; reserve 16k stack on a quadword boundary
and at the top of your linkerscript add OUTPUT_FORMAT("binary"):

Code: Select all

OUTPUT_FORMAT("binary")

ENTRY(start)
SECTIONS
{
  .text 0x100000 :
  {
    code = .; _code = .; __code = .;
    *(.text)
    . = ALIGN(4096);
  }

  .data :
  {
     data = .; _data = .; __data = .;
     *(.data)
     *(.rodata)
     . = ALIGN(4096);
  }

  .bss :
  {
    bss = .; _bss = .; __bss = .;
    *(.bss)
    . = ALIGN(4096);
  }

  end = .; _end = .; __end = .;
} 
If the linker complains about converting a PE to binary, then, remove the 'OUTPUT_FORMAT' bit and use objcopy to convert the PE to binary 'manually'

Posted: Tue Mar 25, 2008 5:53 pm
by JJeronimo
Wave wrote:

Code: Select all

.string "Your String"
will be null-terminated, so don't worry.
Yeah. .string is one of the directives that implicitly add the C endstring.
But ELF is nicer to work with, since you don't need the A.OUT kludge.
Let me disagree with you. I think there's nothing special with declaring the entry point in the MB header. It's rather easy...........
Actually, I think it's a more proper way to format a kernel (just doesn't make sense having an executable that has 2 headers, each from it's standard). Also, it's rather stupid the idea of presenting a boot protocol aimed to facilitate the interoperability between kernels and boot loaders, and then say "here is the format. then, if you are a boot loader, you also have to learn ELF (an OS specific format)"...

Sorry if I'm telling garbage! It's rather possible that there are many arguments for the multiboot spec to preview that the boot loader supports ELF, but I don't see them...
You should use a separate section for the multiboot header to ensure it's placed first in the file.
Not needed. Because of that strange file format that MB proposes, it just needs to be in the first X KB (see the multiboot specs) of the exe image. there's a way to do this with the linker script:

Code: Select all

.text :
{
  start.o(.text)       /* Or something like that... */
  *(.text)                /* Don't accept this code as correct...*/
     /*it's not likely to be so, but get the idea and see the  */
}   /* LD documentation (yes, I agreee with the TR;DR */
     /*portion of your argument!) */
The first statement includes everything that the file "start.o" has to contribute for the .text section, and the second one includes the other .text sections (i'm really not sure whether this includes the crowd from start.o again)...

I do prefer reserving for the header it's it's own section, though...

JJ

Posted: Tue Mar 25, 2008 6:18 pm
by brickhead20
No I'm running linux.

I tried all of the above except objcopy, since the command isn't quite right. I'm toying, trying to get it right, it says "kernel.bin - File format not recognized"

The linker never complained though, so I guess its ok.

Posted: Tue Mar 25, 2008 7:12 pm
by -m32
Well, if the linker didn't complain about 'OUTPUT_FORMAT("binary")' then you won't need to use objcopy.

All you should have to do is:

nasm -f elf -o start.o start.asm
gcc -o kernel.o -c kernel.c -ffreestanding -fno-builtin
ld -Tlink.ld -o kernel.bin start.o kernel.o

That's all I did and it booted fine.

Posted: Wed Mar 26, 2008 2:25 pm
by brickhead20
That worked!

It turned out that using the elf flag in nasm did the trick. Before I had aout instead, and it didn't work.

Thanks m32, you've been really really helpful!

Now I'm interested as to why this is the case.

So why would it not work with the aout flag specified, but with the elf flag instead?

Posted: Thu Mar 27, 2008 1:20 am
by JamesM
So why would it not work with the aout flag specified, but with the elf flag instead?
Try disassembling the file - it's possible your readonly data is being put in a different section in the a.out object file and not being correctly mapped into the resulting binary executable. Using a fully expressive intermediate object file format (ELF/PE) is always recommended.
Actually, I think it's a more proper way to format a kernel (just doesn't make sense having an executable that has 2 headers, each from it's standard). Also, it's rather stupid the idea of presenting a boot protocol aimed to facilitate the interoperability between kernels and boot loaders, and then say "here is the format. then, if you are a boot loader, you also have to learn ELF (an OS specific format)"...

Sorry if I'm telling garbage! It's rather possible that there are many arguments for the multiboot spec to preview that the boot loader supports ELF, but I don't see them...
ELF is used by all UNIX operating system, so while it is specific, it's specific to an entire class/range of OS's. The advantage to a bootloader being able to understand the file format of a kernel is that it can load the extra, ancilliary sections into memory too. GRUB will load in your ELF symbol table for you, along with every other section you may need, including debug information. This is extremely useful, and much nicer than embedding the information directly in the executable (at a known location, for example).

One of the architectures I use has no support for ELF kernels, only SREC (a very similar format to raw binary). I ended up embedding my ELF kernel in the .data section of a 'third stage bootloader' SREC, parsing that embedded ELF and executing it, because that was the only way I could get all the ancilliary data I wanted.

Posted: Thu Mar 27, 2008 6:52 am
by -m32
Thanks m32, you've been really really helpful!
No problem. I'm glad it's finally working :)

Posted: Thu Mar 27, 2008 2:55 pm
by brickhead20
ELF does seem to be quite a bit cleaner to use. I'm going to try to use that instead.

If I start with one format, would it be relatively easy to switch to another? Presumably the file type can be to some extent abstracted quite early, so only a small amount of code would need to be changed (provided the system is sufficiently modular).

I've just GASed myself my own assembly file, to help me understand, but the a.out kludge just seems messy to me.

Clearly ELF can be "wrapped" to work on other systems then, so sufficiently flexible.

Will look into compiling to ELF file format, while writing my own linker script (ish), so I don't have to pinch yours (JamesM)! I just like to feel I understand it all enough to write it.

Thanks again

Posted: Thu Mar 27, 2008 3:14 pm
by brickhead20
Ooo, working with an elf file now I believe. And it takes less work?

Interesting.

Hopefully, C files will now work with no problems too. Rewriting from scratch.