Напишите простой загрузчик HelloWorld — Функция ошибки печати строки

Я пытаюсь создать простой загрузчик, который печатает «привет мир».

Я могу сделать это, когда я вызываю функцию, которая печатает только «hello world», но когда я вызываю функцию для печати определенной строки, ничего не происходит.

Для этого я использую два файла. Первый — boot.ld, а второй — boot.cpp (он также работает в C с boot.c).

Сначала я создаю дискету из моего терминала:

дд если = / dev / zero of = floppy.img bs = 512 count = 2880

Во-вторых, я компилирую код (boot.cpp и boot.ld):

gcc -c -g -Os -m64 -ffreestanding -Wall -Werror boot.cpp -o boot.o

ld -static -Tboot.ld -nostdlib —nmagic -o boot.elf boot.o

objcopy -O бинарный boot.elf boot.bin

Наконец, я добавляю boot.bin в floppy.img:

дд если = boot.bin из = floppy.img

Теперь нам просто нужно добавить дискету с панели хранения VirtualBox и запустить нашу виртуальную машину.

FloppyImage

Исходный код

от: http://www.codeproject.com/Articles/664165/Writing-a-boot-loader-in-Assembly-and-C-Part

boot.ld

ENTRY(main);
SECTIONS
{
. = 0x7C00;
.text : AT(0x7C00)
{
*(.text);
}
.sig : AT(0x7DFE)
{
SHORT(0xaa55);
}
}

boot.cpp (или boot.c)

void cout();

void main()
{
cout();
}

void cout()
{
__asm__ __volatile__("movb $'h' , %al\n");
__asm__ __volatile__("movb $0x0e, %ah\n");
__asm__ __volatile__("int  $0x10\n");

__asm__ __volatile__("movb $'e' , %al\n");
__asm__ __volatile__("movb $0x0e, %ah\n");
__asm__ __volatile__("int  $0x10\n");

__asm__ __volatile__("movb $'l' , %al\n");
__asm__ __volatile__("movb $0x0e, %ah\n");
__asm__ __volatile__("int  $0x10\n");

__asm__ __volatile__("movb $'l' , %al\n");
__asm__ __volatile__("movb $0x0e, %ah\n");
__asm__ __volatile__("int  $0x10\n");

__asm__ __volatile__("movb $'o' , %al\n");
__asm__ __volatile__("movb $0x0e, %ah\n");
__asm__ __volatile__("int  $0x10\n");

__asm__ __volatile__("movb $' ' , %al\n");
__asm__ __volatile__("movb $0x0e, %ah\n");
__asm__ __volatile__("int  $0x10\n");

__asm__ __volatile__("movb $'w' , %al\n");
__asm__ __volatile__("movb $0x0e, %ah\n");
__asm__ __volatile__("int  $0x10\n");

__asm__ __volatile__("movb $'o' , %al\n");
__asm__ __volatile__("movb $0x0e, %ah\n");
__asm__ __volatile__("int  $0x10\n");

__asm__ __volatile__("movb $'r' , %al\n");
__asm__ __volatile__("movb $0x0e, %ah\n");
__asm__ __volatile__("int  $0x10\n");

__asm__ __volatile__("movb $'l' , %al\n");
__asm__ __volatile__("movb $0x0e, %ah\n");
__asm__ __volatile__("int  $0x10\n");

__asm__ __volatile__("movb $'d' , %al\n");
__asm__ __volatile__("movb $0x0e, %ah\n");
__asm__ __volatile__("int  $0x10\n");
}

Выход:

TestBootLoader1

Ошибка исходного кода

boot.cpp (или boot.c)

void cout(const char* str);

void main()
{
cout("hello world");
}

void cout(const char* str)
{
while(*str)
{
__asm__ __volatile__ ("int $0x10" : : "a"(0x0e00 | *str), "b"(0x0007));
++str;
}
}

Выход:

TestBootLoader2

Почему вывод пуст?

Что не так в моей функции?

Я что-то забыл?

Спасибо за вашу помощь.

7

Решение

На моем кросс-компиляторе (i686-elf-gcc (GCC) 4.9.2), более поздний код создает следующую (dis) сборку:

    boot.o:     file format elf32-i386Disassembly of section .text:

00000000 <cout>:
0:   55                      push   %ebp
1:   89 e5                   mov    %esp,%ebp
3:   53                      push   %ebx
4:   bb 07 00 00 00          mov    $0x7,%ebx
9:   8b 55 08                mov    0x8(%ebp),%edx
c:   0f be 02                movsbl (%edx),%eax
f:   84 c0                   test   %al,%al
11:   74 08                   je     1b <cout+0x1b>
13:   80 cc 0e                or     $0xe,%ah
16:   cd 10                   int    $0x10
18:   42                      inc    %edx
19:   eb f1                   jmp    c <cout+0xc>
1b:   5b                      pop    %ebx
1c:   5d                      pop    %ebp
1d:   c3                      ret

Меня очень интересует, используете ли вы GCC (несовместимый с 16 битами компилятор) с 16-битным содержимым (прерывания BIOS). Если вы собираетесь делать 16-битный код, делайте это в полной сборке! GCC просто испортит это, потому что он генерирует 32-битный код, который будет запущен в 16-битном режиме. Если вы хотите перейти непосредственно к C / C ++, то, скорее всего, вы хотите написать не загрузчик, а ядро. В таком (общем) случае читайте бесспорный священный ритуал посвящения вас в OSDev. Тот факт, что ваш первый пример работает, просто удача, и любое минимальное изменение может сломать все, даже приводя к мифическая ужасающая тройная ошибка, кошмары ядра паникуют сами.

В любом случае, вам лучше записывать данные непосредственно в память VGA DMA, чем использовать вызовы BIOS (вам нужно защищенный режим во-первых, и настроить оборудование и режимы VGA
(GRUB делает это для вас, но вы создаете загрузчик, не так ли?)):

void PrintString(const char *str) {
uint16_t *vga = (uint16_t*)0xB8000;

for(; *str != '\0'; str++, vga++)
*vga = ((uint16_t)0x07 << 8) | *str; // Light grey on a black background, nice!
}

КСТАТИ, вы можете найти сообщество OSDev, вики и форумы очень полезно. И, как показано в комментариях, вы должны использовать .code16 за реальный режим код, и ваша связанная статья уже показывает его возраст.

2

Другие решения

Благодаря @MichaelPetch за этот ответ.

Исходный код:

boot.ld

ENTRY(main);
SECTIONS
{
. = 0x7C00;
.text : AT(0x7C00)
{
*(.text);
}
.sig : AT(0x7DFE)
{
SHORT(0xaa55);
}
}

boot.cpp

Также здесь: http://pastebin.com/6NV3UMjE

asm(".code16gcc");
__asm__("jmpl $0x0000, $main\n");

void cout(const char* str);

void main()
{
__asm__ __volatile__ ("xor %ax, %ax\n");
__asm__ __volatile__ ("mov %ax, %ds\n");
cout("Hello World");
__asm__ __volatile__("cli\n");
__asm__ __volatile__("hlt\n");
}

void cout(const char* str)
{
while(*str)
{
__asm__ __volatile__("int $0x10" : : "a"(0x0e00 | *str), "b"(0x0007));
++str;
}
}

Обобщение:

gcc -c -g -O0 -m32 -ffreestanding -Wall -Werror boot.cpp -o boot.o

ld -melf_i386 -static -Tboot.ld -nostdlib —nmagic -o boot.elf boot.o

objcopy -O бинарный boot.elf boot.bin

dd if = boot.bin of = floppy.img conv = notrunc

Выход:

Выход

2

По вопросам рекламы [email protected]