Error 13: Invalid or unsupported executable file when loading a simple kernel in grub with a string literal

I wrote a simple kernel that tries to write two characters to the frame buffer.

If I define a string literal in the kernel, I get the following output when loading:

Booting 'os' kernel /boot/kernel.elf Error 13: Invalid or unsupported executable format Press any key to continue... 

Otherwise, if I define two characters, I get the following (note the β€œab” at the beginning of the output):

 abBooting 'os' kernel /boot/kernel.elf [Multiboot-elf, <0x100000:0x201:0x0>, <0x101000:0x0:0x1000>, shtab=0x102168, entry=0x1001f0] 

Loader

I wrote the bootloader in the assembly:

 global loader ; the entry symbol for ELF MAGIC_NUMBER equ 0x1BADB002 ; define the magic number constant FLAGS equ 0x0 ; multiboot flags CHECKSUM equ -MAGIC_NUMBER ; calculate the checksum ; (magic number + checksum + flags should equal 0) KERNEL_STACK_SIZE equ 4096 ; size of stack in bytes section .text: ; start of the text (code) section align 4 ; the code must be 4 byte aligned dd MAGIC_NUMBER ; write the magic number to the machine code, dd FLAGS ; the flags, dd CHECKSUM ; and the checksum loader: ; the loader label (defined as entry point in linker script) mov eax, 0xCAFEBABE ; place the number 0xCAFEBABE in the register eax mov esp, kernel_stack + KERNEL_STACK_SIZE ; point esp to the start of the ; stack (end of memory area) extern run call run .loop: jmp .loop ; loop forever section .bss align 4 ; align at 4 bytes kernel_stack: ; label points to beginning of memory resb KERNEL_STACK_SIZE ; reserve stack for the kernel 

The kernel is written in c

 #include "io.h" #include "fb.h" void run() { // try writing message to port char* c = (char *) 10000; c[0] = 'a'; c[1] = 'b'; fb_write(c, 2); // this does not cause the error // fb_write("ab",2); // this line would cause the error } 

External headers

There are two external headers. One for I / O ports, called io.h, and one for writing to a frame buffer, called fb.h

Here io.h and implementation io.s

io.h:

 #ifndef INCLUDE_IO_H #define INCLUDE_IO_H /** outb: * Sends the given data to the given I/O port. Defined in io.s * * @param port The I/O port to send the data to * @param data The data to send to the I/O port */ void outb(unsigned short port, unsigned char data); #endif /* INCLUDE_IO_H */ 

io.s:

 global outb ; make the label outb visible outside this file ; outb - send a byte to an I/O port ; stack: [esp + 8] the data byte ; [esp + 4] the I/O port ; [esp ] return address outb: mov al, [esp + 8] mov dx, [esp + 4] out dx, al ret 

fb.h

 #include "io.h" // FRAME BUFFER ================================ // Text colors #define FB_BLACK 0 #define FB_BLUE 1 #define FB_GREEN 2 #define FB_CYAN 3 #define FB_RED 4 #define FB_MAGENTA 5 #define FB_BROWN 6 #define FB_LT_GREY 7 #define FB_DARK_GREY 8 #define FB_LT_BLUE 9 #define FB_LT_GREEN 10 #define FB_LT_CYAN 11 #define FB_LT_RED 12 #define FB_LT_MAGENTA 13 #define FB_LT_BROWN 14 #define FB_WHITE 15 // IO PORTS #define FB_COMMAND_PORT 0x3D4 #define FB_DATA_PORT 0x3D5 // IO PORT COMMANDS #define FB_HIGH_BYTE_COMMAND 14 // move cursor command low #define FB_LOW_BYTE_COMMAND 15 // move cursor command high /** fb_write_cell: * used to write a character to a cell in the framebuffer * * param i which cell to write to * param c the ascii char to write * param fg foreground color * param bf background color */ void fb_write_cell(unsigned int i, char c, unsigned char fg, unsigned char bg); /** fb_move_cursor: * used to move the cursor within the frame buffer * * param pos position within frame buffer to move cursor to */ void fb_move_cursor(unsigned short pos); /** fb_write: * write some text to the cursor * * param buf pointer to character string * param len length of string to write */ int fb_write(char *buf, unsigned int len); 

