Grub error 13

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
curt22
Posts: 3
Joined: Sun Jun 22, 2008 6:52 pm

Grub error 13

Post by curt22 »

Hi everyone, I'm following this tutorial http://www.cs.vu.nl/~herbertb/misc/writingkernels.txt but I keep getting:
kernel (fd0)/boot/grub/kernel.bin

Error 13: Invalid or unsupported executable format

press any key to continue...
I'm using this:
nasm -f elf -o start.o start.asm
gcc -fno-stack-protector -fno-builtin -nostdinc -O -g -Wall -I. -c -o main.o main.c
gcc -fno-stack-protector -fno-builtin -nostdinc -O -g -Wall -I. -c -o scrn.o scrn.c
ld -T link.ld -o kernel.bin start.o main.o scrn.o
to compile it.
I've searched on google, but I'm still not sure what's wrong.
Could someone please help me.
This is my code:

Code: Select all

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; start.asm
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 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.
[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_HEADER_MAGIC	equ 0x1BADB002
    MULTIBOOT_HEADER_FLAGS	equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO
    MULTIBOOT_CHECKSUM	equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)

    ; This is the GRUB Multiboot header. A boot signature
    dd MULTIBOOT_HEADER_MAGIC
    dd MULTIBOOT_HEADER_FLAGS
    dd MULTIBOOT_CHECKSUM
    
; A call to main (the C kernel) followed by an infinite loop (jmp $)
stublet:
 	EXTERN cmain 		; start of our kernel
 	call cmain
	jmp $

; 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

// File: main.c
#include <system.h>

/* some convenient functions - as we don't ahve libc, we must do
   everything ourselves */

unsigned char *memcpy(unsigned char *dest, const unsigned char *src, int count)
{
  int i;
  for (i=0; i<count;i++) dest[i]=src[i];
  return dest;
}

unsigned char *memset(unsigned char *dest, unsigned char val, int count)
{
  int i;
  for (i=0; i<count;i++) dest[i]=val;
  return dest;
}

unsigned short *memsetw(unsigned short *dest, unsigned short val, int count)
{
  int i;
  for (i=0; i<count;i++) dest[i]=val;
  return dest;
}

int strlen(const char *str)
{
  int i;
  for (i=0;;i++) if (str[i] == '\0') return i;
}

/* We can use this for reading from the I/O ports to get data from
*  devices such as the keyboard. We are using what is called 'inline
*  assembly' in these routines to actually do the work. [XXX I still
*  have to add devices to the tutorial] */
unsigned char inportb (unsigned short _port)
{
    unsigned char rv;
    __asm__ __volatile__ ("inb %1, %0" : "=a" (rv) : "dN" (_port));
    return rv;
}

/* We can use this to write to I/O ports to send bytes to
*  devices. Again, we use some inline assembly for the stuff that
*  simply cannot be done in C */
void outportb (unsigned short _port, unsigned char _data)
{
    __asm__ __volatile__ ("outb %1, %0" : : "dN" (_port), "a" (_data));
}

/* This is a very simple main() function. All it does is print stuff
*  and then sit in an infinite loop. This will be like our 'idle'
*  loop */
void
cmain (unsigned long magic, unsigned long addr)
{

  init_video();
  puts ((unsigned char*)"hello world!");

    /* ...and leave this loop in. Note: there is an endless loop in
    *  'start.asm' also, if you accidentally delete this next line */
    for (;;);
}
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////

Code: Select all

// File: scrn.c - putting characters on the screen (see comments below)

#include <system.h>

/* These define our textpointer, our background and foreground
*  colors (attributes), and x and y cursor coordinates */
unsigned short *textmemptr;
int attrib = 0x0F;
int csr_x = 0, csr_y = 0;

#define COLS 80
#define ROWS 24

