操作系统实验一实验报告

这篇博客详细介绍了操作系统实验的内容,包括系统软件启动过程的各个步骤,如通过make生成ucore.img,理解硬盘主引导扇区的规范,使用qemu执行和调试软件,分析bootloader进入保护模式和加载ELF OS的过程。此外,还深入探讨了函数调用堆栈跟踪及中断初始化和处理,如中断描述符表的结构,时钟中断处理函数的实现等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

实验一:系统软件启动过程


练习1:理解通过make生成执行文件的过程

1.1 操作系统镜像文件ucore.img是如何一步一步生成的?

Makefile如下,解释部分内容参考

http://blog.csdn.net/lijunfan1994/article/details/46038167

PROJ    := challenge
EMPTY   :=
SPACE   := $(EMPTY) $(EMPTY)
SLASH   := /

##make "V="可输出make执行的命令
V       := @

#need llvm/cang-3.5+
#USELLVM := 1

##选择交叉编译器检查GCCPREFIX的设置
# try to infer the correct GCCPREFX
ifndef GCCPREFIX
GCCPREFIX := $(shell if i386-elf-objdump -i 2>&1 | grep '^elf32-i386$$' >/dev/null 2>&1; \
    then echo 'i386-elf-'; \
    elif objdump -i 2>&1 | grep 'elf32-i386' >/dev/null 2>&1; \
    then echo ''; \
    else echo "***" 1>&2; \
    echo "*** Error: Couldn't find an i386-elf version of GCC/binutils." 1>&2; \
    echo "*** Is the directory with i386-elf-gcc in your PATH?" 1>&2; \
    echo "*** If your i386-elf toolchain is installed with a command" 1>&2; \
    echo "*** prefix other than 'i386-elf-', set your GCCPREFIX" 1>&2; \
    echo "*** environment variable to that prefix and run 'make' again." 1>&2; \
    echo "*** To turn off this error, run 'gmake GCCPREFIX= ...'." 1>&2; \
    echo "***" 1>&2; exit 1; fi)
endif

##设置QEMU
# try to infer the correct QEMU
ifndef QEMU
QEMU := $(shell if which qemu-system-i386 > /dev/null; \
    then echo 'qemu-system-i386'; exit; \
    elif which i386-elf-qemu > /dev/null; \
    then echo 'i386-elf-qemu'; exit; \
    elif which qemu > /dev/null; \
    then echo 'qemu'; exit; \
    else \
    echo "***" 1>&2; \
    echo "*** Error: Couldn't find a working QEMU executable." 1>&2; \
    echo "*** Is the directory containing the qemu binary in your PATH" 1>&2; \
    echo "***" 1>&2; exit 1; fi)
endif

# eliminate default suffix rules
.SUFFIXES: .c .S .h

##如果遇到error或者被中断了就删除所有目标文件
# delete target files if there is an error (or make is interrupted)
.DELETE_ON_ERROR:

##设置编译器选项
# define compiler and flags
ifndef  USELLVM

##gcc编译,-g为了gdb调式,-Wall生成警告信息,-O2优化处理级别
HOSTCC      := gcc
HOSTCFLAGS  := -g -Wall -O2
CC      := $(GCCPREFIX)gcc

##-fno-builtin不使用C语言的内建函数,-ggdb为GDB生成更丰富的调试信息,-m32用32位编译,-gstabs生成stabs格式调试信息但不包括GDB调试信息,-nostdinc不在系统默认头文件目录中寻找头文件,$(DEFS)未定义可用来扩展信息
CFLAGS  := -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc $(DEFS)

