我正在尝试从头开始制作自己的操作系统,并在制作自己的启动加载程序。我具有将字符串打印到屏幕上的功能。
这里有一些代码:
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关键字,但是如何将其编译为二进制格式的文件?
答案 0 :(得分:4)
基本上,您必须使用gcc
运行-ffreestanding
(不要链接),然后使用带有标志ld
,-static
的{{1}}进行链接。 / p>
用C创建引导加载程序并不是一个好主意。我建议您获取GRUB的副本并在此之上工作。 OSDEV Wiki对此解释得非常好。
总而言之,每当尝试使用C创建bootloader时,请使用以下命令对其进行编译:
-nostdlib
第二件事,您不能使用extern!您没有设置堆栈,因此C代码可能会很快退出紧急状态。 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
此外,默认情况下,GCC会发出32位代码-您需要使用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);
}
}
强制其生成16位代码,或者如注释中所述,将__asm__(".code16gcc\n")
参数传递给编译器的命令行
您可以将函数重写为C(使其抱怨任何调用约定),如下所示:
-m16
当然,在void print(const unsigned char * s){
while(*s){
__asm__ __volatile__ ("int $0x10" : : "a"(0x0E00 | *s), "b"(7));
s++;
}
}
之后,您必须直接跳转到引导加载程序开始处:.code16gcc