从零实现一个操作系统-day1

目的

从这次春招中的碰壁和各种感悟,深刻体会到自己基础知识的不足,从零实现一个操作系统可以帮助自己更好得了解操作系统的知识。自己很早之前就开始有写一个微型操作系统的想法,之前也实践过,但弄了几天就放弃了,发现自己的毅力太差了,其实就是太懒了,写blog的目的也有敦促自己,不要懈怠。

资料

感谢前辈们无私提供的各种教程,这系列blog(希望是系列)跟着hurlex-doc教程来学习,当作自己的学习笔记和敦促自己努力不要偷懒


那就开始吧

环境配置

首先是环境的配置,我使用的系统是ubuntu 18.04,然后需要下载一个虚拟机qemu

1
2
3
sudo apt-get install qemu

sudo ln -s /usr/bin/qemu-system-i386 /usr/bin/qemu

脚本文件

教程中用到的各种脚本文件

Makefile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#!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

项目使用的链接器的脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/*
* 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,随着项目继续进行应该可以看懂吧(大概)
今天也很晚了,先到这吧

本文标题:从零实现一个操作系统-day1

文章作者:

发布时间:2020年04月16日 - 16:04

最后更新:2020年04月21日 - 01:04

原始链接:http://startcraft.cn/post/777e06ba.html

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

-------------The End-------------