fb.c

 #include "fb.h" void fb_write_cell(unsigned int i, char c, unsigned char fg, unsigned char bg) { char *fb = (char *) 0x000B8000; fb[i*2] = c; fb[i*2 + 1] = ((fg & 0x0F) << 4) | (bg & 0x0F); } void fb_move_cursor(unsigned short pos) { outb(FB_COMMAND_PORT, FB_HIGH_BYTE_COMMAND); outb(FB_DATA_PORT, ((pos>>8) & 0x00FF)); outb(FB_COMMAND_PORT, FB_LOW_BYTE_COMMAND); outb(FB_DATA_PORT, pos & 0x00FF); } int fb_write(char *buf, unsigned int len) { unsigned int i = 0; for(i = 0; i < len; i++) { fb_write_cell(i, buf[i], FB_BLACK, FB_WHITE); } return 0; } 

Building it

I have a script builder called link.ld and Makefile. I am using gcc cross compiler for i386-elf. I compiled this guide ( http://wiki.osdev.org/GCC_Cross-Compiler ).

 ENTRY(loader) /* the name of the entry label */ SECTIONS { . = 0x00100000; /* the code should be loaded at 1 MB */ .text ALIGN (0x1000) : /* align at 4 KB */ { *(.text) /* all text sections from all files */ } .rodata ALIGN (0x1000) : /* align at 4 KB */ { *(.rodata*) /* all read-only data sections from all files */ } .data ALIGN (0x1000) : /* align at 4 KB */ { *(.data) /* all data sections from all files */ } .bss ALIGN (0x1000) : /* align at 4 KB */ { sbss = .; *(COMMON) /* all COMMON sections from all files */ *(.bss) /* all bss sections from all files */ ebss = .; } } 

And here is my makefile

 OBJECTS = io.o fb.o loader.o kmain.o #CC = gcc CC = /home/albertlockett/opt/cross/bin/i386-elf-gcc CFLAGS = -m32 -nostdlib -nostdinc -fno-builtin -fno-stack-protector \ -nostartfiles -nodefaultlibs -Wall -Wextra -Werror -c LDFLAGS = -T link.ld -melf_i386 AS = nasm ASFLAGS = -f elf all: kernel.elf kernel.elf: $(OBJECTS) ld $(LDFLAGS) $(OBJECTS) -o kernel.elf os.iso: kernel.elf cp kernel.elf iso/boot/kernel.elf genisoimage -R \ -b boot/grub/stage2_eltorito \ -no-emul-boot \ -boot-load-size 4 \ -A os \ -input-charset utf8 \ -quiet \ -boot-info-table \ -o os.iso \ iso run: os.iso bochs -f bochsrc.txt -q %.o: %.c $(CC) $(CFLAGS) $< -o $@ %.o: %.s $(AS) $(ASFLAGS) $< -o $@ clean: rm -rf *.o kernel.elf os.iso 

Run it

The make file creates from the contents of the iso directory. This folder contains the pre-configured version of grub I got here ( https://github.com/littleosbook/littleosbook/blob/master/files/stage2_eltorito ) and the menu.lst file for grub

menu.lst:

 default=0 timeout=0 title os kernel /boot/kernel.elf 

iso directory contents:

 iso `-- boot |-- grub | |-- menu.lst | `-- stage2_eltorito `-- kernel.elf 

The iso image is uploaded to bochs. Here is my bochsrc.txt file

 megs: 32 display_library: term romimage: file=/usr/share/bochs/BIOS-bochs-latest vgaromimage: file=/usr/share/bochs/VGABIOS-lgpl-latest ata0-master: type=cdrom, path=os.iso, status=inserted boot: cdrom log: bochslog.txt clock: sync=realtime, time0=local cpu: count=1, ips=1000000 com1: enabled=1, mode=file, dev=com1.out 

Does anyone know why the string literal in the kernel file causes an error when trying to load iso?

+5
source share
1 answer

You have an extra colon at the end of section .text: to create a new section named .text: For some unknown reason, which I could not find out from a quick review of the documentation, this section is issued even if it is not specified in your script builder. When you don’t have the alphabetic data in the C code, you are lucky that it still falls into the first 8kiB of the image, so the multitasking header is in the required part. If you have a string literal, you will get a new .rodata section and that for another unclear reason is sorted before your .text: but after the standard .text . Example:

 Sections: Idx Name Size VMA LMA File off Algn 0 .text 00000001 00100000 00100000 00001000 2**4 CONTENTS, ALLOC, LOAD, READONLY, CODE 1 .rodata 00000005 00101000 00101000 00002000 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 2 .text: 00000018 00101008 00101008 00002008 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 3 .bss 0000100a 00102000 00102000 00003000 2**2 ALLOC 

As you can see, this is no longer in the first 8kiB image, so grub will be very sad.

TL DR: remove the extra colon after section .text:

+6
source

Source: https://habr.com/ru/post/1214126/


All Articles