简体   繁体   English

错误13:使用字符串文字在grub中启动简单内核时,可执行文件无效或不受支持

[英]Error 13: Invalid or unsupported executable while booting simple kernel in grub with string literal

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

Otherwise, if I define two characters I get the following (note 'ab' at the start of the output): 否则,如果我定义了两个字符,我得到以下内容(注意输出开头的'ab'):

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

The kernel is written in c 内核用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 IO ports called io.h and one for writing to the frame buffer called fb.h 一个用于称为io.h的IO端口,另一个用于写入称为fb.h的帧缓冲区

Here is io.h and the implementation io.s 这是io.h和实现io.s

io.h: 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: 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 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 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 linker script called link.ld and a Makefile. 我有一个名为link.ld的链接描述文件和一个Makefile。 I'm using gcc cross compiler for i386-elf That I compiled using this guide ( http://wiki.osdev.org/GCC_Cross-Compiler ). 我正在使用gcc交叉编译器为i386-elf我使用本指南编译( 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 这是我的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 makefile builds an iso from the contents of a directory called iso. makefile从名为iso的目录的内容构建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 该文件夹包含我在这里获得的预配置grub版本( https://github.com/littleosbook/littleosbook/blob/master/files/stage2_eltorito )和grub的menu.lst文件

menu.lst: menu.lst文件:

default=0
timeout=0

title os
kernel /boot/kernel.elf

contents of iso directory: iso目录的内容:

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

The iso image boots in bochs. iso图像在bochs中启动。 Here is my bochsrc.txt file 这是我的bochsrc.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

Does anyone know why the string literal in the kernel file produces the error when I try to boot the iso? 有没有人知道为什么当我尝试启动iso时,内核文件中的字符串文字会产生错误?

You have an extra colon at the end of section .text: so that creates a new section named .text: . section .text:末尾有一个额外的冒号,这样就创建了一个名为.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. 如果C代码中没有文字数据,那么幸运的是它仍然属于图像的前8kiB,因此多引导头位于所需部分。 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 . 如果你有一个字符串文字,你会得到一个新的.rodata部分,而且,由于另一个不明确的原因,它在.text:之前排序.text:但是在标准.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 it's no longer within the first 8kiB of the image, so grub will be very sad. 正如你所看到的那样,它不再位于图像的第一个8kiB内,所以grub会非常难过。

TL;DR: remove the extra colon after section .text: . TL; DR:删除section .text:后的额外冒号section .text: .

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在C函数调用中传递char字符串时,Bochs(2.4.6)/ GRUB(0.97)“错误13无效或不支持的可执行格式” - Bochs (2.4.6)/GRUB (0.97) “Error 13 Invalid or unsupported executable format” when passing char string in C function call 为什么此内核映像无法在QEMU上启动 - Why is this kernel image not booting on QEMU 错误:格式字符串不是字符串文字 - Error: format string is not a string literal 在不同的内核版本上加载驱动程序时出现“无效的模块格式”错误 - “Invalid module format” error getting while loading driver on different kernel version 使用设备树引导主线Linux内核 - Booting mainline Linux kernel using device tree 为简单的设备驱动程序编译内核模块时出错 - Error compiling kernel module for simple device driver 为什么我收到错误“kernel/drivers/screen.c:7:22: error: invalid initializer char* string[] = message;” - Why am i getting the error “kernel/drivers/screen.c:7:22: error: invalid initializer char* string[] = message;” 简单的while循环错误 - simple while loop error 当字符串文字以换行符\\ n结尾时,strdup对大小4的读取无效 - strdup invalid read of size 4 when string literal is ending with newline \n 为什么会出现“无效或不支持的图像格式”错误? - Why does the error 'invalid or unsupported image format' appear?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM