全面剖析《自己动手写操作系统》第五章---makefile文件

转载请标注: 

全面剖析《自己动手写操作系统》第五章---makefile文件  

http://blog.csdn.net/zgh1988/article/details/7338380

1、make概述

2、编译和链接

3、makefile规则

4、自己动手写makefile文件

5、后记

一、make概述

        作为程序员,我们都有使用过Visualstdio 2005、VC6.0、eclipse等经典开发工具,使用它们,我们可以方便地建立和管理自己的工程,往往直接点击两个按钮,就完成了编译,链接,运行等功能。但是我们有没有过这样的疑问?它是怎样做到的,它是怎样将不在一起的文件组合到一起的,我们自己能不能管理自己的工程呢。是的,在Linux环境下使用GNU的make工具就可以构建和管理自己的工程,而且还可以自己操作它们的编译、链接等。

        在了解make工具之前,我们需要知道makefile文件,该文件就是用来描述整个工程的编译、链接等规则,其中包括:工程中的哪些源文件需要编译以及如何编译、需要创建哪些库文件以及如何创建这些库文件、如何最后产生我们想要得到的可执行文件。我们的任务就是要掌握如何书写makefile文件。makefile文件有自己的书写格式、关键字、函数,而且可以使用系统shell所提供的任何命令(例如:nasm gcc等指令)。

        make是一个命令工具,它解释makefile文件中的指令。在书写好makefile文件之后,我们只需要在shell提示符下输入make命令,整个工程就会按照makefile文件中的内容完全自动编译,极大的提高了效率。

二、编译和链接

        传统意义上,在生成系统可执行文件之前,需要进行两步走战略:编译和链接。

        编译(compile):指用编译器(compiler)将源代码(sourcecode)生成二进制目标文件(object file),在Windows下也就是 .obj 文件,Linux下是 .o 文件。编译时,编译器需要检查高级语言的语法,函数与变量的声明是否正确。只有所有语法正确,函数与变量声明正确,编译器就可以编译出二进制目标文件。为了和最终生成的可执行目标文件区别,我们暂且称编译后的目标文件为.o文件。

        链接(link):找到所要用到函数所在的目标文件(.o文件),并把它们链接在一起合成为可执行文件(executable file),在Linux环境下,可执行文件的格式为“ELF”格式。链接时,要确保编译器能找到所有被用到了的函数所在的目标文件。链接过程中使用GNU的“ld”工具。

三、makefile规则

一个简单的makefile规则:

TARGET :PREREQUISITES

        COMMAND

从这个形式上来看,我们可以得到两层含义:

(1) 要想得到TARGET,需要执行命令COMMAND。

(2) TARGET依赖于PREREQUISITES,当PREREQUISITES中至少有一个文件比TARGET文件新时,COMMAND才被执行。

        TARGET :规则的目标。通常是最终可以在系统上运行的目标文件 或 实现这个目标文件所需要的中间过程文件。例如.o文件 或者 最后的可执行文件。另外,目标也可以是一个make执行的动作名称,如目标“clean”,不过我们称这样的目标为“伪目标”。

        PREREQUISITES : 规则的依赖。生成规则目标所需要的文件列表,通常一个目标文件依赖于一个或者多个文件。

        COMMAND : 规则的命令行。是规则所要执行的动作。

        (语法1)一个规则可以有多个命令行,每一条命令行占一行。注意:每一个命令行必须以【TAB】字符开始,【TAB】字符告诉make此行是一个命令行。

四、自己动手写makefile

1、一个简单的例子

目标:生成boot.bin和loader.bin文件

条件:boot.asm 包含 load.inc fat12hdr.inc

            loader.asm 包含 load.incfat12hdr.inc pm.inc

下面我们开始写makefile文件:

(1) 首先我们要写出生成boot.bin 的规则:

boot.bin : boot.asm load.inc fat12hdr.inc

         nasm–o boot.bin boot.asm

另外我们写出生成loader.bin的规则:

loader.bin : loader.asm load.incfat12hdr.inc pm.inc

         nasm–o loader.bin loader.asm

我们将这两条规则保存到makefile文件中,将makefile文件放在boot文件下。

此时,如果我们只输入命令行make,发现它只是执行了第一条规则,也就是只生成了boot.bin目标文件。(语法2)因为在默认情况下,make执行的是makefile中的第一个规则。如果想执行第二条规则,我们必须执行make loader.bin,才能够达到目的。

(2) 问题又来了,我们如何通过一条命令把两个规则都执行了呢?我在文件开始处,添加了这样的一条规则,作为该makefile的第一条规则。

everything : boot.bin loader.bin        

这个规则虽然命令行为空,也就是不做任何工作,但是makefile中有这样一条规则,(语法3)make在执行一条规则所定义的命令之前,首先需要处理的是目标文件的所有的依赖文件,在此规则中,也就是boot.bin 和 loader.bin。如果依赖文件不存在,则make会按照依赖文件列表从左到右的顺序依次寻找创建这些依赖文件的规则。

所以在本例中,在执行everything: boot.bin loader.bin这条规则之前,make发现其依赖文件boot.bin 和loader.bin文件不存在,就会去寻找创建这些依赖条件的规则,即规则2,和规则3,分别执行规则2,3,完成boot.bin loader.bin的创建。

(3) 此时我们在输入命令make,会发现一个错误:make:`everything' is up to date。这是为什么呢?难道我们写的规则出现问题了吗?

        我们写的makefile文件是正确的,下面我来告诉你makefile的另一条规则(语法4)在执行一条规则中,如果目标文件不存在,则执行该规则以创建目标文件;如果目标文件存在,其依赖文件中有一个或者多个文件比它“更新”—也就是说依赖文件中有一个或者多个文件在目标文件生成之后,进行了修改,则根据规则重新创建目标文件;如果目标文件存在,它比它的任何一个依赖文件都要“更新”—也就是说在生成目标文件之后,所有的依赖文件都没有发生修改,则什么都不做。

        所以此时执行make命令会发生错误。因为之前我们已经生成了boot.bin 和 loader.bin文件,而且其依赖文件列表没有更新。

        此时怎么办呢?让我们在写一条规则放在最后一行:

clean :

         rm–f boot.bin loader.bin

它不存在依赖条件,它是一条伪规则,命令行的作用是删除文件boot.bin loader.bin。我们通常使用rm指令,来删除一些中间生成文件(例如.o文件)。

(4) 最终的makefile文件如下:

everything : boot.bin loader.bin     

boot.bin : boot.asm load.inc fat12hdr.inc

         nasm-o boot.bin boot.asm

loader.bin : loader.asm load.incfat12hdr.inc pm.inc

         nasm-o loader.bin loader.asm

clean:      

         rm-f boot.bin loader.bin

 

现在我们就可以先执行一个make clean,将目标文件boot.bin loader.bin删除,然后再执行make命令。执行结果如下:


这样我们就完成了我们第一个最简单的例子。

下面让我们来回忆上面所提到的4条规则:

(语法1)一个规则可以有多个命令行,每一条命令行占一行。注意:每一个命令行必须以[TAB]字符开始,【TAB】字符告诉make此行是一个命令行。

(语法2)因为在默认情况下,make执行的是makefile中的第一个规则。

(语法3)make在执行一条规则所定义的命令之前,首先需要处理的是目标文件的所有的依赖文件,如果依赖文件不存在,则make会按照依赖文件列表从左到右的顺序依次寻找创建这些依赖文件的规则。

(语法4)在执行一条规则中,如果目标文件不存在,则执行该规则以创建目标文件;如果目标文件存在,其依赖文件中有一个或者多个文件比它“更新”—也就是说依赖文件中有一个或者多个文件在目标文件生成之后,进行了修改,则根据规则重新创建目标文件;如果目标文件存在,它比它的任何一个依赖文件都要“更新”—也就是说在生成目标文件之后,所有的依赖文件都没有发生修改,则什么都不做。

2、又是一个简单的问题


        此时,为了让整个工程规范,我将头文件load.inc fat12hdr.inc pm.inc放在包含在include下的文件夹里面。此时的makefile文件还是在boot文件夹目录下,此时的makefile该怎么写呢?如果我们不加修改的话,运行make指令肯定会出问题。原因是无法找到依赖文件列表中的load.inc fat12hdr.inc pm.inc文件,因为它们的路径不在/boot下,而是搬到了boot/include下。所以修改makefile文件如下:

everything : boot.bin loader.bin     

boot.bin : boot.asm include/load.incinclude/fat12hdr.inc

         nasm-I include -o boot.bin boot.asm

loader.bin : loader.asm include/load.incinclude/fat12hdr.inc include/pm.inc

         nasm-I include -o loader.bin loader.asm

clean:      

         rm-f boot.bin loader.bin

 

我们相当于添加了一个路径来帮助make自己寻找这些头文件。在nasm指令中,-I 指的就是路径。

下面是运行结果:

3、为makefile添加变量

        这时候,你有没有想过,如果我的工程不断的扩大,到时候我这样一点点的写是不是很麻烦,还会出好多问题。

        其实我还有一点没有告诉你呢,在makefile中,是可以添加变量的。所以我们就要将一些内容赋值给变量,在以后的道路上,我们就可以修改变量了。

        在此问题上,我就要添加变量来简化makefile文件,使其更加清晰明了。

# Makefile for boot

# Programs, flags,etc.

ASM              = nasm

ASMFLAGS = -I include

# This Program

TARGET    =  boot.bin loader.bin

# All Phony Targets

.PHONY : everything clean all

# Default starting position

everything :      $(TARGET)

clean :

         rm -f $(TARGET)

all :   clean everything

 

boot.bin : boot.asminclude/load.inc include/fat12hdr.inc

         $(ASM)  $(ASMFLAGS) -o $@ $<

loader.bin :loader.asm include/load.inc include/fat12hdr.inc include/pm.inc

         $(ASM)  $(ASMFLAGS) -o $@ $<

 

        首先,我们看到的是两个命令行变量,ASM = nasm  ASMFLAGS = -Iinclude

        在今后我们使用到nasm 和–I include 时,我们就只需要用$(ASM), $(ASMFLAGS)来代替,$这个符号的含义,就是取值操作。

        其次是TARGET = boot.bin loader.bin,我们定义了一个目标变量,它的值保护boot.bin和loader.bin。所以在

everything :$(TARGET)  相当于everything : boot.bin loader.bin。

        然后你注意到了我们将everything clean all定义为了.PHONY,我们知道everything clean all只是动作,它是伪规则,所以我们用.PHONY来定义它们。

        最后是两个规则,一个是生成boot.bin,一个是loader.bin。

$(ASM) $(ASMFLAGS) –o $@ $< 相当于:

nasm -I include -o loader.bin loader.asm

S@ = loader.bin  $< = loader.asm

        这时候我们发现,我们的第二个规则有点长,所以我们需要将其变短一些。(语法5)这时候我们需要使用反斜线(\)将一个较长的行分成多行,这样我们的makefile书写清晰、容易阅读理解。但需要注意:反斜线之后不能有空格(这也是大家最容易犯的错误,错误比较隐蔽)

loader.bin : loader.asm include/load.incinclude/fat12hdr.inc \

                    include/pm.inc

         $(ASM)$(ASMFLAGS) -o $@ $<

4、一个复杂的问题


这是本章中最后生成的操作系统的工程目录表,通过它我们来熟悉书写makefile的步骤:
(1) 我们应该找到目标文件和依赖文件之间的关系

boot/boot.asm : boot/boot.asm boot/include/load.inc boot/include/fat12hdr.inc
boot/loader.asm : boot/loader.asm boot/include/load.inc boot/include/fat12hdr.inc \
boot/include/pm.inc
kernel/kernel.o : kernel/kernel.asm
kernel/start.o : kernel/start.c  include/type.h  include/const.h  include/protect.h \
			include/proto.h  include/string.h  include/global.h
kernel/i8259.o : kernel/i8259.c include/type.h include/const.h include/protect.h \
			include/proto.h
kernel/global.o : kernel/global.c include/type.h include/const.h include/protect.h \
			include/proto.h include/global.h
kernel/protect.o : kernel/protect.c include/type.h include/const.h include/protect.h \
			include/global.h
lib/klib.o : lib/klib.asm
lib/string.o : lib/string.asm
lib/klibc.o : lib/klib.c include/type.h include/const.h include/protect.h include/string.h \
		include/proto.h include/global.h
kernel.bin : kernel/kernel.o kernel/start.o kernel/i8259.o kernel/global.o kernel/protect.o \
lib/klib.o lib/string.o lib/klibc.o

(2) 根据上面的目标文件,我们需要定义目标变量,此时不要求完整,随着思考一步步的去完善。

TINIXBOOT       = boot/boot.bin boot/loader.bin

TINIXKERNEL  = kernel.bin

OBJS                 = kernel/kernel.o kernel/start.okernel/i8259.o kernel/global.o kernel/protect.o lib/klib.o lib/string.olib/klibc.o

DASMOUTPUT= kernel.bin.asm

(3) 我们可以需要取定义一些命令变量,此时不要求完整,随着思考一步步的去完善。

ASM          =nasm

DASM       =ndisasm

CC             =gcc

LD              =ld

ASMBFLAGS     =-I boot/include

ASMKFLAGS     =-I include -f elf

ASMKLFLAGS   =-f elf

CFLAGS              =-I include -c -fno-builtin

LDFLAGS           =-s -Ttext $(ENTRYPOINT)

DASMFLAGS     =-u -o $(ENTRYPOINT) -e $(ENTRYOFFSET)

(4) 然后我们开始尝试组织这些变量,生成各种规则。

boot/boot.bin : boot/boot.asm boot/include/load.inc boot/include/fat12hdr.inc
	$(ASM) $(ASMBFLAGS) -o $@ $<

boot/loader.bin : boot/loader.asm boot/include/load.inc boot/include/fat12hdr.inc \
		boot/include/pm.inc
	$(ASM) $(ASMBFLAGS) -o $@ $<

$(TINIXKERNEL) : $(OBJS)
	$(LD) $(LDFLAGS) -o $(TINIXKERNEL) $(OBJS)

kernel/kernel.o : kernel/kernel.asm
	$(ASM) $(ASMKFLAGS) -o $@ $<

kernel/start.o : kernel/start.c include/type.h include/const.h include/protect.h \
		include/string.h include/proto.h
	$(CC) $(CFLAGS) -o $@ $<

kernel/i8259.o : kernel/i8259.c include/type.h include/const.h include/protect.h \
		include/proto.h
	$(CC) $(CFLAGS) -o $@ $<

kernel/global.o : kernel/global.c include/type.h include/const.h include/protect.h \
		include/proto.h include/global.h
	$(CC) $(CFLAGS) -o $@ $<

kernel/protect.o : kernel/protect.c include/type.h include/const.h include/protect.h \
		include/global.h
	$(CC) $(CFLAGS) -o $@ $<

lib/klib.o : lib/klib.asm
	$(ASM) $(ASMKLFLAGS) -o $@ $<

lib/string.o : lib/string.asm
	$(ASM) $(ASMKLFLAGS) -o $@ $<

lib/klibc.o : lib/klib.c include/type.h include/const.h include/protect.h include/string.h \
		include/proto.h include/global.h
	$(CC) $(CFLAGS) -o $@ $<

(5) 最后需要完成一些不同的伪规则,也就是行为,将其中的某些行为进行组合。

# All Phony Targets
.PHONY : everything final image cleanrealclean disasm all buildimg 
# Default starting position
everything : $(TINIXBOOT) $(TINIXKERNEL)
all : realclean everything

final : all clean

image : final buildimg

clean :
         rm -f $(OBJS)
realclean:
         rm -f $(OBJS)  $(TINIXBOOT)  $(TINIXKERNEL)
disasm :
         $(DASM) $(DASMFLAGS)  $(TINIXKERNEL) > $(DASMOUTPUT)

# Write "boot.bin" &"loader.bin" into floppy image "TINIX.IMG"
# We assume that "TINIX.IMG"exists in current folder
buildimg:
         mount Tinix.vfd  /mnt/floppy -o loop
         cp -f  boot/loader.bin  /mnt/floppy
         cp -f kernel.bin  /mnt/floppy
         umount /mnt/floppy

make+不同的伪规则形成不同的结果:

make everything:
nasm -I boot/include -o boot/boot.binboot/boot.asm
nasm -I boot/include -o boot/loader.binboot/loader.asm
nasm -I include -f elf -o kernel/kernel.o kernel/kernel.asm
gcc -I include -c -fno-builtin -okernel/start.o kernel/start.c
nasm -f elf -o lib/klib.o lib/klib.asm
nasm -f elf -o lib/string.o lib/string.asm
ld -s -Ttext 0x30400 -o kernel.binkernel/kernel.o kernel/start.o lib/klib.o lib/string.o

make clean:
rm -f kernel/kernel.o kernel/start.o lib/klib.o lib/string.o
 
make realclean:
rm -f kernel/kernel.o kernel/start.o lib/klib.o lib/string.o boot/boot.bin boot/loader.bin kernel.bin
 
make buildimg:
mount Tinix.vfd /mnt/floppy -o loop
cp -f boot/loader.bin /mnt/floppy
cp -f kernel.bin /mnt/floppy
umount /mnt/floppy
 
make all:
make realclean
make everything
 
make final:
make all (make realclean make everything)
make clean
 
make image:
make final (make all(make realclean makeeverything))
make buildimg

(6) 最后的结果如下:

# Makefile for TINIX

# Entry Point of Tinix
# It must be as same as 'KernelEntryPointPhyAddr' in load.inc!!!
ENTRYPOINT	= 0x30400

# Offset of entry point in kernel file
# It depends on ENTRYPOINT
ENTRYOFFSET	= 0x400

# Programs, flags, etc.
ASM		= nasm
DASM		= ndisasm
CC		= gcc
LD		= ld
ASMBFLAGS	= -I boot/include
ASMKFLAGS	= -I include -f elf
ASMKLFLAGS	= -f elf
CFLAGS		= -I include -c -fno-builtin
LDFLAGS		= -s -Ttext $(ENTRYPOINT)
DASMFLAGS	= -u -o $(ENTRYPOINT) -e $(ENTRYOFFSET)

# This Program
TINIXBOOT	= boot/boot.bin boot/loader.bin
TINIXKERNEL	= kernel.bin
OBJS		= kernel/kernel.o kernel/start.o kernel/i8259.o kernel/global.o kernel/protect.o lib/klib.o lib/string.o lib/klibc.o
DASMOUTPUT	= kernel.bin.asm

# All Phony Targets
.PHONY : everything final image clean realclean disasm all buildimg

# Default starting position
everything : $(TINIXBOOT) $(TINIXKERNEL)

all : realclean everything

final : all clean

image : final buildimg

clean : 
	rm -f $(OBJS)

realclean:
	rm -f $(OBJS) $(TINIXBOOT) $(TINIXKERNEL)

disasm :
	$(DASM) $(DASMFLAGS) $(TINIXKERNEL) > $(DASMOUTPUT)

# Write "boot.bin" & "loader.bin" into floppy image "TINIX.IMG"
# We assume that "TINIX.IMG" exists in current folder
buildimg:
	mount Tinix.vfd /mnt/floppy -o loop
	cp -f boot/loader.bin /mnt/floppy
	cp -f kernel.bin /mnt/floppy
	umount /mnt/floppy

boot/boot.bin : boot/boot.asm boot/include/load.inc boot/include/fat12hdr.inc
	$(ASM) $(ASMBFLAGS) -o $@ $<

boot/loader.bin : boot/loader.asm boot/include/load.inc boot/include/fat12hdr.inc \
		boot/include/pm.inc
	$(ASM) $(ASMBFLAGS) -o $@ $<

$(TINIXKERNEL) : $(OBJS)
	$(LD) $(LDFLAGS) -o $(TINIXKERNEL) $(OBJS)

kernel/kernel.o : kernel/kernel.asm
	$(ASM) $(ASMKFLAGS) -o $@ $<

kernel/start.o : kernel/start.c include/type.h include/const.h include/protect.h \
		include/string.h include/proto.h
	$(CC) $(CFLAGS) -o $@ $<

kernel/i8259.o : kernel/i8259.c include/type.h include/const.h include/protect.h \
		include/proto.h
	$(CC) $(CFLAGS) -o $@ $<

kernel/global.o : kernel/global.c include/type.h include/const.h include/protect.h \
		include/proto.h include/global.h
	$(CC) $(CFLAGS) -o $@ $<

kernel/protect.o : kernel/protect.c include/type.h include/const.h include/protect.h \
		include/global.h
	$(CC) $(CFLAGS) -o $@ $<

lib/klib.o : lib/klib.asm
	$(ASM) $(ASMKLFLAGS) -o $@ $<

lib/string.o : lib/string.asm
	$(ASM) $(ASMKLFLAGS) -o $@ $<

lib/klibc.o : lib/klib.c include/type.h include/const.h include/protect.h include/string.h \
		include/proto.h include/global.h
	$(CC) $(CFLAGS) -o $@ $<

五、后记

本着够用原则,只学习了这么一点关于makefile的知识,希望在以后的时间里,能够对makefile进行深入研究。


全面剖析《自己动手写操作系统》第五章---加载内核kernel.bin http://blog.csdn.net/zgh1988/article/details/7329941

全面剖析《自己动手写操作系统》第五章---Red Hat 9.0 的安装过程  http://blog.csdn.net/zgh1988/article/details/7315676

全面剖析《自己动手写操作系统》第四章---FAT12文件系统 http://blog.csdn.net/zgh1988/article/details/7284834

全面剖析《自己动手写操作系统》第四章---加载Loader.bin http://blog.csdn.net/zgh1988/article/details/7291909

全面剖析《自己动手写操作系统》第三章---进入保护模式   http://blog.csdn.net/zgh1988/article/details/7098981

全面剖析《自己动手写操作系统》第三章---“实模式--保护模式--实模式” http://blog.csdn.net/zgh1988/article/details/7255804

全面剖析《自己动手写操作系统》第三章---堆栈段的工作方式 http://blog.csdn.net/zgh1988/article/details/7256254

全面剖析《自己动手写操作系统》第三章---特权级以及不同特权级代码段之间的跳转 http://blog.csdn.net/zgh1988/article/details/7262901

全面剖析《自己动手写操作系统》第三章---分页机制 http://blog.csdn.net/zgh1988/article/details/7270748

全面剖析《自己动手写操作系统》第三章---中断机制 http://blog.csdn.net/zgh1988/article/details/7276259

全面剖析《自己动手写操作系统》第二章http://blog.csdn.net/zgh1988/article/details/7062065

全面剖析《自己动手写操作系统》第一章http://blog.csdn.net/zgh1988/article/details/7060032

《自己动手写操作系统》读后感http://blog.csdn.net/zgh1988/article/details/7059936


  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
本书在详细分析操作系统原理的基础上,用丰富的实例代码,一步一步地指导读者用C语言和汇编语言编出一个具备操作系统基本功能的操作系统框架。本书不同于其他的理论型书籍,而是提供给读者一个动手实践的路线图。书中讲解了大量在开发操作系统中需注意的细节问题,这些细节不仅能使读者更深刻地认识操作系统的核心原理,而且使整个开发过程少走弯路。全书共分7章。 本书适合各类程序员、程序开发爱好者阅读,也可作为高等院校操作系统课程的实践参考书。 折叠 作品目录 第1章 马上动手一个最小的"操作系统"1 1.1 准备工作1 1.2 10分钟完成的操作系统1 1.3 Boot Sector3 1.4 代码解释3 1.5 水面下的冰山5 1.6 回顾6 第2章 搭建你的工作环境7 2.1 虚拟计算机(Virtual PC)7 2.1.1 Virtual PC初体验8 2.1.2 创建你的第一个Virtual PC9 2.1.3 虚拟软盘研究12 2.1.4 虚拟软盘实战14 2.2 编译器(NASM & GCC)18 2.3 安装虚拟Linux19 2.4 在虚拟Linux上访问Windows文件夹26 2.5 安装虚拟PCDOS26 2.6 其他要素29 2.7 Bochs29 2.7.1 Bochs vs. Virtual PC vs. VMware30 2.7.2 Bochs的使用方法31 2.7.3 用Bochs进行调试33 2.7.4 在Linux上开发34 2.8 总结与回顾36 第3章 保护模式(Protect Mode)37 3.1 认识保护模式37 3.1.1 GDT(Global Descriptor Table) 42 3.1.2 实模式到保护模式,不一般的jmp45 3.1.3 描述符属性47 3.2 保护模式进阶50 3.2.1 海阔凭鱼跃50 3.2.2 LDT(Local Descriptor Table)58 3.2.3 特权级62 3.3 页式存储82 3.3.1 分页机制概述83 3.3.2 编代码启动分页机制84 3.3.3 PDE和PTE85 3.3.4 cr388 3.3.5 回头看代码88 3.3.6 克勤克俭用内存90 3.3.7 进一步体会分页机制100 3.4 中断和异常107 3.4.1 中断和异常机制109 3.4.2 外部中断111 3.4.3 编程操作8259A113 3.4.4 建立IDT116 3.4.5 实现一个中断117 3.4.6 时钟中断试验119 3.4.7 几点额外说明121 3.5 保护模式下的I/O122 3.5.1 IOPL122 3.5.2 I/O许可位图(I/O Permission Bitmap)123 3.6 保护模式小结123 第4章 让操作系统走进保护模式125 4.1 突破512字节的限制125 4.1.1 FAT12126 4.1.2 DOS可以识别的引导盘131 4.1.3 一个最简单的Loader132 4.1.4 加载Loader入内存133 4.1.5 向Loader交出控制权142 4.1.6 整理boot.asm142 4.2 保护模式下的"操作系统"144 第5章 内核雏形146 5.1 用NASM在Linux下Hello World146 5.2 再进一步,汇编和C同步使用148 5.3 ELF(Executable and Linkable Format)150 5.4 从Loader到内核155 5.4.1 用Loader加载ELF155 5.4.2 跳入保护模式161 5.4.3 重新放置内核170 5.4.4 向内核交出控制权175 5.4.5 操作系统的调试方法176 5.5 扩充内核184 5.5.1 切换堆栈和GDT184 5.5.2 整理我们的文件夹191 5.5.3 Makefile191 5.5.4 添加中断处理200 5.5.5 两点说明218 5.6 小结219 第6章 进程221 6.1 迟到的进程221 6.2 概述222 6.2.1 进程介绍222 6.2.2 未雨绸缪--形成进程的必要考虑222 6.2.3 参考的代码224 6.3 最简单的进程224 6.3.1 简单进程的关键技术预测225 6.3.2 第一步--ring0→ring1227 6.3.3 第二步--丰富中断处理程序243 6.3.4 进程体设计技巧254 6.4 多进程256 6.4.1 添加一个进程体256 6.4.2 相关的变量和宏257 6.4.3 进程表初始化代码扩充258 6.4.4 LDT260 6.4.5 修改中断处理程序261 6.4.6 添加一个任务的步骤总结263 6.4.7 号外:Minix的中断处理265 6.4.8 代码回顾与整理269 6.5 系统调用280 6.5.1 实现一个简单的系统调用280 6.5.2 get_ticks的应用286 6.6 进程调度292 6.6.1 避免对称--进程的节奏感292 6.6.2 优先级调度总结300 第7章 输入/输出系统302 7.1 键盘302 7.1.1 从中断开始--键盘初体验302 7.1.2 AT、PS/2键盘304 7.1.3 键盘敲击的过程304 7.1.4 解析扫描码309 7.2 显示器325 7.2.1 初识TTY325 7.2.2 基本概念326 7.2.3 寄存器328 7.3 TTY任务332 7.3.1 TTY任务框架的搭建334 7.3.2 多控制台340 7.3.3 完善键盘处理346 7.3.4 TTY任务总结354 7.4 区分任务和用户进程354 7.5 printf357 7.5.1 为进程指定TTY357 7.5.2 printf()的实现358 7.5.3 系统调用write()361 7.5.4 使用printf()363 后记366
自己动手操作系统在详细分析操作系统原理的基础上,用丰富的实例代码,一步一步地指导读者用C语言和汇编语言编出一个具备操作系统基本功能的操作系统框架。本书不同于其他的理论型书籍,而是提供给读者一个动手实践的路线图。书中讲解了大量在开发操作系统中需注意的细节问题,这些细节不仅能使读者更深刻地认识操作系统的核心原理,而且使整个开发过程少走弯路。全书共分7章。 第1章 马上动手一个最小的“操作系统”1 1.1 准备工作1 1.2 10分钟完成的操作系统1 1.3 Boot Sector3 1.4 代码解释3 1.5 水面下的冰山5 1.6 回顾6 第2章 搭建你的工作环境7 2.1 虚拟计算机(Virtual PC)7 2.1.1 Virtual PC初体验8 2.1.2 创建你的第一个Virtual PC9 2.1.3 虚拟软盘研究12 2.1.4 虚拟软盘实战14 2.2 编译器(NASM & GCC)18 2.3 安装虚拟Linux19 2.4 在虚拟Linux上访问Windows文件夹26 2.5 安装虚拟PCDOS26 2.6 其他要素29 2.7 Bochs29 2.7.1 Bochs vs. Virtual PC vs. VMware30 2.7.2 Bochs的使用方法31 2.7.3 用Bochs进行调试33 2.7.4 在Linux上开发34 2.8 总结与回顾36 第3章 保护模式(Protect Mode)37 3.1 认识保护模式37 3.1.1 GDT(Global Des criptor Table) 42 3.1.2 实模式到保护模式,不一般的jmp45 3.1.3 描述符属性47 3.2 保护模式进阶50 3.2.1 海阔凭鱼跃50 3.2.2 LDT(Local Des criptor Table)58 3.2.3 特权级62 3.3 页式存储82 3.3.1 分页机制概述83 3.3.2 编代码启动分页机制84 3.3.3 PDE和PTE85 3.3.4 cr388 3.3.5 回头看代码88 3.3.6 克勤克俭用内存90 3.3.7 进一步体会分页机制100 3.4 中断和异常107 3.4.1 中断和异常机制109 3.4.2 外部中断111 3.4.3 编程操作8259A113 3.4.4 建立IDT116 3.4.5 实现一个中断117 3.4.6 时钟中断试验119 3.4.7 几点额外说明121 3.5 保护模式下的I/O122 3.5.1 IOPL122 3.5.2 I/O许可位图(I/O Permission Bitmap)123 3.6 保护模式小结123 第4章 让操作系统走进保护模式125 4.1 突破512字节的限制125 4.1.1 FAT12126 4.1.2 DOS可以识别的引导盘131 4.1.3 一个最简单的Loader132 4.1.4 加载Loader入内存133 4.1.5 向Loader交出控制权142 4.1.6 整理boot.asm142 4.2 保护模式下的“操作系统”144 第5章 内核雏形146 5.1 用NASM在Linux下Hello World146 5.2 再进一步,汇编和C同步使用148 5.3 ELF(Executable and Linkable Format)150 5.4 从Loader到内核155 5.4.1 用Loader加载ELF155 5.4.2 跳入保护模式161 5.4.3 重新放置内核170 5.4.4 向内核交出控制权175 5.4.5 操作系统的调试方法176 5.5 扩充内核184 5.5.1 切换堆栈和GDT184 5.5.2 整理我们的文件夹191 5.5.3 Makefile191 5.5.4 添加中断处理200 5.5.5 两点说明218 5.6 小结219 第6章 进程221 6.1 迟到的进程221 6.2 概述222 6.2.1 进程介绍222 6.2.2 未雨绸缪——形成进程的必要考虑222 6.2.3 参考的代码224 6.3 最简单的进程224 6.3.1 简单进程的关键技术预测225 6.3.2 第一步——ring0→ring1227 6.3.3 第二步——丰富中断处理程序243 6.3.4 进程体设计技巧254 6.4 多进程256 6.4.1 添加一个进程体256 6.4.2 相关的变量和宏257 6.4.3 进程表初始化代码扩充258 6.4.4 LDT260 6.4.5 修改中断处理程序261 6.4.6 添加一个任务的步骤总结263 6.4.7 号外:Minix的中断处理265 6.4.8 代码回顾与整理269 6.5 系统调用280 6.5.1 实现一个简单的系统调用280 6.5.2 get_ticks的应用286 6.6 进程调度292 6.6.1 避免对称——进程的节奏感292 6.6.2 优先级调度总结300 第7章 输入/输出系统302 7.1 键盘302 7.1.1 从中断开始——键盘初体验302 7.1.2 AT、PS/2键盘304 7.1.3 键盘敲击的过程304 7.1.4 解析扫描码309 7.2 显示器325 7.2.1 初识TTY325 7.2.2 基本概念326 7.2.3 寄存器328 7.3 TTY任务332 7.3.1 TTY任务框架的搭建334 7.3.2 多控制台340 7.3.3 完善键盘处理346 7.3.4 TTY任务总结354 7.4 区分任务和用户进程354 7.5 printf357 7.5.1 为进程指定TTY357 7.5.2 printf()的实现358 7.5.3 系统调用write()361 7.5.4 使用printf()363 后记366 参考文献369 附录书中的章节和代码对照表370

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值