jos学习---day1代码整体结构
目录结构
workdir
|------ GNUmakefile
|
|------ boot
| |---- Makefrag
| |---- boot.S
| |---- main.c
|------ fs
|
|------ inc
|
|------ kern
| |---- Makefrag
| |---- kernel.ld
| |---- entry.S
| |---- entrypgdir,c
| |---- init.c
| |---- monitor.c
| |---- monitor.h
| |---- kdebug.c
| |---- kdebug.h
| |---- printf.c
| |---- console.c
| |---- console.h
|
|------ user
|
|------ conf
| |---- env.mk
| |---- lab.mk
这里boot和kern目录下的Makefrag分别定义了内核boot和主体在编译时所需要的文件
文件boot/Makefarg
内容如下:
# 编译之后对象文件输出的目录
OBJDIRS += boot# 编译之后输出的对象文件
BOOT_OBJS := $(OBJDIR)/boot/boot.o $(OBJDIR)/boot/main.o# 得到对象文件的方法
# 下面出现的变量都是在顶层Makefile中
# 将所有的.c文件编译成.o文件
$(OBJDIR)/boot/%.o: boot/%.c@echo + cc -Os $<@mkdir -p $(@D)$(V)$(CC) -nostdinc $(KERN_CFLAGS) -Os -c -o $@ $<# 将所有的.S文件编译.o文件
$(OBJDIR)/boot/%.o: boot/%.S@echo + as $<@mkdir -p $(@D)$(V)$(CC) -nostdinc $(KERN_CFLAGS) -c -o $@ $<$(OBJDIR)/boot/main.o: boot/main.c@echo + cc -Os $<$(V)$(CC) -nostdinc $(KERN_CFLAGS) -Os -c -o $(OBJDIR)/boot/main.o boot/main.c$(OBJDIR)/boot/boot: $(BOOT_OBJS)@echo + ld boot/boot$(V)$(LD) $(LDFLAGS) -N -e start -Ttext 0x7C00 -o $@.out $^$(V)$(OBJDUMP) -S $@.out >$@.asm$(V)$(OBJCOPY) -S -O binary -j .text $@.out $@$(V)perl boot/sign.pl $(OBJDIR)/boot/boot
文件kern/Makefarg
内容如下:
OBJDIRS += kernKERN_LDFLAGS := $(LDFLAGS) -T kern/kernel.ld -nostdlib# entry.S must be first, so that it's the first code in the text segment!!!
#
# We also snatch the use of a couple handy source files
# from the lib directory, to avoid gratuitous code duplication.
KERN_SRCFILES := kern/entry.S \kern/entrypgdir.c \kern/init.c \kern/console.c \kern/monitor.c \kern/pmap.c \kern/env.c \kern/kclock.c \kern/picirq.c \kern/printf.c \kern/trap.c \kern/trapentry.S \kern/sched.c \kern/syscall.c \kern/kdebug.c \lib/printfmt.c \lib/readline.c \lib/string.c# Only build files if they exist.
KERN_SRCFILES := $(wildcard $(KERN_SRCFILES))# Binary program images to embed within the kernel.
KERN_BINFILES :=KERN_OBJFILES := $(patsubst %.c, $(OBJDIR)/%.o, $(KERN_SRCFILES))
KERN_OBJFILES := $(patsubst %.S, $(OBJDIR)/%.o, $(KERN_OBJFILES))
KERN_OBJFILES := $(patsubst $(OBJDIR)/lib/%, $(OBJDIR)/kern/%, $(KERN_OBJFILES))KERN_BINFILES := $(patsubst %, $(OBJDIR)/%, $(KERN_BINFILES))# How to build kernel object files
$(OBJDIR)/kern/%.o: kern/%.c $(OBJDIR)/.vars.KERN_CFLAGS@echo + cc $<@mkdir -p $(@D)$(V)$(CC) -nostdinc $(KERN_CFLAGS) -c -o $@ $<$(OBJDIR)/kern/%.o: kern/%.S $(OBJDIR)/.vars.KERN_CFLAGS@echo + as $<@mkdir -p $(@D)$(V)$(CC) -nostdinc $(KERN_CFLAGS) -c -o $@ $<$(OBJDIR)/kern/%.o: lib/%.c $(OBJDIR)/.vars.KERN_CFLAGS@echo + cc $<@mkdir -p $(@D)$(V)$(CC) -nostdinc $(KERN_CFLAGS) -c -o $@ $<# Special flags for kern/init
$(OBJDIR)/kern/init.o: override KERN_CFLAGS+=$(INIT_CFLAGS)
$(OBJDIR)/kern/init.o: $(OBJDIR)/.vars.INIT_CFLAGS# How to build the kernel itself
$(OBJDIR)/kern/kernel: $(KERN_OBJFILES) $(KERN_BINFILES) kern/kernel.ld \$(OBJDIR)/.vars.KERN_LDFLAGS@echo + ld $@$(V)$(LD) -o $@ $(KERN_LDFLAGS) $(KERN_OBJFILES) $(GCC_LIB) -b binary $(KERN_BINFILES)$(V)$(OBJDUMP) -S $@ > $@.asm$(V)$(NM) -n $@ > $@.sym# How to build the kernel disk image
$(OBJDIR)/kern/kernel.img: $(OBJDIR)/kern/kernel $(OBJDIR)/boot/boot@echo + mk $@$(V)dd if=/dev/zero of=$(OBJDIR)/kern/kernel.img~ count=10000 2>/dev/null$(V)dd if=$(OBJDIR)/boot/boot of=$(OBJDIR)/kern/kernel.img~ conv=notrunc 2>/dev/null$(V)dd if=$(OBJDIR)/kern/kernel of=$(OBJDIR)/kern/kernel.img~ seek=1 conv=notrunc 2>/dev/null$(V)mv $(OBJDIR)/kern/kernel.img~ $(OBJDIR)/kern/kernel.imgall: $(OBJDIR)/kern/kernel.imggrub: $(OBJDIR)/jos-grub$(OBJDIR)/jos-grub: $(OBJDIR)/kern/kernel@echo + oc $@$(V)$(OBJCOPY) --adjust-vma=0x10000000 $^ $@
关于makefile语法的一些补充
makefile中等号的使用
=
:make会将整个makefile展开之后再决定左边变量的值,所以左边变量的值会是makefile中最后被指定的值
:=
:变量使用:=
赋值会覆盖之前的值,当使用:=
赋值时,变量的值取决于赋值的位置
?=
:如果左边变量之前没有被赋值,则将右边的值赋给左边,反之,变量保留原值
+=
:将右边的值加到左边的变量中
$<
代表依赖目标,即:
右边的文件,这里是将右边的文件一个一个的提取出来
$@
代表目标文件,即:
左边的文件,这里是将左边的文件一个一个的提取出来
以上面的Makefile为例
$(V)$(CC) -nostdinc $(KERN_CFLAGS) -Os -c -o $@ $<
这句在执行时会将$(OBJDIR)/boot/%.o: boot/%.c
指定的.c文件一个一个的编译成.o文件
关于gcc编译选项的说明
-Os
:优化等级和-O2
一致,但是不缩减代码尺寸
-nostdinc
:不在系统目录中寻找头文件
-pipe
:在编译的各个阶段使用管道而不是临时文件进行通信
-fno-builtin
:不引用标准库的c语言函数
-MD
:根据makefile会生成对应目标文件的依赖文件,即.d文件
关于ld的链接选项
-N
:与--omagic
等价,作用是将text段和data段设置为可读可写的。同时data段不以page为单位对齐
-e
:与--entry
等价,作用是将后面跟的符号作为程序执行的入口,而不是默认入口(一般是main)
-Ttext
:设置text段的地址,与其类似的还有-Tbss
,Tdata
关于dd指令的使用
创建一个可以启动的jos镜像需要以下三步
- dd if=/dev/zero of=obj/kern/kernel.img~ count=10000 2>/dev/null
- dd if=obj/boot/boot of=obj/kern/kernel.img~ conv=notrunc 2>/dev/null
- dd if=obj/kern/kernel of=obj/kern/kernel.img~ seek=1 conv=notrunc 2>/dev/null
第一步是初始化了一个10000个block的镜像文件kernel.img~,每个block的大小可以有ibs选项设置,默认是512bytes
第二步是将编译出来的boot elf文件加载到kernel.img~的第一个block中
第三步是将编译出来的kernel elf文件从第二个block开始加载到kernel.img中
seek
:跳过seek选项后面数值的block之后开始复制
conv
:设置传输模式,这里设置的notrunc意思是不截断输出文件
jos在qemu中启动内核的操作
qemu-system-i386 -drive file=obj/kern/kernel.img,index=0,media=disk,format=raw -serial mon:stdio -gdb tcp::26000 -D qemu.log
里面比较关键的几个选项是:
-drive file=obj/kern/kernel.img,index=0,media=disk,format=raw
-serial mon:stdio
gdb tcp::26000
-D qemu.log
我尝试了一下不加-drive选项直接引导镜像,也可以启动系统,但是有一个警告,并且在系统运行的过程中shell中没有任何的log输出。
WARNING: Image format was not specified for 'obj/kern/kernel.img' and probing guessed raw.Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.Specify the 'raw' format explicitly to remove the restrictions.
这里的提示是没有指定镜像的格式,自动探测为raw格式。限制了对block 0的写操作。
qemu一些标志的使用
参考
标准选项
-h : 显示帮助
-version : 显示版本
-machine [type]name[,prop=value[,…]]
- 该选项中name指定qemu模拟的机器平台,prop用于指定该机器运行时的一些属性。当前支持的机器平台可以使用-machine help得到
-drive option[[,option[,option[,…]]]]
- file=file 该选项用于指定要使用的镜像文件
- if=interface 该选项用于指定驱动器连接的接口类型,包括ide, scsi, sd, mtd, floppy, pflash, virtio, none.
- bus=bus,unit=unit 该选项指定bus号和unit号,决定驱动器的连接位置。
- index=index 在给定的接口类型的列表中定位连接驱动器的位置
- media=media 指定存储介质,包括disk和cdrom
-serial dev 该选项试讲虚拟串口重定向到宿主机的字符设备上去。默认是vc(图形化界面)和stdio(非图形化界面)
- vc[:WxH] 配置图形的大小
- pty
- chardev:id
- mon:dev_string 允许监视器被多路复用到另一个端口
jos学习---day1代码整体结构相关推荐
- 学习记录:UnityHDRP高清渲染管线学习 day1
附一张这本书的封面截图 ps:(我自我介绍一下吧,高中不好好学习去了大专,现在大一暑假在一家郑州互联网公司实习,月薪4500,转正之后是八千多(我觉得挺多了),其实并不是我多聪明,只是抓住了机会不想再 ...
- 如何阅读一份深度学习项目代码?
犹豫很久要不要把读代码这个事情专门挑出来写成一篇推文.毕竟读代码嘛,大家可能都会读.而且笔者个人读的和写的代码量也并不足以到指导大家读代码的程度.但笔者还是决定大胆地写一点:就当是给自己设立今后读代码 ...
- 准确率可提升50%以上,Facebook用迁移学习改进代码自动补全
视学算法报道 转载自:机器之心 编辑:陈萍.杜伟 来自 Facebook 的研究团队将迁移学习用于代码自动补全,提出的方法在非常小的微调数据集上提高 50% 以上的准确率,在 50k 标记示例上提高了 ...
- 深度学习项目代码阅读建议
点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达本文转自|机器学习实验室 犹豫很久要不要把读代码这个事情专门挑出来写 ...
- 如何高效的学习TensorFlow代码?
如何高效的学习TensorFlow代码? 如题,或者如何掌握TensorFlow,应用到任何领域? 添加评论分享 10 个回答 爱琳李,老李,明天就辍学了 8 人赞同 本来都忘了这个问题了,不过看到很 ...
- 为什么设计师应该学习编写代码
通常,在完成了一件网页设计后,设计师的无知都会显露无遗而备受指责.他们把创建网页代码的繁重工作都留给了程序员们.这种现象不只出现在网络开发行业,在软件及游戏开发业也是如此(完整图文版).残酷的事实就是 ...
- 怎样高效阅读一份深度学习项目代码?
犹豫很久要不要把读代码这个事情专门挑出来写成一篇推文.毕竟读代码嘛,大家可能都会读.而且笔者个人读的和写的代码量也并不足以到指导大家读代码的程度.但笔者还是决定大胆地写一点:就当是给自己设立今后读代码 ...
- 代价敏感多标签主动学习的代码开发跟踪
1 简介 代价敏感多标签主动学习目前是闵老师小组正在进行的一个开发项目,目的是将代价敏感和主动学习思想应用到多标签学习中.整个Java代码涵盖了很多技术:并行计算.batch处理.本文就是在学习这个代 ...
- 全员学习低代码,一汽大众领跑数智化转型背后的秘密
简介:500位低代码开发者,90%来自一线,低代码开发在一汽-大众百花齐放. 一汽-大众有500位低代码开发者,90%是来自一线的业务人员,他们如何用低代码解决身边的数字化需求?钉钉宜搭<102 ...
最新文章
- 活动目录实战系列六(win98客户端加入域)
- C++primer 10.6节练习
- 数据库本地服务器为空,本地搭建的服务器访问不到数据库数据
- Visual C++——CComboBox控件在对话框中没有下拉项目问题解决方案
- java ee自动生成编码_EE Servlet 3:在Servlet中生成HTML输出
- stm32滴答计时器_stm32笔记:Systick系统滴答定时器
- angular4动态添加html,angular4 动态创建组件
- Smartmontools检测硬盘坏道
- 【Java并发.3】对象的共享
- face_recognition基础接口
- 中国生态城市规划行业“十四五”规划与前景规模预测报告2022-2028年版
- 如何完美的卸载Office2007?
- Linux 之旅 21:编译安装软件
- 电线线缆铜芯和铝芯有什么区别?哪个更好呢?
- 2015校招季,阿里、搜狗、百度、蘑菇街面试总结
- flink DataStream returns 设置返回类型
- 微前端之 qiankun 入门、上手、实战(构建大型 web 应用)
- Matlab App Designer 实现简单程序的设计笔记 (实时更新)
- php高强度薄壁金属复合管,PHP高强度薄壁金属复合管承插快速连接装置
- 关于新书《修炼之道:.NET开发要点精讲》的各种说明