如何将汇编和C一起编译为bin格式

时间:2018-10-03 16:25:48

标签: c assembly x86-16 bootloader

我正在尝试从头开始制作自己的操作系统,并在制作自己的启动加载程序。我具有将字符串打印到屏幕上的功能。

这里有一些代码:

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 :(得分: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