这里的环境我参照的是《操作系统真象还原》。
C语言的编译器我用的是gcc
,但是如果使用MacOS自带的gcc
的话有一个问题。书上加载内核时是按照elf32
格式解析的,关于elf32
的文件格式可以去看这位大哥的文章。MacOS自带的gcc
编译器产生的是苹果电脑上的可执行文件格式(即Mach-O 64-bit executable x86_64
,我的机器是64位)。这时我们就需要一个交叉编译器。经过查阅资料,我得知了MacOS上的交叉编译器叫做i386-elf-gcc
,可以通过brew install i386-elf-gcc
安装,但是却出现了一条警告:
Warning: Use x86_64-elf-gcc instead of deprecated i386-elf-gcc
大意是说i386-elf-gcc
已被废弃,现在已被更新为x86_64-elf-gcc
。我们不管,继续安装。但是按照名字来看,这个x86_64-elf-gcc
貌似是编译出elf64
文件格式的,32位和64位在加载内核上还是有区别的。果然,编译出的文件格式为ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
。通过百度,我了解到可以通过-m32
来指定输出32位文件。撒花……等等!这个链接器又“罢工”了。这时我们的编译器应该使用x86_64-elf-ld
了,可是它为什么提示没有-m32
这个参数呢?于是我查阅了一下文档,原来需要使用-m elf_i386
参数才行。大功告成!
其实我个人还是更加喜欢使用C++
,只要安装了x86_64-elf-gcc
,那么就安装了x86_64-elf-g++
,使用这个编译就好啦。
这里的汇编编译器我们使用的是nasm
,只要通过brew install nasm
安装,编译时添加一个新的参数-f elf_i386
就行啦!
等我把加载内核的代码写完了后发现加载器却罢工了,不知道大家有没有遇到这个问题呢?别急,我们把内核的加载地址往后移0x1000
个字节,即0xc0002500
,然后再把代码中的和dd
命令中的扇区数从4
改成6
。当当当,能运行啦!因为书上默认的加载器的代码不会超过2.0KB
,但是可能是因为工具换了的原因,我编译出的代码居然有2.2KB
!这还能运行?所以赶紧把地址改了过来。
书中所写的检测完内存容量的地址是存储在0xb00
(第5章),但是我在这个地址读出的内容居然是0
!经过一遍一遍地审视代码,终于发现了作者计算地址时似乎少算了开头jmp loader_start
的3个字节,因此真正的地址应该为0xb03
!同样GDT的地址(第11章)也要往后移3
个字节!
Makefile就相当于是一个高级的“批处理文件”,书中的Makefile是到了第8章才开始讲的,不过我觉得,这个东西还是早用早受益,以下附上我编写的Makefile(我现在看到第11章):
ASM = nasm
GCC = x86_64-elf-gcc
G++ = x86_64-elf-g++
LD = x86_64-elf-ld
ASMFLAGS = -f elf32
CFLAGS = -m32 -c -fno-builtin
LDFLAGS = -m elf_i386 -Ttext 0xc0002500 -e main
OBJS = kernel/main.o kernel/console.o kernel/init.o kernel/interrupt.o kernel/memory.o kernel/sync.o kernel/thread.o kernel/tss.o kernel/kernel.o kernel/switch.o device/keyboard.o device/timer.o lib/string.o lib/kernel/bitmap.o lib/kernel/fifo.o lib/kernel/list.o lib/kernel/print.o
boot/mbr.bin: boot/mbr.S Makefile
$(ASM) -o boot/mbr.bin boot/mbr.S
boot/loader.bin: boot/loader.S Makefile
$(ASM) -o boot/loader.bin boot/loader.S
kernel/main.o: kernel/main.cpp Makefile
$(G++) $(CFLAGS) -o kernel/main.o kernel/main.cpp
kernel/console.o: kernel/console.cpp Makefile
$(G++) $(CFLAGS) -o kernel/console.o kernel/console.cpp
kernel/init.o: kernel/init.cpp Makefile
$(G++) $(CFLAGS) -o kernel/init.o kernel/init.cpp
kernel/interrupt.o: kernel/interrupt.cpp Makefile
$(G++) $(CFLAGS) -o kernel/interrupt.o kernel/interrupt.cpp
kernel/memory.o: kernel/memory.cpp Makefile
$(G++) $(CFLAGS) -o kernel/memory.o kernel/memory.cpp
kernel/sync.o: kernel/sync.cpp Makefile
$(G++) $(CFLAGS) -o kernel/sync.o kernel/sync.cpp
kernel/thread.o: kernel/thread.cpp Makefile
$(G++) $(CFLAGS) -o kernel/thread.o kernel/thread.cpp
kernel/tss.o: kernel/tss.cpp Makefile
$(G++) $(CFLAGS) -o kernel/tss.o kernel/tss.cpp
kernel/kernel.o: kernel/kernel.S Makefile
$(ASM) $(ASMFLAGS) -o kernel/kernel.o kernel/kernel.S
kernel/switch.o: kernel/switch.S Makefile
$(ASM) $(ASMFLAGS) -o kernel/switch.o kernel/switch.S
device/keyboard.o: device/keyboard.cpp Makefile
$(G++) $(CFLAGS) -o device/keyboard.o device/keyboard.cpp
device/timer.o: device/timer.cpp Makefile
$(G++) $(CFLAGS) -o device/timer.o device/timer.cpp
lib/string.o: lib/string.cpp Makefile
$(G++) $(CFLAGS) -o lib/string.o lib/string.cpp
lib/kernel/bitmap.o: lib/kernel/bitmap.cpp Makefile
$(G++) $(CFLAGS) -o lib/kernel/bitmap.o lib/kernel/bitmap.cpp
lib/kernel/fifo.o: lib/kernel/fifo.cpp Makefile
$(G++) $(CFLAGS) -o lib/kernel/fifo.o lib/kernel/fifo.cpp
lib/kernel/list.o: lib/kernel/list.cpp Makefile
$(G++) $(CFLAGS) -o lib/kernel/list.o lib/kernel/list.cpp
lib/kernel/print.o: lib/kernel/print.S Makefile
$(ASM) $(ASMFLAGS) -o lib/kernel/print.o lib/kernel/print.S
kernel/main.bin: $(OBJS) Makefile
$(LD) $(LDFLAGS) -o kernel/main.bin $(OBJS)
run: bochsrc.disk boot.img boot/mbr.bin boot/loader.bin kernel/main.bin Makefile
dd if=boot/mbr.bin of=boot.img bs=512 count=1 conv=notrunc
dd if=boot/loader.bin of=boot.img bs=512 count=7 seek=2 conv=notrunc
dd if=kernel/main.bin of=boot.img bs=512 count=200 seek=9 conv=notrunc
bochs -f bochsrc.disk
clean: Makefile
-rm boot/mbr.bin
-rm boot/loader.bin
-rm kernel/*.o
-rm device/*.o
-rm lib/*.o
-rm lib/kernel/*.o
-rm kernel/main.bin
好啦,看到这里各位的环境都已经搭建好了吧。这本书的错误挺多的, 大家要敢于质疑,希望能尽快看到大家开发的操作系统。最后,点个赞再走吧~