[英]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]
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
#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
}
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;
}
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
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.