/* Scrolls the screen */
void scroll(void)
{
    unsigned blank, temp;

    /* A blank is defined as a space... we need to give it
    *  backcolor too */
    blank = 0x20 | (attrib << 8);

    /* Row 25 is the end, this means we need to scroll up */
    if(csr_y >= ROWS/*25*/)
    {
        /* Move the current text chunk that makes up the screen
        *  back in the buffer by a line */
        temp = csr_y - ROWS/*25*/ + 1;
        memcpy ((unsigned char *)textmemptr, 
		(const unsigned char *)textmemptr + temp * COLS, 
		(ROWS/*25*/ - temp) * COLS * 2);

        /* Finally, we set the chunk of memory that occupies
        *  the last line of text to our 'blank' character */
        memsetw (textmemptr + (ROWS/*25*/ - temp) * COLS, blank, COLS);
        csr_y = ROWS/*25*/ - 1;
    }
}

/* Updates the hardware cursor: the little blinking line
*  on the screen under the last character pressed! */
void move_csr(void)
{
    unsigned temp;

    /* The equation for finding the index in a linear
    *  chunk of memory can be represented by:
    *  Index = [(y * width) + x] */
    temp = csr_y * COLS + csr_x;

    /* This sends a command to indicies 14 and 15 in the
    *  CRT Control Register of the VGA controller. These
    *  are the high and low bytes of the index that show
    *  where the hardware cursor is to be 'blinking'. To
    *  learn more, you should look up some VGA specific
    *  programming documents. A great start to graphics:
    *  http://www.brackeen.com/home/vga */
    outportb(0x3D4, 14);
    outportb(0x3D5, temp >> 8);
    outportb(0x3D4, 15);
    outportb(0x3D5, temp);
}

/* Clears the screen */
void cls()
{
    unsigned blank;
    int i;

    /* Again, we need the 'short' that will be used to
    *  represent a space with color */
    blank = 0x20 | (attrib << 8);

    /* Sets the entire screen to spaces in our current
    *  color */
    for(i = 0; i < ROWS/*25*/; i++)
        memsetw (textmemptr + i * COLS, blank, COLS);

    /* Update out virtual cursor, and then move the
    *  hardware cursor */
    csr_x = 0;
    csr_y = 0;
    move_csr();
}

/* Puts a single character on the screen */
void putch(unsigned char c)
{
    unsigned short *where;
    unsigned att = attrib << 8;

    /* Handle a backspace, by moving the cursor back one space */
    if(c == 0x08)
    {
        if(csr_x != 0) csr_x--;
    }
    /* Handles a tab by incrementing the cursor's x, but only
    *  to a point that will make it divisible by 8 */
    else if(c == 0x09)
    {
        csr_x = (csr_x + 8) & ~(8 - 1);
    }
    /* Handles a 'Carriage Return', which simply brings the
    *  cursor back to the margin */
    else if(c == '\r')
    {
        csr_x = 0;
    }
    /* We handle our newlines the way DOS and the BIOS do: we
    *  treat it as if a 'CR' was also there, so we bring the
    *  cursor to the margin and we increment the 'y' value */
    else if(c == '\n')
    {
        csr_x = 0;
        csr_y++;
    }
    /* Any character greater than and including a space, is a
    *  printable character. The equation for finding the index
    *  in a linear chunk of memory can be represented by:
    *  Index = [(y * width) + x] */
    else if(c >= ' ')
    {
        where = textmemptr + (csr_y * COLS + csr_x);
        *where = c | att;	/* Character AND attributes: color */
        csr_x++;
    }

    /* If the cursor has reached the edge of the screen's width, we
    *  insert a new line in there */
    if(csr_x >= COLS)
    {
        csr_x = 0;
        csr_y++;
    }

    /* Scroll the screen if needed, and finally move the cursor */
    scroll();
    move_csr();
}

/* Uses the above routine to output a string... */
void puts(unsigned char *text)
{
    int i;

    for (i = 0; i < strlen((const char*)text); i++)
    {
        putch(text[i]);
    }
}

/* Sets the forecolor and backcolor that we will use */
void settextcolor(unsigned char forecolor, unsigned char backcolor)
{
    /* Top 4 bytes are the background, bottom 4 bytes
    *  are the foreground color */
  attrib = (backcolor << 4) | (forecolor & 0x0F);
}

/* Sets our text-mode VGA pointer, then clears the screen for us */
void init_video(void)
{
    textmemptr = (unsigned short *)0xB8000;
    cls();
}
//////////////////////////////////////////////////////////////////////

Code: Select all

// File: system.h

#ifndef __SYSTEM_H
#define __SYSTEM_H

