我的博客: startcraft.cn
目的
從這次春招中的碰壁和各種感悟,深刻體會到自己基礎知識的不足,從零實現一個操作系統可以幫助自己更好得了解操作系統的知識。自己很早之前就開始有寫一個微型操作系統的想法,之前也實踐過,但弄了幾天就放棄了,發現自己的毅力太差了,其實就是太懶了,寫blog的目的也有敦促自己,不要懈怠。
資料
感謝前輩們無私提供的各種教程,這系列blog(希望是系列)跟着hurlex-doc教程來學習,當作自己的學習筆記和敦促自己努力不要偷懶
那就開始吧
環境配置
首先是環境的配置,我使用的系統是ubuntu 18.04,然後需要下載一個虛擬機qemu
sudo apt-get install qemu
sudo ln -s /usr/bin/qemu-system-i386 /usr/bin/qemu
腳本文件
教程中用到的各種腳本文件
Makefile
#!Makefile
C_SOURCES = $(shell find . -name "*.c")
C_OBJECTS = $(patsubst %.c, %.o, $(C_SOURCES))
S_SOURCES = $(shell find . -name "*.s")
S_OBJECTS = $(patsubst %.s, %.o, $(S_SOURCES))
CC = gcc
LD = ld
ASM = nasm
C_FLAGS = -c -Wall -m32 -ggdb -gstabs+ -nostdinc -fno-builtin -fno-stack-protector -I include
LD_FLAGS = -T scripts/kernel.ld -m elf_i386 --nostdlib
ASM_FLAGS = -f elf -g -F stabs
all: $(S_OBJECTS) $(C_OBJECTS) link update_image
.c.o:
@echo 編譯代碼文件 $< ...
$(CC) $(C_FLAGS) $< -o $@
.s.o:
@echo 編譯彙編文件 $< ...
$(ASM) $(ASM_FLAGS) $<
link:
@echo 鏈接內核文件...
$(LD) $(LD_FLAGS) $(S_OBJECTS) $(C_OBJECTS) -o time_kernel
.PHONY:clean
clean:
$(RM) $(S_OBJECTS) $(C_OBJECTS) time_kernel
.PHONY:update_image
update_image:
sudo mount floppy.img /mnt/kernel
sudo cp time_kernel /mnt/kernel/time_kernel
sleep 1
sudo umount /mnt/kernel
.PHONY:mount_image
mount_image:
sudo mount floppy.img /mnt/kernel
.PHONY:umount_image
umount_image:
sudo umount /mnt/kernel
.PHONY:qemu
qemu:
qemu -fda floppy.img -boot a
.PHONY:bochs
bochs:
bochs -f tools/bochsrc.txt
.PHONY:debug
debug:
qemu -S -s -fda floppy.img -boot a &
sleep 1
cgdb -x tools/gdbinit
makefile文件是構建大型工程所必需的,我們來看看這個makefile文件幹了什麼
第1-4行定義了一些變量 這些變量是什麼 首先我們要知道編譯的過程
首先要把源文件編譯成中間代碼文件,在Windows下也就是 .obj 文件,UNIX下是 .o 文件,即 Object File,這個動作叫做編譯(compile)。然後再把大量的Object File合成執行文件,這個動作叫作鏈接(link)
C_SOURCES和S_SOURCES定義的是C和彙編的源文件,採用shell命令對所有以.c和.s的文件進行查找
C_OBJECTS和S_OBJECTS使用了patsubst將所有的.c和.s的文件名替換爲.o也就是目標文件
後面3行就是定義了一些工具的名稱gcc是c語言的編譯器,ld是鏈接器,nasm是彙編器
再後面三個變量就是編譯連接的一些選項
gcc
- -c 編譯和彙編但是不鏈接
- -Wall 編譯後顯示所有警告
- -m32 以32位模式編譯
- -ggdb 此選項將儘可能的生成gdb的能夠使用的調試信息
- -gstabs+ 此選項以stabs格式聲稱調試信息,並且包含僅供gdb使用的額外調試信息.
- -nostdinc 使編譯器不再系統缺省的頭文檔目錄裏面找頭文檔,一般和-I聯合使用,明確限定頭文檔的位置
- -fno-builtin 不承認不以__builtin_開頭的函數爲內建(built-in)函數
- -fno-stack-protector 禁用堆棧保護 不保護堆棧溢出
- -I include 指定頭文件的搜索目錄
ld
- -T scripts/kernel.ld 使用指定的鏈接腳本kernel.ld
- -m elf_i386 生成i386平臺下的elf格式的可執行文件
- -nostdlib 不連接c語言標準庫
標籤的功能
再往下是目標all,它後面的是這個makefile在缺省條件下的目標,即生成所有的c和彙編的目標文件(.o)
並且完成鏈接和更新鏡像
.c.o表示的是%.o:%.c 即對所有xx.o的目標文件它的依賴是xx.c .s.o同理
$<表示第一個依賴文件 $@表示目標文件
link標籤是將c的目標文件和彙編的目標文件鏈接在一起輸出爲time_kernel文件
update_image標籤顧名思義就是更新鏡像文件,qemu加載的就是操作系統的鏡像,更新過程是先掛載鏡像,然後用time_kernel覆蓋,然後卸載鏡像
clean標籤就是刪除所有生成的文件僅僅保留源代碼
剩下的標籤像 mount_image umount_image就是掛載和卸載鏡像 qemu就是啓動qemu虛擬機
bochs是另一個虛擬機可以忽略 debug就是以debug模式啓動qemu來調試程序
kernel.ld
項目使用的鏈接器的腳本
/*
* kernel.ld -- 針對 kernel 格式所寫的鏈接腳本
*/
ENTRY(start)
SECTIONS
{
/* 段起始位置 */
. = 0x100000;
.text :
{
*(.text)
. = ALIGN(4096);
}
.data :
{
*(.data)
*(.rodata)
. = ALIGN(4096);
}
.bss :
{
*(.bss)
. = ALIGN(4096);
}
.stab :
{
*(.stab)
. = ALIGN(4096);
}
.stabstr :
{
*(.stabstr)
. = ALIGN(4096);
}
/DISCARD/ : { *(.comment) *(.eh_frame) }
}
這個腳本暫時看不懂2333,隨着項目繼續進行應該可以看懂吧(大概)
今天也很晚了,先到這吧