目录
- 环境配置
- 工具的使用及相关资源
- Compling and Running NEMU
- 配置系统make menuconfig
- 项目构建make
- 运行与调试
- Submit
环境配置
- Ubuntu安装中的分区不太明白
- 安装了中文输入法和必要的工具链
- 虚拟机与主机互联
工具的使用及相关资源
- vim(vimtutor是vim的一个内置教程)
主要修改一下配置文件,先进行备份:
$ cp /etc/vim/vimrc ~/.vimrc
然后回到家目录:
$ vi .vimrc
添加如下内容:
set tabstop=4
set softtabstop =4
set cindent
set shiftwidth=4
可以参考讲义里的配置
- make
基本的操作如下:
$ vi hello.c
$ gcc hello.c -o hello
$ ./hello
在hello.c所在目录下新建一个文件Makefile,输入以下内容并保存:
hello:hello.c gcc hello.c -o hello # 注意开头的 tab,而不是空格
.PHONY: clean
clean: rm hello # 注意开头的 tab,而不是空格
返回命令行,键入 make,你会发现 make 程序调用了 gcc 进行编译。
若连续多次执行 make,会得到 make: ‘hello’ is up to date. 的提示信息。
其中 .PHONY: clean 这一行的作用是防止同目录下的 clean 文件影响 Makefile 的执行。
- git
The workflow above shows how you will use branch in PAs:- before starting a new PA, new a branch pa? and check out to it
- coding in the branch pa? (this will introduce lot of modifications)
- after finish the PA, merge the branch pa? into master, and check out back to master
Compling and Running NEMU
在nemu/文件夹中,我们需要进行 NEMU 项目中的配置系统和项目构建(更多内容详见 PA1 RTFSC)。
配置系统make menuconfig
执行这一步前,需要先安装 bison 和 flex(根据报错提示安装即可)
NEMU 中的配置系统为于 nemu/tools/kconfig,它来源于 GNU / Linux 项目中的 kconfig。
kconfig 定义了一套简单的语言,开发者可以使用这套语言来编写“配置描述文件”。
在 NEMU 项目中,“配置描述文件”的文件名都为 Kconfig,如 nemu/Kconfig。
当键入 make menuconfig 的时候,背后其实发生了如下事件:
- 检查 nemu/tools/kconfig/build/mconf 程序是否存在,若不存在,则编译并生成 mconf
- 检查 nemu/tools/kconfig/build/conf 程序是否存在,若不存在,则编译并生成 conf
- 运行命令 mconf nemu/Kconfig,此时 mconf 将会解析 nemu/Kconfig 中的描述,以菜单树的形式展示各种配置选项,供开发者进行选择
- 退出菜单时,mconf 会把开发者选择的结果记录到 nemu/.config 文件中
- 运行命令 conf --syncconfig nemu/Kconfig,此时 conf 将会解析 nemu/Kconfig 中的描述,并读取选择结果 nemu/.config,结合两者来生成如下文件:
- 可以被包含到 C 代码中的宏定义 (nemu/include/generated/autoconf.h),这些宏的名称都是形如 CONFIG_xxx 的形式
- 可以被包含到 Makefile 中的变量定义 (nemu/include/config/auto.conf)
- ……
+ CC src/memory/paddr.c
+ CXX src/utils/disasm.cc
src/utils/disasm.cc:5:10: fatal error: llvm/Support/TargetRegistry.h: No such file or directory
5 | #include "llvm/Support/TargetRegistry.h"
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make: *** [/home/crx/ics2021/nemu/scripts/build.mk:40: /home/crx/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/utils/disasm.o] Error 1
经过stackoverflow的启发Stackoverflow:llvm/Support/TargetRegistry.h: No such file or directory,知道了是编译(8月31号开始)src/utils/disasm.cc的时候,出现了文件引用失败。这时候用到了一个命令apt-file来寻找这个TargetRegistry.h文件。在这里简单介绍下apt-file 的作用 apt-file。
apt-file:apt-file is a command line tool for searching files in packages for the APT package management system。apt-file 是一个命令行界面的 APT 包搜索工具。当我们在编译源代码时,时有缺少文件的情况发生。此时,通过 apt-file 就可以找出该缺失文件所在的包,然后将缺失的包安装后即可让编译顺利进行了。所以当我们通过执行命令
apt-file search TargetRegistry.h
后,可以发现
所以可以解决TargetRegistry.h文件缺失问题了:因为当前我们的llvm版本是14,TargetRegistry.h文件在/llvm/MC/下,而不是src/utils/disasm.cc文件的#include “llvm/Support/TargetRegistry.h”
项目构建make
liaobei@liaohaijin-vm:~/ics2021/nemu$ make
+ CC src/nemu-main.c
+ CC src/cpu/difftest/dut.c
+ CC src/cpu/cpu-exec.c
+ CC src/monitor/sdb/sdb.c
+ CC src/monitor/sdb/watchpoint.c
+ CC src/monitor/sdb/expr.c
+ CC src/monitor/monitor.c
+ CC src/utils/timer.c
+ CC src/utils/state.c
+ CC src/utils/log.c
+ CC src/utils/rand.c
+ CC src/memory/paddr.c
+ CC src/memory/vaddr.c
+ CC src/isa/riscv32/difftest/dut.c
+ CC src/isa/riscv32/reg.c
+ CC src/isa/riscv32/init.c
+ CC src/isa/riscv32/system/intr.c
+ CC src/isa/riscv32/system/mmu.c
+ CC src/isa/riscv32/instr/decode.c
+ CC src/isa/riscv32/logo.c
+ CC src/device/io/map.c
+ CC src/device/io/mmio.c
+ CC src/device/io/port-io.c
+ CC src/engine/interpreter/init.c
+ CC src/engine/interpreter/hostcall.c
+ CXX src/utils/disasm.cc
+ LD /home/liaobei/ics2021/nemu/build/riscv32-nemu-interpreter
下面是Makefile文件的内容,对其进行解读:
# Sanity check
ifeq ($(wildcard $(NEMU_HOME)/src/nemu-main.c),)
$(error NEMU_HOME=$(NEMU_HOME) is not a NEMU repo)
endif
# Include variables and rules generated by menuconfig
-include $(NEMU_HOME)/include/config/auto.conf
-include $(NEMU_HOME)/include/config/auto.conf.cmd
remove_quote = $(patsubst "%",%,$(1))
# Extract variabls from menuconfig
GUEST_ISA ?= $(call remove_quote,$(CONFIG_ISA))
ENGINE ?= $(call remove_quote,$(CONFIG_ENGINE))
NAME = $(GUEST_ISA)-nemu-$(ENGINE)
# Include all filelist.mk to merge file lists
FILELIST_MK = $(shell find ./src -name "filelist.mk")
include $(FILELIST_MK)
# Filter out directories and files in blacklist to obtain the final set of source files
DIRS-BLACKLIST-y += $(DIRS-BLACKLIST)
SRCS-BLACKLIST-y += $(SRCS-BLACKLIST) $(shell find $(DIRS-BLACKLIST-y) -name "*.c")
SRCS-y += $(shell find $(DIRS-y) -name "*.c")
SRCS = $(filter-out $(SRCS-BLACKLIST-y),$(SRCS-y))
# Extract compiler and options from menuconfig
CC = $(call remove_quote,$(CONFIG_CC))
CFLAGS_BUILD += $(call remove_quote,$(CONFIG_CC_OPT))
CFLAGS_BUILD += $(if $(CONFIG_CC_LTO),-flto,)
CFLAGS_BUILD += $(if $(CONFIG_CC_DEBUG),-ggdb3,)
CFLAGS_BUILD += $(if $(CONFIG_CC_ASAN),-fsanitize=address,)
CFLAGS_TRACE += -DITRACE_COND=$(if $(CONFIG_ITRACE_COND),$(call remove_quote,$(CONFIG_ITRACE_COND)),true)
CFLAGS += $(CFLAGS_BUILD) $(CFLAGS_TRACE) -D__GUEST_ISA__=$(GUEST_ISA)
LDFLAGS += $(CFLAGS_BUILD)
# Include rules for menuconfig
include $(NEMU_HOME)/scripts/config.mk
ifdef CONFIG_TARGET_AM
include $(AM_HOME)/Makefile
LINKAGE += $(ARCHIVES)
else
# Include rules to build NEMU
include $(NEMU_HOME)/scripts/native.mk
endif
- 与配置系统进行关联
通过包含nemu/include/config/auto.conf,与kconfig生成的变量进行关联
-include $(NEMU_HOME)/include/config/auto.conf
- 文件列表
在nemu/src及其子目录下存在一些名为filelist.mk的文件:
liaobei@liaohaijin-vm:~/ics2021/nemu$ find ./ -name filelist.mk
./src/utils/filelist.mk
./src/filelist.mk
./src/isa/filelist.mk
./src/device/filelist.mk
./src/engine/filelist.mk
它们会根据menuconfig的配置对如下4个变量进行维护:
- SRCS-y - 参与编译的源文件的候选集合
- SRCS-BLACKLIST-y - 不参与编译的源文件的黑名单集合
- DIRS-y -参与编译的目录集合, 该目录下的所有文件都会被加入到SRCS-y中
- DIRS-BLACKLIST-y - 不参与编译的目录集合,该目录下的所有文件都会被加入到SRCS-BLACKLIST-y中
Makefile中会包含项目中的所有filelist.mk文件,对上述4个变量的追加定义进行汇总,最终会过滤出在SRCS-y中但不在SRCS-BLACKLIST-y中的源文件,来作为最终参与编译的源文件的集合。 - 编译和链接
Makefile的编译规则在nemu/srcripts/build.mk中定义,见# Compilation patterns 后的部分:
.DEFAULT_GOAL = app
# Add necessary options if the target is a shared library
ifeq ($(SHARE),1)
SO = -so
CFLAGS += -fPIC
LDFLAGS += -rdynamic -shared -fPIC
endif
WORK_DIR = $(shell pwd)
BUILD_DIR = $(WORK_DIR)/build
INC_PATH := $(WORK_DIR)/include $(INC_PATH)
OBJ_DIR = $(BUILD_DIR)/obj-$(NAME)$(SO)
BINARY = $(BUILD_DIR)/$(NAME)$(SO)
# Compilation flags
ifeq ($(CC),clang)
CXX := clang++
else
CXX := g++
endif
LD := $(CXX)
INCLUDES = $(addprefix -I, $(INC_PATH))
CFLAGS := -O2 -MMD -Wall -Werror $(INCLUDES) $(CFLAGS)
LDFLAGS := -O2 $(LDFLAGS)
OBJS = $(SRCS:%.c=$(OBJ_DIR)/%.o) $(CXXSRC:%.cc=$(OBJ_DIR)/%.o)
# Compilation patterns
$(OBJ_DIR)/%.o: %.c
@echo + CC $<
@mkdir -p $(dir $@)
@$(CC) $(CFLAGS) -c -o $@ $<
$(call call_fixdep, $(@:.o=.d), $@)
$(OBJ_DIR)/%.o: %.cc
@echo + CXX $<
@mkdir -p $(dir $@)
@$(CXX) $(CFLAGS) $(CXXFLAGS) -c -o $@ $<
$(call call_fixdep, $(@:.o=.d), $@)
# Depencies
-include $(OBJS:.o=.d)
# Some convenient rules
.PHONY: app clean
app: $(BINARY)
$(BINARY): $(OBJS) $(ARCHIVES)
@echo + LD $@
@$(LD) -o $@ $(OBJS) $(LDFLAGS) $(ARCHIVES) $(LIBS)
clean:
-rm -rf $(BUILD_DIR)
$@表示所有参数列表,$<表示第一个依赖文件,call_fixdep的调用用于生成更合理的依赖关系(先忽略)。
可以通过输入make -nB让make程序以“只输出命令但不执行”的方式强制构建目标。
截取整理好的一段输出分析:
gcc -O2 -MMD -Wall -Werror -I/home/liaobei/ics2021/nemu/include -I/home/liaobei/ics2021/nemu/src/isa/riscv32/include -I/home/liaobei/ics2021/nemu/src/engine/interpreter -O2 -ggdb3 -DITRACE_COND=true -D__GUEST_ISA__=riscv32 -c -o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/nemu-main.o src/nemu-main.c
gcc -O2 -MMD -Wall -Werror -I/home/liaobei/ics2021/nemu/include -I/home/liaobei/ics2021/nemu/src/isa/riscv32/include -I/home/liaobei/ics2021/nemu/src/engine/interpreter -O2 -ggdb3 -DITRACE_COND=true -D__GUEST_ISA__=riscv32 -c -o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/cpu/difftest/dut.o src/cpu/difftest/dut.c
gcc -O2 -MMD -Wall -Werror -I/home/liaobei/ics2021/nemu/include -I/home/liaobei/ics2021/nemu/src/isa/riscv32/include -I/home/liaobei/ics2021/nemu/src/engine/interpreter -O2 -ggdb3 -DITRACE_COND=true -D__GUEST_ISA__=riscv32 -c -o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/cpu/cpu-exec.o src/cpu/cpu-exec.c
gcc -O2 -MMD -Wall -Werror -I/home/liaobei/ics2021/nemu/include -I/home/liaobei/ics2021/nemu/src/isa/riscv32/include -I/home/liaobei/ics2021/nemu/src/engine/interpreter -O2 -ggdb3 -DITRACE_COND=true -D__GUEST_ISA__=riscv32 -c -o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/monitor/sdb/sdb.o src/monitor/sdb/sdb.c
gcc -O2 -MMD -Wall -Werror -I/home/liaobei/ics2021/nemu/include -I/home/liaobei/ics2021/nemu/src/isa/riscv32/include -I/home/liaobei/ics2021/nemu/src/engine/interpreter -O2 -ggdb3 -DITRACE_COND=true -D__GUEST_ISA__=riscv32 -c -o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/monitor/sdb/watchpoint.o src/monitor/sdb/watchpoint.c
gcc -O2 -MMD -Wall -Werror -I/home/liaobei/ics2021/nemu/include -I/home/liaobei/ics2021/nemu/src/isa/riscv32/include -I/home/liaobei/ics2021/nemu/src/engine/interpreter -O2 -ggdb3 -DITRACE_COND=true -D__GUEST_ISA__=riscv32 -c -o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/monitor/sdb/expr.o src/monitor/sdb/expr.c
gcc -O2 -MMD -Wall -Werror -I/home/liaobei/ics2021/nemu/include -I/home/liaobei/ics2021/nemu/src/isa/riscv32/include -I/home/liaobei/ics2021/nemu/src/engine/interpreter -O2 -ggdb3 -DITRACE_COND=true -D__GUEST_ISA__=riscv32 -c -o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/monitor/monitor.o src/monitor/monitor.c
gcc -O2 -MMD -Wall -Werror -I/home/liaobei/ics2021/nemu/include -I/home/liaobei/ics2021/nemu/src/isa/riscv32/include -I/home/liaobei/ics2021/nemu/src/engine/interpreter -O2 -ggdb3 -DITRACE_COND=true -D__GUEST_ISA__=riscv32 -c -o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/utils/timer.o src/utils/timer.c
gcc -O2 -MMD -Wall -Werror -I/home/liaobei/ics2021/nemu/include -I/home/liaobei/ics2021/nemu/src/isa/riscv32/include -I/home/liaobei/ics2021/nemu/src/engine/interpreter -O2 -ggdb3 -DITRACE_COND=true -D__GUEST_ISA__=riscv32 -c -o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/utils/state.o src/utils/state.c
gcc -O2 -MMD -Wall -Werror -I/home/liaobei/ics2021/nemu/include -I/home/liaobei/ics2021/nemu/src/isa/riscv32/include -I/home/liaobei/ics2021/nemu/src/engine/interpreter -O2 -ggdb3 -DITRACE_COND=true -D__GUEST_ISA__=riscv32 -c -o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/utils/log.o src/utils/log.c
gcc -O2 -MMD -Wall -Werror -I/home/liaobei/ics2021/nemu/include -I/home/liaobei/ics2021/nemu/src/isa/riscv32/include -I/home/liaobei/ics2021/nemu/src/engine/interpreter -O2 -ggdb3 -DITRACE_COND=true -D__GUEST_ISA__=riscv32 -c -o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/utils/rand.o src/utils/rand.c
gcc -O2 -MMD -Wall -Werror -I/home/liaobei/ics2021/nemu/include -I/home/liaobei/ics2021/nemu/src/isa/riscv32/include -I/home/liaobei/ics2021/nemu/src/engine/interpreter -O2 -ggdb3 -DITRACE_COND=true -D__GUEST_ISA__=riscv32 -c -o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/memory/paddr.o src/memory/paddr.c
gcc -O2 -MMD -Wall -Werror -I/home/liaobei/ics2021/nemu/include -I/home/liaobei/ics2021/nemu/src/isa/riscv32/include -I/home/liaobei/ics2021/nemu/src/engine/interpreter -O2 -ggdb3 -DITRACE_COND=true -D__GUEST_ISA__=riscv32 -c -o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/memory/vaddr.o src/memory/vaddr.c
gcc -O2 -MMD -Wall -Werror -I/home/liaobei/ics2021/nemu/include -I/home/liaobei/ics2021/nemu/src/isa/riscv32/include -I/home/liaobei/ics2021/nemu/src/engine/interpreter -O2 -ggdb3 -DITRACE_COND=true -D__GUEST_ISA__=riscv32 -c -o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/isa/riscv32/difftest/dut.o src/isa/riscv32/difftest/dut.c
对比可知,我们可以知道,$<为src/nemu-main.c,$@为/home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/nemu-main.o,$(CC)为gcc等,这些Makefile中的变量,在/include/config/auto.conf定义了。
可以根据上述输出结果和 Makefile 反推 $(CFLAGS) 的值是如何形成的。
编译之后是一系列 git 操作,规则在 nemu/scripts/git.mk 中定义。下面是输出:
git add /home/liaobei/ics2021/nemu/.. -A --ignore-errors
while (test -e .git/index.lock); do sleep 0.1; done
sync
最后是链接操作:
g++ -o /home/liaobei/ics2021/nemu/build/riscv32-nemu-interpreter /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/nemu-main.o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/cpu/difftest/dut.o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/cpu/cpu-exec.o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/monitor/sdb/sdb.o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/monitor/sdb/watchpoint.o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/monitor/sdb/expr.o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/monitor/monitor.o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/utils/timer.o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/utils/state.o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/utils/log.o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/utils/rand.o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/memory/paddr.o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/memory/vaddr.o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/isa/riscv32/difftest/dut.o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/isa/riscv32/reg.o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/isa/riscv32/init.o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/isa/riscv32/system/intr.o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/isa/riscv32/system/mmu.o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/isa/riscv32/instr/decode.o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/isa/riscv32/logo.o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/device/io/map.o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/device/io/mmio.o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/device/io/port-io.o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/engine/interpreter/init.o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/engine/interpreter/hostcall.o /home/liaobei/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/utils/disasm.o -O2 -O2 -ggdb3 -lLLVM-14 -lreadline -ldl -pie
运行与调试
To run NEMU, type
make run
To debug NEMU with gdb, type
make gdb
Submit
需要有足够的耐心,对于不清楚的知识和看不懂的源码像Makefile的内容,不断进行RTFM和STFW,要有信心一定有工具能帮助我们更好的理解代码😆。