I'm coding a basic kernel in C and x86 ASM, and for some reason whenever my kernel grows above a certain size, GRUB says throws an Error 13: Invalid or unsupported executable format. I've been following this tutorial: http://www.osdever.net/bkerndev/index.php?the_id=90
I started getting this whenever I implemented puts() and called it. Whenever I call that function, I get the error 13, but if I don't it works fine. One thing I noticed right away is that when I call puts() the kernel grows to 13k and if I don't it's 8k. I tried to make the kernel bigger by adding huge variables and the like to the program, but the program sticks at 8k. So I tried the next thing. I copied the code from puts() and put it straight into my main() function after initializing the screen. Same problem. So then I thought that it might be the for loop. So I made a random for loop that didn't really do anything and iterated 20 times. The filesize stuck at 8k. It worked. So then I made a character array and made the for loop iterate through the character array. Now it grew to....13 kilobytes again. So, I thought that maybe it was too much data for main() to hold, so I took all of that out of main and just had main call init_screen(); and then enter an endless loop (like it was before). I put puts("Hello, world!"); into init_screen(); so it would not be called from main() if that was the problem. Nope, I still get an error 13.
Does anybody know what the problem might be? I'm using FAT16 for the filesystem and my kernel is just a plain binary that I linked with the LD script provided in the link above.
13k kernel doesn't work
- carbonBased
- Member
- Posts: 382
- Joined: Sat Nov 20, 2004 12:00 am
- Location: Wellesley, Ontario, Canada
- Contact:
Make sure that your multiboot header is at the very beginning of your kernel. It has to be withen a certain number of kb for it to be recognised (I don't recall this limit offhand).
Changes are, the header is near the end, and the more code you add, the farther away it gets.
You should edit your linker script to ensure its near the beginning and/or ensure its the first object on the linker command line.
--Jeff
Changes are, the header is near the end, and the more code you add, the farther away it gets.
You should edit your linker script to ensure its near the beginning and/or ensure its the first object on the linker command line.
--Jeff
Okay, I put start.o as the first thing on the list for ld and it still didn't fix it. Here's my start.asm code:
And my linker script:
To me, it looks like it does put it in the beginning, but I am not an expert on linker scripts or assembly language.
Code: Select all
; This is the kernel's entry point. We could either call main here,
; or we can use this to setup the stack or other nice stuff, like
; perhaps setting up the GDT and segments. Please note that interrupts
; are disabled at this point: More on interrupts later!
[BITS 32]
global start
start:
mov esp, _sys_stack ; This points the stack to our new stack area
jmp stublet
; This part MUST be 4byte aligned, so we solve that issue using 'ALIGN 4'
ALIGN 4
mboot:
; Multiboot macros to make a few lines later more readable
MULTIBOOT_PAGE_ALIGN equ 1<<0
MULTIBOOT_MEMORY_INFO equ 1<<1
MULTIBOOT_AOUT_KLUDGE equ 1<<16
MULTIBOOT_HEADER_MAGIC equ 0x1BADB002
MULTIBOOT_HEADER_FLAGS equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO | MULTIBOOT_AOUT_KLUDGE
MULTIBOOT_CHECKSUM equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
EXTERN code, bss, end
; This is the GRUB Multiboot header. A boot signature
dd MULTIBOOT_HEADER_MAGIC
dd MULTIBOOT_HEADER_FLAGS
dd MULTIBOOT_CHECKSUM
; AOUT kludge - must be physical addresses. Make a note of these:
; The linker script fills in the data for these ones!
dd mboot
dd code
dd bss
dd end
dd start
; This is an endless loop here. Make a note of this: Later on, we
; will insert an 'extern _main', followed by 'call _main', right
; before the 'jmp $'.
stublet:
extern main
call main
jmp $
; Shortly we will add code for loading the GDT right here!
; In just a few pages in this tutorial, we will add our Interrupt
; Service Routines (ISRs) right here!
; Here is the definition of our BSS section. Right now, we'll use
; it just to store the stack. Remember that a stack actually grows
; downwards, so we declare the size of the data before declaring
; the identifier '_sys_stack'
SECTION .bss
resb 8192 ; This reserves 8KBytes of memory here
_sys_stack:
Code: Select all
OUTPUT_FORMAT("binary")
ENTRY(start)
phys = 0x00100000;
SECTIONS
{
.text phys : AT(phys) {
code = .;
*(.text)
. = ALIGN(4096);
}
.data : AT(phys + (data - code))
{
data = .;
*(.data)
. = ALIGN(4096);
}
.bss : AT(phys + (bss - code))
{
bss = .;
*(.bss)
. = ALIGN(4096);
}
end = .;
}
I just tried upping the 8k on the resb at the bottom of start.asm to 16k and it doesn't change a thing
edit: I ran mbchk and it does say it can't find the multiboot header. I don't know how to fix this, the tutorial says nothing about this at all. You are right that it's at the end though, because I took two of my old builds and mbchk says that the really old one is found at offset 12 and the slightly newer one is offset 28
I opened up the kernel in hexedit and the bultiboot checksum is all the way back at 0x10000C/0x102000. How do I get this at the beginning of the file? The string: "Hello, world!" is all the way at 0x00
edit: I ran mbchk and it does say it can't find the multiboot header. I don't know how to fix this, the tutorial says nothing about this at all. You are right that it's at the end though, because I took two of my old builds and mbchk says that the really old one is found at offset 12 and the slightly newer one is offset 28
I opened up the kernel in hexedit and the bultiboot checksum is all the way back at 0x10000C/0x102000. How do I get this at the beginning of the file? The string: "Hello, world!" is all the way at 0x00
You didn't define a section for your asm-Code, so NASM put it into an extra section. (Something strange like "NASMDEFSEG001" or so). LD placed that section after .bss because you didn't mention it in your linker script. I guess a simple "section .text" after [BITS 32] should fix that.
Items marked with a * are required unless stated otherwise.
I added "section .text" in the line right under "[BITS 32]" in start.asm and when I hexedit'd my kernel, the multiboot header is STILL near the end of the binary.
I gzip'd all of the files in my kernel here: http://www.zshare.net/download/kernel-tgz.html
To build from a *nix environment, just type "./build.bash" from the command line. Otherwise, you can look in the script and see what commands I run to build my kernel. Be warned, I haven't gotten around to cleaning up and finishing the build script, so it's a wee bit messy yet. I intend on adding functions to it and such to clean it up.
edit: I switched over to ELF for my kernel, and now it works fine.
I gzip'd all of the files in my kernel here: http://www.zshare.net/download/kernel-tgz.html
To build from a *nix environment, just type "./build.bash" from the command line. Otherwise, you can look in the script and see what commands I run to build my kernel. Be warned, I haven't gotten around to cleaning up and finishing the build script, so it's a wee bit messy yet. I intend on adding functions to it and such to clean it up.
edit: I switched over to ELF for my kernel, and now it works fine.