/* MAIN.C */
extern unsigned char *memcpy(unsigned char *dest, const unsigned char *src, int count);
extern unsigned char *memset(unsigned char *dest, unsigned char val, int count);
extern unsigned short *memsetw(unsigned short *dest, unsigned short val, int count);
extern int strlen(const char *str);
extern unsigned char inportb (unsigned short _port);
extern void outportb (unsigned short _port, unsigned char _data);

/* SCRN.C */
extern  void cls();
extern void putch(unsigned char c);
extern void puts(unsigned char *str);
extern void settextcolor(unsigned char forecolor, unsigned char backcolor);
extern void init_video();
#endif
User avatar
devel
Member
Member
Posts: 62
Joined: Wed Nov 28, 2007 4:15 am
Contact:

Re: Grub error 13

Post by devel »

hi,
how does your linker script (link.ld) look like? Did you use that one from mentioned URL?
User avatar
Omega
Member
Member
Posts: 250
Joined: Sun May 25, 2008 2:04 am
Location: United States
Contact:

Re: Grub error 13

Post by Omega »

VST_0201 wrote:If you want to load or jump on a Windows OS real quick you can do the following (or Translate these steps to be suitable in Linux OS) steps below.
1. Try assembling your loader as a COFF image. (nasm -f coff -o start.asm start.o)
2. Replace your loader with this one

Code: Select all

[BITS 32]
global start
start:
    mov esp, _sys_stack     ; This points the stack to our new stack area
    jmp stublet

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
    
; A call to main (the C kernel) followed by an infinite loop (jmp $)
stublet:
 	EXTERN _main 		; start of our kernel
 	call _main
	jmp $

SECTION .bss
    resb 8192               ; This reserves 8KBytes of memory here
_sys_stack:
Create a batch file and place it in the grub folder and type:

Code: Select all

@echo off
copy /b stage1 + stage2 a.img
pause
3. Use RawWrite to write the (a.img) file to a floppy disk.
4. Do as you were with GCC and with LD
5. Make sure your link.ld file is correct (post it as requested)
6. Write your kernel to another floppy like so:

Code: Select all

copy kernel.bin a:\kernel.bin
7. Load (DISK 01: GRUB Image) in MS Virtual PC or BOCHS
8. Once you see the prompt swap disks (i.e., Disk 01 for Disk 02)
9. At the prompt type: kernel /kernel.bin (hit enter)
10. Type: boot (hit enter)

Have fun! Happy coding. Hope this helps.
Free energy is indeed evil for it absorbs the light.
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Re: Grub error 13

Post by pcmattman »

curt22 wrote:I'm using this:
nasm -f elf -o start.o start.asm
gcc -fno-stack-protector -fno-builtin -nostdinc -O -g -Wall -I. -c -o main.o main.c
gcc -fno-stack-protector -fno-builtin -nostdinc -O -g -Wall -I. -c -o scrn.o scrn.c
ld -T link.ld -o kernel.bin start.o main.o scrn.o
Is "gcc" a cross-compiler? It's generally a better idea to use a cross-compiler rather than the default system compiler. It should still work though.

It would help if you showed us your link.ld, and also tell us what system you're running under (specifically whether this is Cygwin under Windows or a Linux distro). I also suggest doing an objdump on your kernel.bin file and making sure it's what you think it is.

EDIT: Re-reading your post after Combuster's reply, I realise it's probably highly likely you are on Windows. If you could tell us what environment you're working with that would help. Follow Combuster's advice and you should be set ;)
Last edited by pcmattman on Mon Jun 23, 2008 1:18 am, edited 1 time in total.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Grub error 13

Post by Combuster »

What I see is that you use elf for the assembly code, and the system default for the C code (which is different on mingw, cygwin and djgpp). In all these cases you should really create a GCC Cross-Compiler to avoid the discrepancies between all the formats.

if you're on linux, you'll have an utility called mbcheck - run that on your output binary and tell us what it says.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
Omega
Member
Member
Posts: 250
Joined: Sun May 25, 2008 2:04 am
Location: United States
Contact:

Re: Grub error 13

Post by Omega »

If he IS on Windows then what is wrong with what I said? My post was meant for Windows. :roll:
Free energy is indeed evil for it absorbs the light.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Grub error 13