##$(shell)可以输出shell指令,-fno-stack-protector禁用堆栈保护,-E仅预处理不进行编译汇编链接可以提高速度,-x c指明c语言
##/dev/null指定目标文件,>/dev/null 2>&1标准错误重定向到标准输出,&&先运行前一句若成功再运行后一句
##意为只预处理,所有出错全部作为垃圾(/dev/null类似垃圾文件)测试能否开启-fno-stack-protector,若能则CFLAGS += -fno-stack-protector
CFLAGS  += $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector)
else
##若使用clang,类似处理
HOSTCC      := clang
HOSTCFLAGS  := -g -Wall -O2
CC      := clang
CFLAGS  := -fno-builtin -Wall -g -m32 -mno-sse -nostdinc $(DEFS)
CFLAGS  += $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector)
endif

##源文件类型为.c和.S
CTYPE   := c S

LD      := $(GCCPREFIX)ld

##shell中命令 ld -V可以输出支持的版本,|管道将前者的输出作为后者的输入,grep在输入中搜索elf_i386字串,找到就输出elf_i386
##意味如果支持elf_i386则LDFLAGS := -m elf_i386
LDFLAGS := -m $(shell $(LD) -V | grep elf_i386 2>/dev/null)

##-nostdlib不连接系统标准库文件
LDFLAGS += -nostdlib

OBJCOPY := $(GCCPREFIX)objcopy
OBJDUMP := $(GCCPREFIX)objdump

##定义一些shell命令
COPY    := cp
MKDIR   := mkdir -p
MV      := mv
RM      := rm -f
AWK     := awk
SED     := sed
SH      := sh
TR      := tr
TOUCH   := touch -c

OBJDIR  := obj
BINDIR  := bin

ALLOBJS :=
ALLDEPS :=
TARGETS :=

##在function.mk中定义了大量辅助函数,部分说明参考了引用中的博文
include tools/function.mk

##call:call func,变量1,变量2,...
##listf:列出某地址下某类型的文件
##listf_cc:列出变量1下的.c与.S文件
listf_cc = $(call listf,$(1),$(CTYPE))

# for cc

##将文件打包
add_files_cc = $(call add_files,$(1),$(CC),$(CFLAGS) $(3),$(2),$(4))

##创建目标文件包
create_target_cc = $(call create_target,$(1),$(2),$(3),$(CC),$(CFLAGS))

# for hostcc
add_files_host = $(call add_files,$(1),$(HOSTCC),$(HOSTCFLAGS),$(2),$(3))
create_target_host = $(call create_target,$(1),$(2),$(3),$(HOSTCC),$(HOSTCFLAGS))

##patsubst替换通配符
##cgtype(filenames,type1,type2)把文件名中type1的改为type2,如.c改为.o
cgtype = $(patsubst %.$(2),%.$(3),$(1))

##列出所有目标文件,并按规则改后缀名
objfile = $(call toobj,$(1))
asmfile = $(call cgtype,$(call toobj,$(1)),o,asm)
outfile = $(call cgtype,$(call toobj,$(1)),o,out)
symfile = $(call cgtype,$(call toobj,$(1)),o,sym)

# for match pattern
match = $(shell echo $(2) | $(AWK) '{for(i=1;i<=NF;i++){if(match("$(1)","^"$$(i)"$$")){exit 1;}}}'; echo $$?)

# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
# include kernel/user

INCLUDE += libs/

CFLAGS  += $(addprefix -I,$(INCLUDE))

LIBDIR  += libs

$(call add_files_cc,$(call listf_cc,$(LIBDIR)),libs,)

# -------------------------------------------------------------------
# kernel

KINCLUDE    += kern/debug/ \
               kern/driver/ \
               kern/trap/ \
               kern/mm/

KSRCDIR     += kern/init \
               kern/libs \
               kern/debug \
               kern/driver \
               kern/trap \
               kern/mm

KCFLAGS     += $(addprefix -I,$(KINCLUDE))

$(call add_files_cc,$(call listf_cc,$(KSRCDIR)),kernel,$(KCFLAGS))

KOBJS   = $(call read_packet,kernel libs)

# create kernel target
##将所有文件链接生成kernel
kernel = $(call totarget,kernel)

$(kernel): tools/kernel.ld

$(kernel): $(KOBJS)
    @echo + ld $@
    $(V)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值