В основном вам нужно запустить gcc
с -ffreestanding
(не связывать), а затем связать с помощью ld
с флагами -static
, -nostdlib
.
Создание загрузчика в Cне совсем хорошая идея.Я бы порекомендовал вам получить копию GRUB и поработать над ней.Вики OSDEV объяснил это невероятно хорошо.
Подводя итог, всякий раз, когда вы пытаетесь создать загрузчик в C, используйте его для его компиляции:
$ gcc -m16 -c -g -Os -march=i686 -ffreestanding -Wall -Werror -I. -o bootloader.o bootloader.c
$ ld -static -T linker.ld -nostdlib --nmagic -o bootloader.elf bootloader.o
$ objcopy -O binary bootloader.elf bootloader.bin
Во-вторых, вы можетене используй extern!Вы не установили стек, поэтому код на C, вероятно, выручит довольно быстро.Компилятор C не знает, в каком формате вы передаете ему параметры, потому что ваша функция не следует ни одному из обычных соглашений.Возможный сценарий компоновщика:
ENTRY(main);
SECTIONS
{
. = 0x7C00;
.text : AT(0x7C00)
{
_text = .;
*(.text);
_text_end = .;
}
.data :
{
_data = .;
*(.bss);
*(.bss*);
*(.data);
*(.rodata*);
*(COMMON)
_data_end = .;
}
.sig : AT(0x7DFE)
{
SHORT(0xaa55);
}
/DISCARD/ :
{
*(.note*);
*(.iplt*);
*(.igot*);
*(.rel*);
*(.comment);
}
}
Кроме того, GCC по умолчанию генерирует 32-битный код - вам нужно заставить его генерировать 16-битный код, используя __asm__(".code16gcc\n")
или, как предлагается в комментариях, передать -m16
параметр командной строки компилятора.
Вы можете переписать свою функцию на C (чтобы она жаловалась на любое соглашение о вызовах), например так:
void print(const unsigned char * s){
while(*s){
__asm__ __volatile__ ("int $0x10" : : "a"(0x0E00 | *s), "b"(7));
s++;
}
}
И, конечно же, сразу после .code16gcc
, вам нужно перейти непосредственно к началу загрузчика: __asm__ ("jmpl $0, $main\n");