Intereting Posts
Как преобразовать римские цифры в int при отказе от недопустимых чисел с помощью стандартного C? C-> C ++ Автоматически вводить указатель void в указатель типа в C ++ в #define в случае типа не указывается (C-стиль) Конвертируйте одно 32-битное число с плавающей запятой в два 16-разрядных uint-номера, а затем снова конвертируйте их обратно в 32-битный Анализ текста в Objective-C? Необработанный указатель превращается в нуль, проходящий от Rust до C Как вернуть 2D-массив функции в C? Regex для каталога и списка файлов в C цикл do-while для проверки ввода пользователей с использованием c Передайте имя поля struct для доступа внутри функции C Макросы: как сопоставить другой макрос с переменными аргументами? Получение 0 вместо нуля для двоичного дерева поиска Как рассчитать расстояние между координатами GPS на процессоре с плохой поддержкой с плавающей запятой? Почему нужно указывать строку при назначении указателя на 2D-массив? Есть ли способ разделить строку на несколько символов в C? OpenGL Black Screen и Gamma Correction после обновления для MacOs Mojave 10.14?

Ошибка 13: Неверный или неподдерживаемый исполняемый файл при загрузке простого ядра в grub со строковым литералом

Я написал простое kernel, которое пытается записать два символа в буфер кадров.

Если я определяю строковый литерал в ядре, я получаю следующий вывод при загрузке:

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

В противном случае, если я определяю два символа, я получаю следующее (обратите внимание на «ab» в начале вывода):

 abBooting 'os' kernel /boot/kernel.elf [Multiboot-elf, , , shtab=0x102168, entry=0x1001f0] 

погрузчик

Я написал загрузчик в сборке:

 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, и один для записи в буфер кадров, называемый fb.h

Здесь io.h и реализация 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) <>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. Я использую gcc cross compiler для 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 = .; } } 

И вот мой 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 

Запустить его

Файл make создает изо из содержимого каталога iso. Эта папка содержит предварительно сконфигурированную версию grub, которую я получил здесь ( https://github.com/littleosbook/littleosbook/blob/master/files/stage2_eltorito ) и файл menu.lst для grub

menu.lst:

 default=0 timeout=0 title os kernel /boot/kernel.elf по default=0 timeout=0 title os kernel /boot/kernel.elf - default=0 timeout=0 title os kernel /boot/kernel.elf 

содержимое каталога iso:

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

Изображение iso загружается в bochs. Вот мой файл 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 

Кто-нибудь знает, почему строковый литерал в файле ядра вызывает ошибку, когда я пытаюсь загрузить iso?

У вас есть дополнительный двоеточие в конце section .text: так что создается новый раздел с именем .text: По какой-то непонятной причине, которую я не мог быстро узнать из документации, этот раздел выдается на выход, даже если он не указан в вашем сценарии компоновщика. Когда у вас нет буквенных данных в коде C, вам повезло, что он все еще попадает в первый 8kiB изображения, так что заголовок многозадачности находится в требуемой части. Если у вас есть строковый литерал, вы получите новый раздел .rodata и, что еще одна непонятная причина, сортируется перед вашим .text: но после стандартного .text . Пример:

 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 будет очень грустно.

TL; DR: удалить дополнительный двоеточие после section .text: