Как скомпилировать сборку и C вместе в формате bin - PullRequest
0 голосов
/ 03 октября 2018

Я пытаюсь создать собственную операционную систему с нуля и создаю собственный загрузчик.У меня есть функция для печати строки на экране.

Вот некоторый код, который у меня есть:

ORG 0x7C00
BITS 16

mov si, msg
call Print

cli
hlt

Print:
  lodsb
  cmp al, 0
  je Done
  mov ah, 0Eh
  mov bh, 0
  int 10h
  jmp Print

Done:
  ret

msg db 'Hello World!', 0
times 510-($-$$) db 0
dw 0xAA55

Затем он компилируется с помощью следующей команды:

nasm -f bin bootloader.asm -o bootloader.bin

Вопрос в том, как мне получить доступ к функции печати в C?Я знаю, что должен использовать ключевое слово extern, но как мне скомпилировать его в файл двоичного формата?

1 Ответ

0 голосов
/ 03 октября 2018

В основном вам нужно запустить 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");

...