错误13:同时用字符串启动简单内核的grub无效或不支持的可执行文件 [英] Error 13: Invalid or unsupported executable while booting simple kernel in grub with string literal

查看:542
本文介绍了错误13:同时用字符串启动简单内核的grub无效或不支持的可执行文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经写了尝试两个字符写入到帧缓冲简单的内核。

I've written 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 it boots:

  Booting 'os'                                                                  

kernel /boot/kernel.elf                                                         

Error 13: Invalid or unsupported executable format                              

Press any key to continue... 

否则,如果我定义了两个角色我得到以下(注意'AB'在输出的开始):

Otherwise, if I define two characters I get the following (note 'ab' at the start 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 loader in 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

内核是用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
}

外部标题

有两个外部头。一个名为io.h IO端口和一个用于写入名为fb.h

External headers

There are two external headers. One for IO ports called io.h and one for writing to the frame buffer called fb.h

下面是io.h和实现io.s

Here is io.h and the 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;

}

建立它

我有一个链接脚本称为link.ld和Makefile文件。我使用了i386精灵GCC交叉编译那我用这个指南( HTTP编译://wiki.osdev .ORG / GCC_Cross编译器)。

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 = .;


    }
}

和这里是我的makefile

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

运行它

Makefile将一个目录中称为异内容的ISO。该文件夹中包含的grub,我来到这里的preconfigured版本(的https:/ /github.com/littleosbook/littleosbook/blob/master/files/stage2_eltorito )和蛴螬一个menu.lst文件

Run it

The makefile builds an iso from the contents of a directory called iso. That folder contains a preconfigured version of grub that I got here (https://github.com/littleosbook/littleosbook/blob/master/files/stage2_eltorito) and a menu.lst file for grub

menu.lst文件:

menu.lst:

default=0
timeout=0

title os
kernel /boot/kernel.elf

ISO目录的内容:

contents of iso directory:

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

ISO映像靴Bochs的。这是我bochsrc.txt文件

The iso image boots in 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

有谁知道为什么字符串中的内核文件字面产生错误,当我尝试启动ISO?

Does anyone know why the string literal in the kernel file produces the error when I try to boot the iso?

推荐答案

您必须在 .text段的最后一个额外的冒号:,以便创建一个新的命名节的.text:。对于一些模糊的原因,我无法从在文档快速浏览发现,这部分排放到即使它是不是在你的链接脚本中所列的输出。当你在C code无文本数据,你是幸运的,它仍然图像的第一8kiB之内,从而使多重引导头在需要的部分。如果你有一个字符串,你会得到一个新的节 .RODATA ,并且对于另一个模糊的原因,之前被你的的.text分类但标准后的.text 。例如:

You have an extra colon at the end of section .text: so that creates a new section named .text:. For some obscure reason that I couldn't find out from a quick glance at the documentation, this section is emitted to the output even though it is not listed in your linker script. When you have no literal data in the C code, you are lucky that it still falls within the first 8kiB of the image, so that the multiboot header is in the required portion. If you do have a string literal, you will get a new section .rodata and that, for yet another obscure reason, gets 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

正如你可以看到它的不再是图像的第一8kiB之内,所以grub会很伤心的。

As you can see it's no longer within the first 8kiB of the image, so grub will be very sad.

TL; DR:删除 .text段后额外的冒号:

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

这篇关于错误13:同时用字符串启动简单内核的grub无效或不支持的可执行文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