编写一个简单的引导加载程序HelloWorld
我尝试创建一个打印“hello world”的简单引导程序。
当我调用一个只打印“hello world”的函数时,我可以这样做,但是当我调用一个函数来打印特定的字符串时,什么也没有发生。
为此,我使用两个文件。 第一个是boot.ld,第二个是boot.cpp(它也可以在C中使用boot.c)。
首先,我从终端上创建软盘:
dd if = / dev / zero of = floppy.img bs = 512 count = 2880
其次,我编译代码(boot.cpp和boot.ld):
gcc -c -g -Os -m64 -wreestanding -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中:
dd if = boot.bin of = floppy.img
现在我们只需要从VirtualBox的存储面板添加软盘并启动我们的虚拟机。
源代码
来自: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' , %aln");
__asm__ __volatile__("movb $0x0e, %ahn");
__asm__ __volatile__("int $0x10n");
__asm__ __volatile__("movb $'e' , %aln");
__asm__ __volatile__("movb $0x0e, %ahn");
__asm__ __volatile__("int $0x10n");
__asm__ __volatile__("movb $'l' , %aln");
__asm__ __volatile__("movb $0x0e, %ahn");
__asm__ __volatile__("int $0x10n");
__asm__ __volatile__("movb $'l' , %aln");
__asm__ __volatile__("movb $0x0e, %ahn");
__asm__ __volatile__("int $0x10n");
__asm__ __volatile__("movb $'o' , %aln");
__asm__ __volatile__("movb $0x0e, %ahn");
__asm__ __volatile__("int $0x10n");
__asm__ __volatile__("movb $' ' , %aln");
__asm__ __volatile__("movb $0x0e, %ahn");
__asm__ __volatile__("int $0x10n");
__asm__ __volatile__("movb $'w' , %aln");
__asm__ __volatile__("movb $0x0e, %ahn");
__asm__ __volatile__("int $0x10n");
__asm__ __volatile__("movb $'o' , %aln");
__asm__ __volatile__("movb $0x0e, %ahn");
__asm__ __volatile__("int $0x10n");
__asm__ __volatile__("movb $'r' , %aln");
__asm__ __volatile__("movb $0x0e, %ahn");
__asm__ __volatile__("int $0x10n");
__asm__ __volatile__("movb $'l' , %aln");
__asm__ __volatile__("movb $0x0e, %ahn");
__asm__ __volatile__("int $0x10n");
__asm__ __volatile__("movb $'d' , %aln");
__asm__ __volatile__("movb $0x0e, %ahn");
__asm__ __volatile__("int $0x10n");
}
输出:
窃取的源代码
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;
}
}
输出:
为什么输出是空的?
我的功能有什么问题?
我忘记了什么?
谢谢你的帮助。
在我的交叉编译器( i686-elf-gcc (GCC) 4.9.2
)中,后面的代码产生以下(dis)程序集:
boot.o: file format elf32-i386
Disassembly 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位代码,请在全汇编中完成! 海湾合作委员会只会搞砸了,因为它生成的32位代码将运行在16位模式 。 如果你想直接进入C / C ++,那么你想写的可能不是引导程序,而是内核。 在这种(普通)的情况下,请阅读无可置疑的神圣仪式,以启动您进入OSDev。 你的第一个例子的运作只是运气,任何微小的变化都可能破坏一切,甚至导致神秘的可怕的三重错误,即内核恐慌本身的噩梦。
无论如何,最好直接写入VGA DMA内存,而不是使用BIOS调用(您需要首先进入保护模式,然后设置VGA硬件和模式(GRUB为您执行此操作,但您正在创建引导加载程序,aren你呢?)):
void PrintString(const char *str) {
uint16_t *vga = (uint16_t*)0xB8000;
for(; *str != ' '; str++, vga++)
*vga = ((uint16_t)0x07 << 8) | *str; // Light grey on a black background, nice!
}
顺便说一句 ,你可能会发现OSDev社区,wiki和论坛非常有用。 而且,如评论所示,您应该使用.code16
作为实模式代码,并且您的链接文章已经显示其年龄。
感谢@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, $mainn");
void cout(const char* str);
void main()
{
__asm__ __volatile__ ("xor %ax, %axn");
__asm__ __volatile__ ("mov %ax, %dsn");
cout("Hello World");
__asm__ __volatile__("clin");
__asm__ __volatile__("hltn");
}
void cout(const char* str)
{
while(*str)
{
__asm__ __volatile__("int $0x10" : : "a"(0x0e00 | *str), "b"(0x0007));
++str;
}
}
编译:
gcc -c -g -O0 -m32 -wreestanding -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
输出:
链接地址: http://www.djcxy.com/p/88127.html上一篇: Write a simple Bootloader HelloWorld
下一篇: Comparing SHA256 made with PHP hash() and NodeJS crypto.createHash()