TOC
Open TOC
ICS PA 0
环境配置
Ubuntu
安装中的分区不太明白。- 安装了中文输入法和
Typora
。 - 虚拟机与主机使用 Gitee 互联。
工具的使用及相关资源
vim
主要修改一下配置文件,先进行备份:
$ cp /etc/vim/vimrc ~/.vimrc
然后回到家目录:
$ vi .vimrc
添加如下内容:
set tabstop=4set softtabstop=4set cindentset 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?
intomaster
, and check out back tomaster
Access GitHub
修改 /etc/hosts
文件如下:
127.0.0.1 localhost127.0.1.1 vgalaxy-VirtualBox10.0.2.15 github.com git13.250.177.223 github.com
# github.com192.30.253.112 github.com192.30.253.119 gist.github.com151.101.100.133 assets-cdn.github.com151.101.100.133 raw.githubusercontent.com151.101.100.133 gist.githubusercontent.com151.101.100.133 cloud.githubusercontent.com151.101.100.133 camo.githubusercontent.com151.101.100.133 avatars0.githubusercontent.com151.101.100.133 avatars1.githubusercontent.com151.101.100.133 avatars2.githubusercontent.com151.101.100.133 avatars3.githubusercontent.com151.101.100.133 avatars4.githubusercontent.com151.101.100.133 avatars5.githubusercontent.com151.101.100.133 avatars6.githubusercontent.com151.101.100.133 avatars7.githubusercontent.com151.101.100.133 avatars8.githubusercontent.com185.199.108.153 assets-cdn.github.com185.199.109.153 assets-cdn.github.com185.199.110.153 assets-cdn.github.com185.199.111.153 assets-cdn.github.com151.101.113.194 github.global.ssl.fastly.net
# The following lines are desirable for IPv6 capable hosts::1 ip6-localhost ip6-loopbackfe00::0 ip6-localnetff00::0 ip6-mcastprefixff02::1 ip6-allnodesff02::2 ip6-allrouters
其中 10.0.2.15
通过 ifconfig
命令查看
Compiling 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
) - ……
- 可以被包含到 C 代码中的宏定义 (
项目构建 make
$ make+ CC src/nemu-main.c+ CC src/cpu/difftest/dut.c+ CC src/cpu/cpu-exec.c+ CC src/monitor/monitor.c+ CC src/monitor/sdb/watchpoint.c+ CC src/monitor/sdb/expr.c+ CC src/monitor/sdb/sdb.c+ CC src/utils/log.c+ CC src/utils/timer.c+ CC src/utils/state.c+ CC src/utils/rand.c+ CC src/memory/paddr.c+ CC src/memory/vaddr.c+ CC src/device/io/port-io.c+ CC src/device/io/map.c+ CC src/device/io/mmio.c+ CC src/engine/interpreter/hostcall.c+ CC src/engine/interpreter/init.c+ CC src/isa/riscv32/system/intr.c+ CC src/isa/riscv32/system/mmu.c+ CC src/isa/riscv32/reg.c+ CC src/isa/riscv32/difftest/dut.c+ CC src/isa/riscv32/instr/decode.c+ CC src/isa/riscv32/logo.c+ CC src/isa/riscv32/init.c+ LD /home/vgalaxy/ics2021/nemu/build/riscv32-nemu-interpreter
下面是 Makefile
文件的内容,我们对其进行解读:
# Sanity checkifeq ($(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 menuconfigGUEST_ISA ?= $(call remove_quote,$(CONFIG_ISA))ENGINE ?= $(call remove_quote,$(CONFIG_ENGINE))NAME = $(GUEST_ISA)-nemu-$(ENGINE)
# Include all filelist.mk to merge file listsFILELIST_MK = $(shell find ./src -name "filelist.mk")include $(FILELIST_MK)
# Filter out directories and files in blacklist to obtain the final set of source filesDIRS-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 menuconfigCC = $(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 += $(CFLAGS_BUILD) -D__GUEST_ISA__=$(GUEST_ISA)LDFLAGS += $(CFLAGS_BUILD)
# Include rules for menuconfiginclude $(NEMU_HOME)/scripts/config.mk
ifdef CONFIG_TARGET_AMinclude $(AM_HOME)/MakefileLINKAGE += $(ARCHIVES)else# Include rules to build NEMUinclude $(NEMU_HOME)/scripts/native.mkendif
- 与配置系统进行关联
通过包含 nemu/include/config/auto.conf
,与 kconfig 生成的变量进行关联。
- 文件列表
在 nemu/src
及其子目录下存在一些名为 filelist.mk
的文件:
vgalaxy@vgalaxy-VirtualBox:/home/vgalaxy/ics2021/nemu$ find ./ -name filelist.mk./src/filelist.mk./src/device/filelist.mk./src/engine/filelist.mk./src/isa/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/scripts/build.mk
中定义,见 # Compilation patterns
后的部分:
.DEFAULT_GOAL = app
# Add necessary options if the target is a shared libraryifdef SHARESO = -soCFLAGS += -fPICLDFLAGS += -rdynamic -shared -fPICendif
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)
CC ?= gcc
# Compilation flagsCC := $(CC)LD := $(CC)INCLUDES = $(addprefix -I, $(INC_PATH))CFLAGS := -O2 -MMD -Wall -Werror $(INCLUDES) $(CFLAGS)LDFLAGS := -O2 $(LDFLAGS)
OBJS = $(SRCS:%.c=$(OBJ_DIR)/%.o)
# Compilation patterns$(OBJ_DIR)/%.o: %.c @echo + CC $< @mkdir -p $(dir $@) @$(CC) $(CFLAGS) -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
程序以“只输出命令但不执行”的方式强制构建目标。
我们截取最开始的一段输出分析,中间用空行分隔开:
echo + CC src/nemu-main.c
mkdir -p /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/
gcc -O2 -MMD -Wall -Werror -I/home/vgalaxy/ics2021/nemu/include -I/home/vgalaxy/ics2021/nemu/src/engine/interpreter -I/home/vgalaxy/ics2021/nemu/src/isa/riscv32/include -O2 -D__GUEST_ISA__=riscv32 -c -o /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/nemu-main.o src/nemu-main.c
/home/vgalaxy/ics2021/nemu/tools/fixdep/build/fixdep /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/nemu-main.d /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/nemu-main.o unused > /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/nemu-main.d.tmp
mv /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/nemu-main.d.tmp /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/nemu-main.d
对比可知,我们可以了解到 $<
为 src/nemu-main.c
,$@
为 /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/nemu-main.o
,$(CC)
为 gcc
等。
可以根据上述输出结果和 Makefile 反推 $(CFLAGS)
的值是如何形成的。
编译之后是一系列 git
操作,规则在 nemu/scripts/git.mk
中定义。下面是输出:
git add /home/vgalaxy/ics2021/nemu/.. -A --ignore-errors
while (test -e .git/index.lock); do sleep 0.1; done
(echo "> "compile"" && echo 201220000 && hostnamectl && uptime) | git commit -F - -q --author='tracer-ics2021 <tracer@njuics.org>' --no-verify --allow-empty
sync
最后是链接操作:
echo + LD /home/vgalaxy/ics2021/nemu/build/riscv32-nemu-interpreter
gcc -o /home/vgalaxy/ics2021/nemu/build/riscv32-nemu-interpreter /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/nemu-main.o /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/cpu/difftest/dut.o /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/cpu/cpu-exec.o /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/monitor/monitor.o /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/monitor/sdb/watchpoint.o /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/monitor/sdb/expr.o /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/monitor/sdb/sdb.o /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/utils/log.o /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/utils/timer.o /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/utils/state.o /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/utils/rand.o /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/memory/paddr.o /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/memory/vaddr.o /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/device/io/port-io.o /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/device/io/map.o /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/device/io/mmio.o /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/engine/interpreter/hostcall.o /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/engine/interpreter/init.o /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/isa/riscv32/system/intr.o /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/isa/riscv32/system/mmu.o /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/isa/riscv32/reg.o /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/isa/riscv32/difftest/dut.o /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/isa/riscv32/instr/decode.o /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/isa/riscv32/logo.o /home/vgalaxy/ics2021/nemu/build/obj-riscv32-nemu-interpreter/src/isa/riscv32/init.o -O2 -O2 -lreadline -ldl -pie
运行与调试
To run NEMU, type
$ make run
To debug NEMU with gdb, type
$ make gdb
submit
终于收到了 jyy 的 TOKEN。环境变量在 ~/.bashrc
中设置,另外还需要修改 nemu/scripts/git.mk
中的学号和姓名,并安装 curl 🤣。