Post by Combuster »

That you're telling him to use a different file format altogether - one that is badly supported, badly documented, and basically is a hack that is not proven to work under all conditions.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
Omega
Member
Member
Posts: 250
Joined: Sun May 25, 2008 2:04 am
Location: United States
Contact:

Re: Grub error 13

Post by Omega »

Respectively, why is it a hack? Also, in Windows I couldn't assemble using ELF, so if he is on Windows he will probably need to use COFF instead. In which situations does it not work exactly? I am new to GRUB, so I am seriously asking.
Free energy is indeed evil for it absorbs the light.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Grub error 13

Post by Combuster »

you are telling him to generate a PE or LZ exe with the AOUT kludge.

PE is a sectioned with headers. Grub doesn't know PE so it has to treat it as a flat binary. However, PE isn't flat internally. It has alignment constraints, padding between sections, non-code sections in between. To have the aout kludge work the binary must have code, data and bss directly following one another, with the same padding conditions as alignment set in the linker script. The offsets must be consecutive, and any insertion of other info that's perfectly valid for PE exe's will ruin everything.

In other words, the output may not be as flat as you might want it to be.

other than that, DJGPP is dated and will cause you no end of trouble when you hit the limits of DOS. MinGW is broken and horribly dependent on windows. Cygwin's better but still includes windows stuff. The crosscompiler solves all those problems: no host-specific issues that get you down, no DOS limits, and you get a unix environment for free :)
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
Omega
Member
Member
Posts: 250
Joined: Sun May 25, 2008 2:04 am
Location: United States
Contact:

Re: Grub error 13

Post by Omega »

Nice. That's pretty awesome! Thanks
Free energy is indeed evil for it absorbs the light.
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Re: Grub error 13

Post by pcmattman »

vst_0201 wrote:Respectively, why is it a hack? Also, in Windows I couldn't assemble using ELF, so if he is on Windows he will probably need to use COFF instead. In which situations does it not work exactly? I am new to GRUB, so I am seriously asking.
It's a hack because it's getting around a specific error message by modifying the script to work a specific way that results in the wanted behaviour (GRUB working) but in a different way.

And Combuster is right - ELF is much easier to work with and is far better documented. Also, if you couldn't assemble using ELF then something else is wrong with your own setup.

OP: Cross-compiler's the way to go.
curt22
Posts: 3
Joined: Sun Jun 22, 2008 6:52 pm

Re: Grub error 13

Post by curt22 »

:shock: I didn't think I would get that many replies so fast.
Here is a copy of link.ld

Code: Select all

ENTRY(start)
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 = .;
}
I did follow the steps here [wiki]http://wiki.osdev.org/GCC_Cross-Compiler#What_is_a_cross-compiler.3F[/wiki] to create a cross compiler, and I have tried compiling the kernel with both the system compiler and the cross compiler, but it doesn't change anything.

Also I am using linux not windows to compile the kernel.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Grub error 13

Post by Combuster »

curt22 wrote:I did follow the steps here [wiki]http://wiki.osdev.org/GCC_Cross-Compiler#What_is_a_cross-compiler.3F[/wiki] to create a cross compiler, and I have tried compiling the kernel with both the system compiler and the cross compiler, but it doesn't change anything.

Also I am using linux not windows to compile the kernel.
Good thing linux's not as susceptible to broken compilers as windows is. :wink:

Still, there's the mbcheck utility that comes with grub - run it on your output binary to see what it thinks about it. The output of objdump is also helpful to diagnose placement issues.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
curt22
Posts: 3
Joined: Sun Jun 22, 2008 6:52 pm

Re: Grub error 13

Post by curt22 »

Thanks everyone I got it working. I deleted it and rebuilt it with the cross compiler using:

Code: Select all

nasm  -f elf -o start.o start.asm
i586-elf-gcc -fno-stack-protector -fno-builtin -nostdinc -O -g -Wall -I. -c -o main.o main.c
i586-elf-gcc  -fno-stack-protector -fno-builtin -nostdinc -O -g -Wall -I. -c -o scrn.o scrn.c
ld -T link.ld -o kernel.bin start.o main.o scrn.o
I must have done something wrong the first time I built it. :oops: :oops: :oops:
Post Reply