Write a simple Bootloader HelloWorld
I try to create a simple bootloader which print "hello world".
I can do it when I call a function which only print "hello world", but when I call a function to print a specific string, nothing is happening.
For it, I use two files. The first one is boot.ld and the second is boot.cpp (it also work in C with boot.c).
Firstly, I create the floppy disk from my terminal:
dd if=/dev/zero of=floppy.img bs=512 count=2880
Secondly, I compile the code (boot.cpp and boot.ld):
gcc -c -g -Os -m64 -ffreestanding -Wall -Werror boot.cpp -o boot.o
ld -static -Tboot.ld -nostdlib --nmagic -o boot.elf boot.o
objcopy -O binary boot.elf boot.bin
Lastly, I add boot.bin into floppy.img:
dd if=boot.bin of=floppy.img
Now we just need to add the floppy from the storage panel of VirtualBox and launch our Virtual Machine.
The source code
from: 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 (or 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");
}
Output:
The bugged source code
boot.cpp (or 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;
}
}
Output:
Why the output is empty?
What is wrong in my function?
I have forget something?
Thanks for your help.
On my cross-compiler ( i686-elf-gcc (GCC) 4.9.2
), the later code produces the following (dis)assembly:
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
I'm very interested in whether you're using GCC (a non-16-bit-compatible compiler) with 16-bit stuff (BIOS interrupts). If you're going to do 16-bit code, do it in full assembly! GCC will simply mess it up, because it's generating 32-bit code that will be run on 16-bit mode . If you want to go directly to C/C++, then what you want to write is probably not a bootloader, but a kernel. In such a (common) case, read the unquestionable sacred ritual to initiate you into OSDev. The fact that your first example works is just luck, and any minimal change may break everything, even leading to the mythical horrifying triple fault, nightmares of kernel panics themselves.
Anyway, you're better off writing directly to VGA DMA memory than using BIOS calls (you need to get to protected mode first, and setup the VGA hardware and modes (GRUB does this for you, but you're creating a bootloader, aren't you?)):
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!
}
BTW , you may find the OSDev community, wiki, andforums very useful. And, as shown in the comments, you should be using .code16
for real mode code, and your linked article already shows its age.
Thanks to @MichaelPetch for this answer.
Source code:
boot.ld
ENTRY(main);
SECTIONS
{
. = 0x7C00;
.text : AT(0x7C00)
{
*(.text);
}
.sig : AT(0x7DFE)
{
SHORT(0xaa55);
}
}
boot.cpp
Also here: 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;
}
}
Compile:
gcc -c -g -O0 -m32 -ffreestanding -Wall -Werror boot.cpp -o boot.o
ld -melf_i386 -static -Tboot.ld -nostdlib --nmagic -o boot.elf boot.o
objcopy -O binary boot.elf boot.bin
dd if=boot.bin of=floppy.img conv=notrunc
Output:
链接地址: http://www.djcxy.com/p/88128.html上一篇: 你如何在sbt中撰写任务?