2015-02-25 31 views
5

Napisałem proste jądro, które próbuje napisać dwa znaki do bufora ramki.Błąd 13: Nieprawidłowy lub nieobsługiwany plik wykonywalny podczas rozruchu prostego jądra w GRUB-ie z literałem łańcuchowym

Gdybym określić ciąg dosłowne w jądrze, pojawia się następujący komunikat, gdy buty:

Booting 'os'                 

kernel /boot/kernel.elf               

Error 13: Invalid or unsupported executable format        

Press any key to continue... 

W przeciwnym razie, jeśli zdefiniować dwa znaki otrzymuję następujący (nota „ab” na początku wyjście):

abBooting 'os'                 

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

ładowarka

napisałem program ładujący w zespole:

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 

Jądro jest napisany w 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 
} 

nagłówki zewnętrzne

Istnieją dwa nagłówki zewnętrzne. Jeden z portów IO zwanych io.h i jeden na piśmie do bufora ramki o nazwie fb.h

Oto io.h i realizacja 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; 

} 

budowa To

Mam skrypt linkera nazwie link.ld i Makefile. Używam kompilatora krzyżowego gcc dla i386-elf, który skompilowałem przy użyciu tego przewodnika (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 = .; 


    } 
} 

I tu jest moje 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 [email protected] 

%.o: %.s 
    $(AS) $(ASFLAGS) $< -o [email protected] 

clean: 
    rm -rf *.o kernel.elf os.iso 

Run to

Makefile buduje ISO z zawartością katalogu o nazwie iso. Że folder zawiera wstępnie skonfigurowaną wersję grub, że mam tutaj (https://github.com/littleosbook/littleosbook/blob/master/files/stage2_eltorito) oraz plik menu.lst dla grub

menu.lst:

default=0 
timeout=0 

title os 
kernel /boot/kernel.elf 

zawartość katalogu ISO:

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

Buty obrazu iso w bochs. Oto mój bochsrc.plik txt

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 

Czy ktoś wie, dlaczego literał ciągu w pliku jądra powoduje błąd podczas próby uruchomienia systemu iso?

+0

Wow, naprawdę nie spodziewałem się, że ktoś miał dokładnie ten sam problem co ja – cstack

+0

Gdyby tak było ... dwukropek .text jest literówką w samym littleosbook. – cmlaverdiere

Odpowiedz

6

Masz dodatkowy dwukropek na końcu section .text:, więc tworzy nową sekcję o nazwie .text:. Z jakiegoś niejasnego powodu, którego nie mogłem się dowiedzieć z szybkiego spojrzenia na dokumentację, ta sekcja jest wysyłana do wyjścia, nawet jeśli nie jest wymieniona w twoim skryptu linkera. Kiedy nie masz żadnych danych literowych w kodzie C, masz szczęście, że nadal mieści się w granicach pierwszych 8kiB obrazu, tak że nagłówek wielu serwerów jest w wymaganej części. Jeśli masz literał łańcuchowy, otrzymasz nową sekcję .rodata i że, z jeszcze innego niejasnego powodu, zostanie posortowana przed twoim .text:, ale po standardzie .text. Przykład:

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 

Jak widać, nie ma już w nim pierwszych 8 billi obrazu, więc grub będzie bardzo smutny.

TL; DR: usuń dodatkowy dwukropek po section .text:.

+0

Dzięki! to naprawiło. Jak wytworzyłeś ten wynik? – albertlockett

+0

Używane 'objdump -h' – Jester

+0

Dlaczego dwukropek tworzy inną sekcję? – cstack