你可能需要google: kernel, ELF format, makefile
目标: 写一个简单的kernel,让bootsect启动它
The kernel
我们用C语言写的内核只能做一点点事,就是在屏幕左上角打印一个'X',打开这个kernel.c
。
你会发现第一个函数中什么都没写,这个函数创建了指向main
函数的内核入口。
添加-g的原因是在调试中需要用到这些信息,最后链接器链接kernel.o 与kernel_entry.o时会用到这些信息生成.elf,而这个.elf最终会用在gdb remote 到qemu中调试时用到。
i386-elf-gcc -g -ffreestanding -c kernel.c -o kernel.o
调用main
的程序是 kernel_entry.asm
。打开学习学习汇编中[extern]
声明的用法。编译这个文件的elf
格式生成kernel.o
,注意,这次的最终文件不是.bin
的机器码文件。
nasm kernel_entry.asm -f elf -o kernel_entry.o
The linker
链接器是非常有用的工具,我们刚才只使用到它一点点能力。
要链接两个.obj文件,并且解析标签,运行:
注意:这里的kernel_entry.o kernle.o两个文件的顺序不能颠倒,否则程序找不到入口!
i386-elf-ld -o kernel.bin -Ttext 0x1000 kernel_entry.o kernel.o --oformat binary
注意,内核代码可不是被放在内存的0x0
位置上,而是放在了0x1000
,(译注:进入保护模式后会跳转到这个地址执行内核代码,指定地址后,链接器会将所有跳转(段内)指令的目标地址加上0x1000
)。引导程序需要知道这个地址。这和lesson10中bootsect.asm
很像。
The bootsector
编译它:
nasm bootsect.asm -f bin -o bootsect.bin
Putting it all together
现在我们分别由两个文件,bootsecto
和 kernel
。
可以直接link
它们吗?哈哈,当然,把他们接在一起就可以:
cat bootsect.bin kernel.bin > os-image.bin
Run!
用qemu运行!
注意,如果你遇到硬盘载入错误之类的情况,可能需要调整硬盘的编号或者qemu的参数,我通常这么做:
qemu-system-i386 -fda os-image.bin
如果成功,会看到如下信息:
- "Started in 16-bit Real Mode"
- "Loading kernel into memory"
- (Top left) "Landed in 32-bit Protected Mode"
- (Top left, overwriting previous message) "X"
Congratulations!
THE ORIGIN ARTICALE IN GITHUB:[^1]
Concepts you may want to Google beforehand: kernel, ELF format, makefile
Goal: Create a simple kernel and a bootsector capable of booting it
The kernel
Our C kernel will just print an 'X' on the top left corner of the screen. Go ahead and open kernel.c
.
You will notice a dummy function that does nothing. That function will force us to create a kernel entry routine which does not point to byte 0x0 in our kernel, but to an actual label which we know that launches it. In our case, function main()
.
i386-elf-gcc -ffreestanding -c kernel.c -o kernel.o
That routine is coded on kernel_entry.asm
. Read it and you will learn how to use [extern]
declarations in assembly. To compile this file, instead of generating a binary, we will generate an elf
format file which will be linked with kernel.o
nasm kernel_entry.asm -f elf -o kernel_entry.o
The linker
A linker is a very powerful tool and we only started to benefit from it.
To link both object files into a single binary kernel and resolve label references, run:
i386-elf-ld -o kernel.bin -Ttext 0x1000 kernel_entry.o kernel.o --oformat binary
Notice how our kernel will be placed not at 0x0
in memory, but at 0x1000
. The bootsector will need to know this address too.
The bootsector
It is very similar to the one in lesson 10. Open bootsect.asm
and examine the code. Actually, if you remove all the lines used to print messages on the screen, it accounts to a couple dozen lines.
Compile it with nasm bootsect.asm -f bin -o bootsect.bin
Putting it all together
Now what? We have two separate files for the bootsector and the kernel?
Can't we just "link" them together into a single file? Yes, we can, and it's easy, just concatenate them:
cat bootsect.bin kernel.bin > os-image.bin
Run!
You can now run os-image.bin
with qemu.
Remember that if you find disk load errors you may need to play with the disk numbers or qemu parameters (floppy = 0x0
, hdd = 0x80
). I usually use qemu-system-i386 -fda os-image.bin
You will see four messages:
- "Started in 16-bit Real Mode"
- "Loading kernel into memory"
- (Top left) "Landed in 32-bit Protected Mode"
- (Top left, overwriting previous message) "X"
Congratulations!
Makefile
As a last step, we will tidy up the compilation process with a Makefile. Open the Makefile
script and examine its contents. If you don't know what a Makefile is, now is a good time to Google and learn it, as this will save us a lot of time in the future.
参考资料:
[1]:https://github.com/cfenollosa/os-tutorial/blob/master/12-kernel-c
版权注明:本文所有涉及到:https://github.com/cfenollosa/os-tutorial/
git仓库的内容,全部对应以下开源协议声明:
BSD 3-Clause License
Copyright (c) 2018,
Carlos Fenollosa