Lab_1:练习一——理解通过make生成执行文件的过程
参考网站:
https://www.cnblogs.com/chaunceyctx/p/7188779.html
https://cloud.tencent.com/developer/article/1415004
https://www.runoob.com/linux/linux-comm-dd.html
https://www.jianshu.com/p/49c6433fd6d2
https://www.cnblogs.com/cyx-b/p/11750020.html
练习1:理解通过make生成执行文件的过程。(要求在报告中写出对下述问题的回答)
列出本实验各练习中对应的OS原理的知识点,并说明本实验中的实现部分如何对应和体现了原理中的基本概念和关键知识点。
在此练习中,大家需要通过静态分析代码来了解:
- 操作系统镜像文件ucore.img是如何一步一步生成的?(需要比较详细地解释Makefile中每一条相关命令和命令参数的含义,以及说明命令导致的结果)
- 一个被系统认为是符合规范的硬盘主引导扇区的特征是什么
一、操作步骤
1、进入/moocos/ucore_lab/labcodes_answer/lab1_result目录
cd ./moocos/ucore_lab/labcodes_answer/lab1_result
2、执行make qemu
Ctrl+C退出
3、make clean
清除上次的make命令所产生的object文件(后缀为“.o”的文件)及可执行文件
4、查看Makefile
cat Makefile
PROJ := challenge
EMPTY :=
SPACE := $(EMPTY) $(EMPTY)
SLASH := / V := @
#need llvm/cang-3.5+
#USELLVM :=
# try to infer the correct GCCPREFX
ifndef GCCPREFIX
GCCPREFIX := $(shell if i386-elf-objdump -i >& | grep '^elf32-i386$$' >/dev/null >&; \
then echo 'i386-elf-'; \
elif objdump -i >& | grep 'elf32-i386' >/dev/null >&; \
then echo ''; \
else echo "***" >&; \
echo "*** Error: Couldn't find an i386-elf version of GCC/binutils." >&; \
echo "*** Is the directory with i386-elf-gcc in your PATH?" >&; \
echo "*** If your i386-elf toolchain is installed with a command" >&; \
echo "*** prefix other than 'i386-elf-', set your GCCPREFIX" >&; \
echo "*** environment variable to that prefix and run 'make' again." >&; \
echo "*** To turn off this error, run 'gmake GCCPREFIX= ...'." >&; \
echo "***" >&; exit ; fi)
endif # 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 "***" >&; \
echo "*** Error: Couldn't find a working QEMU executable." >&; \
echo "*** Is the directory containing the qemu binary in your PATH" >&; \
echo "***" >&; exit ; fi)
endif # eliminate default suffix rules
.SUFFIXES: .c .S .h # delete target files if there is an error (or make is interrupted)
.DELETE_ON_ERROR: # define compiler and flags
ifndef USELLVM
HOSTCC := gcc
HOSTCFLAGS := -g -Wall -O2
CC := $(GCCPREFIX)gcc
CFLAGS := -march=i686 -fno-builtin -fno-PIC -Wall -ggdb -m32 -gstabs -nostdinc $(DEFS)
CFLAGS += $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null >& && echo -fno-stack-protector)
else
HOSTCC := clang
HOSTCFLAGS := -g -Wall -O2
CC := clang
CFLAGS := -march=i686 -fno-builtin -fno-PIC -Wall -g -m32 -nostdinc $(DEFS)
CFLAGS += $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null >& && echo -fno-stack-protector)
endif CTYPE := c S LD := $(GCCPREFIX)ld
LDFLAGS := -m $(shell $(LD) -V | grep elf_i386 >/dev/null | head -n )
LDFLAGS += -nostdlib OBJCOPY := $(GCCPREFIX)objcopy
OBJDUMP := $(GCCPREFIX)objdump 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 := include tools/function.mk listf_cc = $(call listf,$(),$(CTYPE)) # for cc
add_files_cc = $(call add_files,$(),$(CC),$(CFLAGS) $(),$(),$())
create_target_cc = $(call create_target,$(),$(),$(),$(CC),$(CFLAGS)) # for hostcc
add_files_host = $(call add_files,$(),$(HOSTCC),$(HOSTCFLAGS),$(),$())
create_target_host = $(call create_target,$(),$(),$(),$(HOSTCC),$(HOSTCFLAGS)) cgtype = $(patsubst %.$(),%.$(),$())
objfile = $(call toobj,$())
asmfile = $(call cgtype,$(call toobj,$()),o,asm)
outfile = $(call cgtype,$(call toobj,$()),o,out)
symfile = $(call cgtype,$(call toobj,$()),o,sym) # for match pattern
match = $(shell echo $() | $(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 = $(call totarget,kernel) $(kernel): tools/kernel.ld $(kernel): $(KOBJS)
@echo + ld $@
$(V)$(LD) $(LDFLAGS) -T tools/kernel.ld -o $@ $(KOBJS)
@$(OBJDUMP) -S $@ > $(call asmfile,kernel)
@$(OBJDUMP) -t $@ | $(SED) '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $(call symfile,kernel) $(call create_target,kernel) # ------------------------------------------------------------------- # create bootblock
bootfiles = $(call listf_cc,boot)
$(foreach f,$(bootfiles),$(call cc_compile,$(f),$(CC),$(CFLAGS) -Os -nostdinc)) bootblock = $(call totarget,bootblock) $(bootblock): $(call toobj,$(bootfiles)) | $(call totarget,sign)
@echo + ld $@
$(V)$(LD) $(LDFLAGS) -N -e start -Ttext 0x7C00 $^ -o $(call toobj,bootblock)
@$(OBJDUMP) -S $(call objfile,bootblock) > $(call asmfile,bootblock)
@$(OBJCOPY) -S -O binary $(call objfile,bootblock) $(call outfile,bootblock)
@$(call totarget,sign) $(call outfile,bootblock) $(bootblock) $(call create_target,bootblock) # ------------------------------------------------------------------- # create 'sign' tools
$(call add_files_host,tools/sign.c,sign,sign)
$(call create_target_host,sign,sign) # ------------------------------------------------------------------- # create ucore.img
UCOREIMG := $(call totarget,ucore.img) $(UCOREIMG): $(kernel) $(bootblock)
$(V)dd if=/dev/zero of=$@ count=
$(V)dd if=$(bootblock) of=$@ conv=notrunc
$(V)dd if=$(kernel) of=$@ seek= conv=notrunc $(call create_target,ucore.img) # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> $(call finish_all) IGNORE_ALLDEPS = clean \
dist-clean \
grade \
touch \
print-.+ \
handin ifeq ($(call match,$(MAKECMDGOALS),$(IGNORE_ALLDEPS)),)
-include $(ALLDEPS)
endif # files for grade script TARGETS: $(TARGETS) .DEFAULT_GOAL := TARGETS .PHONY: qemu qemu-nox debug debug-nox
qemu-mon: $(UCOREIMG)
$(V)$(QEMU) -no-reboot -monitor stdio -hda $< -serial null
qemu: $(UCOREIMG)
$(V)$(QEMU) -no-reboot -parallel stdio -hda $< -serial null
log: $(UCOREIMG)
$(V)$(QEMU) -no-reboot -d int,cpu_reset -D q.log -parallel stdio -hda $< -serial null
qemu-nox: $(UCOREIMG)
$(V)$(QEMU) -no-reboot -serial mon:stdio -hda $< -nographic
TERMINAL :=gnome-terminal
debug: $(UCOREIMG)
$(V)$(QEMU) -S -s -parallel stdio -hda $< -serial null &
$(V)sleep
$(V)$(TERMINAL) -e "gdb -q -tui -x tools/gdbinit" debug-nox: $(UCOREIMG)
$(V)$(QEMU) -S -s -serial mon:stdio -hda $< -nographic &
$(V)sleep
$(V)$(TERMINAL) -e "gdb -q -x tools/gdbinit" .PHONY: grade touch GRADE_GDB_IN := .gdb.in
GRADE_QEMU_OUT := .qemu.out
HANDIN := proj$(PROJ)-handin.tar.gz TOUCH_FILES := kern/trap/trap.c MAKEOPTS := --quiet --no-print-directory grade:
$(V)$(MAKE) $(MAKEOPTS) clean
$(V)$(SH) tools/grade.sh touch:
$(V)$(foreach f,$(TOUCH_FILES),$(TOUCH) $(f)) print-%:
@echo $($(shell echo $(patsubst print-%,%,$@) | $(TR) [a-z] [A-Z])) .PHONY: clean dist-clean handin packall tags
clean:
$(V)$(RM) $(GRADE_GDB_IN) $(GRADE_QEMU_OUT) cscope* tags
-$(RM) -r $(OBJDIR) $(BINDIR) dist-clean: clean
-$(RM) $(HANDIN) handin: packall
@echo Please visit http://learn.tsinghua.edu.cn and upload $(HANDIN). Thanks! packall: clean
@$(RM) -f $(HANDIN)
@tar -czf $(HANDIN) `find . -type f -o -type d | grep -v '^\.*$$' | grep -vF '$(HANDIN)'` tags:
@echo TAGS ALL
$(V)rm -f cscope.files cscope.in.out cscope.out cscope.po.out tags
$(V)find . -type f -name "*.[chS]" >cscope.files
$(V)cscope -bq
$(V)ctags -L cscope.files
Makefile文件的内容
5、输入make V=
查看make执行的命令
moocos-> make V=
+ cc kern/init/init.c
gcc -Ikern/init/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/init/init.c -o obj/kern/init/init.o
+ cc kern/libs/readline.c
gcc -Ikern/libs/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/libs/readline.c -o obj/kern/libs/readline.o
+ cc kern/libs/stdio.c
gcc -Ikern/libs/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/libs/stdio.c -o obj/kern/libs/stdio.o
+ cc kern/debug/kdebug.c
gcc -Ikern/debug/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/debug/kdebug.c -o obj/kern/debug/kdebug.o
+ cc kern/debug/kmonitor.c
gcc -Ikern/debug/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/debug/kmonitor.c -o obj/kern/debug/kmonitor.o
+ cc kern/debug/panic.c
gcc -Ikern/debug/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/debug/panic.c -o obj/kern/debug/panic.o
+ cc kern/driver/clock.c
gcc -Ikern/driver/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/driver/clock.c -o obj/kern/driver/clock.o
+ cc kern/driver/console.c
gcc -Ikern/driver/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/driver/console.c -o obj/kern/driver/console.o
+ cc kern/driver/intr.c
gcc -Ikern/driver/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/driver/intr.c -o obj/kern/driver/intr.o
+ cc kern/driver/picirq.c
gcc -Ikern/driver/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/driver/picirq.c -o obj/kern/driver/picirq.o
+ cc kern/trap/trap.c
gcc -Ikern/trap/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/trap/trap.c -o obj/kern/trap/trap.o
+ cc kern/trap/trapentry.S
gcc -Ikern/trap/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/trap/trapentry.S -o obj/kern/trap/trapentry.o
+ cc kern/trap/vectors.S
gcc -Ikern/trap/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/trap/vectors.S -o obj/kern/trap/vectors.o
+ cc kern/mm/pmm.c
gcc -Ikern/mm/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/mm/pmm.c -o obj/kern/mm/pmm.o
+ cc libs/printfmt.c
gcc -Ilibs/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -c libs/printfmt.c -o obj/libs/printfmt.o
+ cc libs/string.c
gcc -Ilibs/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -c libs/string.c -o obj/libs/string.o
+ ld bin/kernel
ld -m elf_i386 -nostdlib -T tools/kernel.ld -o bin/kernel obj/kern/init/init.o obj/kern/libs/readline.o obj/kern/libs/stdio.o obj/kern/debug/kdebug.o obj/kern/debug/kmonitor.o obj/kern/debug/panic.o obj/kern/driver/clock.o obj/kern/driver/console.o obj/kern/driver/intr.o obj/kern/driver/picirq.o obj/kern/trap/trap.o obj/kern/trap/trapentry.o obj/kern/trap/vectors.o obj/kern/mm/pmm.o obj/libs/printfmt.o obj/libs/string.o
+ cc boot/bootasm.S
gcc -Iboot/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Os -nostdinc -c boot/bootasm.S -o obj/boot/bootasm.o
+ cc boot/bootmain.c
gcc -Iboot/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Os -nostdinc -c boot/bootmain.c -o obj/boot/bootmain.o
+ cc tools/sign.c
gcc -Itools/ -g -Wall -O2 -c tools/sign.c -o obj/sign/tools/sign.o
gcc -g -Wall -O2 obj/sign/tools/sign.o -o bin/sign
+ ld bin/bootblock
ld -m elf_i386 -nostdlib -N -e start -Ttext 0x7C00 obj/boot/bootasm.o obj/boot/bootmain.o -o obj/bootblock.o
'obj/bootblock.out' size: bytes
build bytes boot sector: 'bin/bootblock' success!
dd if=/dev/zero of=bin/ucore.img count=
+ records in
+ records out
bytes (5.1 MB) copied, 0.0601803 s, 85.1 MB/s
dd if=bin/bootblock of=bin/ucore.img conv=notrunc
+ records in
+ records out
bytes ( B) copied, 0.000141238 s, 3.6 MB/s
dd if=bin/kernel of=bin/ucore.img seek= conv=notrunc
+ records in
+ records out
bytes ( kB) copied, 0.00356787 s, 21.0 MB/s
二、问题一的解答
问题:操作系统镜像文件ucore.img是如何一步一步生成的?(需要比较详细地解释Makefile中每一条相关命令和命令参数的含义,以及说明命令导致的结果)
答:
(1)make V=
1、总体概述
①首先把C的源代码编译为目标文件(.o文件)
比方说下面这样:
+ cc kern/init/init.c
gcc -Ikern/init/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/init/init.c -o obj/kern/init/init.o
+ cc kern/libs/readline.c
gcc -Ikern/libs/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/libs/readline.c -o obj/kern/libs/readline.o
②ld命令将这些目标文件转变成可执行文件
比如像下面这样的:
+ ld bin/kernel
ld -m elf_i386 -nostdlib -T tools/kernel.ld -o bin/kernel obj/kern/init/init.o obj/kern/libs/readline.o obj/kern/libs/stdio.o obj/kern/debug/kdebug.o obj/kern/debug/kmonitor.o obj/kern/debug/panic.o obj/kern/driver/clock.o obj/kern/driver/console.o obj/kern/driver/intr.o obj/kern/driver/picirq.o obj/kern/trap/trap.o obj/kern/trap/trapentry.o obj/kern/trap/vectors.o obj/kern/mm/pmm.o obj/libs/printfmt.o obj/libs/string.o
③dd命令把bootloader放到ucore.img.count的虚拟硬盘中
dd if=/dev/zero of=bin/ucore.img count=
+ records in
+ records out
bytes (5.1 MB) copied, 0.0601803 s, 85.1 MB/s
dd if=bin/bootblock of=bin/ucore.img conv=notrunc
+ records in
+ records out
bytes ( B) copied, 0.000141238 s, 3.6 MB/s
dd if=bin/kernel of=bin/ucore.img seek= conv=notrunc
+ records in
+ records out
bytes ( kB) copied, 0.00356787 s, 21.0 MB/s
④还生成了两个软件,一个是bootloader,另一个是kernel
2、具体分析
需要生成ucore.img首先需要生成bootblock,
而生成bootblock需要先生成bootmain.o和bootasm.o还有sign
说明:
ld:ld命令是二进制工具集GNU Binutils的一员,是GNU链接器,用于将目标文件与库链接为可执行程序或库文件
dd:用指定大小的块拷贝一个文件,并在拷贝的同时进行指定的转换。
-b <input-format>:指定目标代码输入文件的格式
-Bstatic:只使用静态库
-Bdynamic:只使用动态库
-Bsymbolic:把引用捆绑到共享库中的全局符号
-c <MRI-commandfile>,--mri-script=<MRI-commandfile>:为与MRI链接器兼容,ld接受由MRI命令语言编写的脚本文件
--cref:创建跨引用表
-d,-dc,-dp:即使指定了可重定位的输出文件(使用-r),也会为公共符号分配空间。脚本命令“FORCE_COMMON_ALLOCATION”具有相同的效果
-defsym:在输出文件中创建指定的全局符号
-demangle:在错误消息中还原符号名称
-e <entry>:使用指定的符号作为程序的初始执行点
-E,--export-dynamic:对于ELF格式文件,创建动态链接的可执行文件时,把所有符号添加到动态符号表
-f <name>,--auxiliary=<name>:对于ELF格式共享对象,设置 DT_AUXILIARY 名称
-F <name>,--filter=<name>:对于ELF格式共享对象,设置 DT_FILTER 名称。这告诉动态链接器,正在创建的共享对象的符号表应该用作共享对象名称的符号表的筛选器。
-g:被忽略。用于提供和其他工具的兼容性
-h:对于ELF格式共享对象,设置 DT_SONAME 名称
-I<file>,--dynamic-linker=<file>:指定动态链接器。这仅在生成动态链接的ELF可执行文件时才有意义。默认的动态链接器通常是正确的,除非您知道正在做什么,否则不要使用该选项。
-l <namespec>,--library=<namespec>:把指定的库文件添加到要链接的文件清单
-L <searchdir>,--library-path=searchdir:把指定的路径添加添加到搜索库的目录清单
-M,--print-map:显示链接映射,用于诊断目的
-Map=<mapfile>: 将链接映射输出到指定的文件
-m <emulation>: 模拟指定的链接器
-N,--omagic: 指定读取/写入文本和数据段
-n,--nmagic: 关闭节的页面对齐,并禁用对共享库的链接。如果输出格式支持Unix样式的幻数,则将输出标记为"NMAGIC"
-noinhibit-exec:生成输出文件,即使出现非致命链接错误。通常,如果链接器在链接过程中遇到错误,它将不会生成输出文件。
-no-keep-memory:ld通常在内存中缓存输入文件的符号表来优化内存使用速度。此选项告诉ld不要缓存符号表。当链接大型可执行文件时,如果ld耗尽内存空间,则可能需要使用该选项
-O <level>:对于非零的优化等级,ld将优化输出。此操作会比较耗时,应该在生成最终的结果时使用。
-o <output>,--output=<output>:指定输出文件的名称
-oformat=<output-format>:指定输出文件的二进制格式
-R <filename>,--just-symbols=<filename>:从指定的文件读取符号名称和地址
-r,--relocatable:生成可重定位的输出(称为部分连接)
-rpath=<dir>:把指定的目录添加到运行时库搜索路径
-rpath-link=<dir>:指定搜索运行时共享库的目录
-S,--strip-debug:忽略来自输出文件的调试器符号信息
-s,--strip-all:忽略来自输出文件的所有符号信息
-shared,-Bshareable:创建共享库
-split-by-file[=size]:为每个目标文件在输出文件中创建额外的段大小达到size。size默认为1
-split-by-reloc[=count]:按照指定的长度在输出文件中创建额外的段
--section-start=<sectionname>=<org>:在输出文件中指定的地址定位指定的段
-T <scriptfile>,--script=<scriptfile>:使用scriptfile作为链接器脚本。此脚本将替换ld的默认链接器脚本(而不是添加到其中),因此脚本必须指定输出文件所需的所有内容。如果当前目录中不存在脚本文件,“ld”会在-L选项指定的目录中查找
-Ttext=<org>:使用指定的地址作为文本段的起始点
-Tdata=<org>:使用指定的地址作为数据段的起始点
-Tbss=<org>:使用指定的地址作为bss段的起始点
-t,--trace:在处理输入文件时显示它们的名称
-u <symbol>,--undefined=<symbol>:强制指定符号在输出文件中作为未定义符号
-v,-V,--version:显示ld版本号
-warn-common:当一个通用符号和另一个通用符号结合时发出警告
-warn-constructors:如果没有使用任何全局构造器,则发出警告
-warn-once:对于每个未定义的符号只发出一次警告
-warn-section-align:如果为了对齐而改动了输出段地址,则发出警告
--whole-archive:对于指定的存档文件,在存档中包含所有文件
-X,--discard-locals:删除所有本地临时符号
-x,--discard-al:删除所有本地符号
ld命令用法
Linux dd命令用于读取、转换并输出数据。
dd可从标准输入或文件中读取数据,根据指定的格式来转换数据,再输出到文件、设备或标准输出。
参数说明:
if=文件名:输入文件名,默认为标准输入。即指定源文件。
of=文件名:输出文件名,默认为标准输出。即指定目的文件。
ibs=bytes:一次读入bytes个字节,即指定一个块大小为bytes个字节。
obs=bytes:一次输出bytes个字节,即指定一个块大小为bytes个字节。
bs=bytes:同时设置读入/输出的块大小为bytes个字节。
cbs=bytes:一次转换bytes个字节,即指定转换缓冲区大小。
skip=blocks:从输入文件开头跳过blocks个块后再开始复制。
seek=blocks:从输出文件开头跳过blocks个块后再开始复制。
count=blocks:仅拷贝blocks个块,块大小等于ibs指定的字节数。
conv=<关键字>,关键字可以有以下11种:
conversion:用指定的参数转换文件。
ascii:转换ebcdic为ascii
ebcdic:转换ascii为ebcdic
ibm:转换ascii为alternate ebcdic
block:把每一行转换为长度为cbs,不足部分用空格填充
unblock:使每一行的长度都为cbs,不足部分用空格填充
lcase:把大写字符转换为小写字符
ucase:把小写字符转换为大写字符
swab:交换输入的每对字节
noerror:出错时不停止
notrunc:不截短输出文件
sync:将每个输入块填充到ibs个字节,不足部分用空(NUL)字符补齐。
--help:显示帮助信息
--version:显示版本信息
dd命令用法
+ ld bin/kernel
ld -m elf_i386 -nostdlib -T tools/kernel.ld -o bin/kernel obj/kern/init/init.o obj/kern/libs/readline.o obj/kern/libs/stdio.o obj/kern/debug/kdebug.o obj/kern/debug/kmonitor.o obj/kern/debug/panic.o obj/kern/driver/clock.o obj/kern/driver/console.o obj/kern/driver/intr.o obj/kern/driver/picirq.o obj/kern/trap/trap.o obj/kern/trap/trapentry.o obj/kern/trap/vectors.o obj/kern/mm/pmm.o obj/libs/printfmt.o obj/libs/string.o
ld将.o文件整合成可执行文件kernel,而这些.o文件是Makefile文件通过命令使用gcc把有关kernel的.c文件编译生成
+ ld bin/bootblock
ld -m elf_i386 -nostdlib -N -e start -Ttext 0x7C00 obj/boot/bootasm.o obj/boot/bootmain.o -o obj/bootblock.o
'obj/bootblock.out' size: bytes
build bytes boot sector: 'bin/bootblock' success!
同理ld也将.o文件整合成可执行文件bootblock,大小为488字节,但还是放入512字节扇区中,但是,而这些.o文件也是Makefile文件通过命令使用gcc把有关bootloader的.c文件编译生成
dd if=/dev/zero of=bin/ucore.img count=
+ records in
+ records out
bytes (5.1 MB) copied, 0.0601803 s, 85.1 MB/s
创建10000块扇区,每个扇区512字节,制成ucore.img虚拟磁盘
dd if=bin/bootblock of=bin/ucore.img conv=notrunc
+ records in
+ records out
bytes ( B) copied, 0.000141238 s, 3.6 MB/s
将bootblock存到ucore.img虚拟磁盘的第一块
dd if=bin/kernel of=bin/ucore.img seek= conv=notrunc
+ records in
+ records out
bytes ( kB) copied, 0.00356787 s, 21.0 MB/s
将kernel存到ucore.img虚拟磁盘的第二块及之后几块,注意seek1,最终ucore.img虚拟磁盘制作完成
(2)Makefile
Makefile文件中,可以看到对应的生成ucore.img的过程及相应语句如下:
注:Makefile文件在~/moocos/ucore_lab/labcodes_answer/lab1_result中
打开方式为cat Makefile等
Makefile中的M一定要大写
Makefile中生成ucore.img的代码为
# create ucore.img
UCOREIMG := $(call totarget,ucore.img) $(UCOREIMG): $(kernel) $(bootblock)
$(V)dd if=/dev/zero of=$@ count=
$(V)dd if=$(bootblock) of=$@ conv=notrunc
$(V)dd if=$(kernel) of=$@ seek= conv=notrunc $(call create_target,ucore.img)
逐条分析:
$(kernel)
:生成kernel。需要以下两步
编译kern/目录下的C程序,生成kernel需要的.o文件
$(call add_files_cc,$(call listf_cc,$(KSRCDIR)),kernel,$(KCFLAGS))
实际执行的命令为:
+ cc kern/init/init.c
gcc -Ikern/init/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/init/init.c -o obj/kern/init/init.o
+ cc kern/libs/stdio.c
gcc -Ikern/libs/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/libs/stdio.c -o obj/kern/libs/stdio.o
+ cc kern/libs/readline.c
gcc -Ikern/libs/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/libs/readline.c -o obj/kern/libs/readline.o
+ cc kern/debug/panic.c
gcc -Ikern/debug/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/debug/panic.c -o obj/kern/debug/panic.o
+ cc kern/debug/kdebug.c
gcc -Ikern/debug/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/debug/kdebug.c -o obj/kern/debug/kdebug.o
+ cc kern/debug/kmonitor.c
gcc -Ikern/debug/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/debug/kmonitor.c -o obj/kern/debug/kmonitor.o
+ cc kern/driver/clock.c
gcc -Ikern/driver/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/driver/clock.c -o obj/kern/driver/clock.o
+ cc kern/driver/console.c
gcc -Ikern/driver/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/driver/console.c -o obj/kern/driver/console.o
+ cc kern/driver/picirq.c
gcc -Ikern/driver/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/driver/picirq.c -o obj/kern/driver/picirq.o
+ cc kern/driver/intr.c
gcc -Ikern/driver/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/driver/intr.c -o obj/kern/driver/intr.o
+ cc kern/trap/trap.c
gcc -Ikern/trap/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/trap/trap.c -o obj/kern/trap/trap.o
+ cc kern/trap/vectors.S
gcc -Ikern/trap/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/trap/vectors.S -o obj/kern/trap/vectors.o
+ cc kern/trap/trapentry.S
gcc -Ikern/trap/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/trap/trapentry.S -o obj/kern/trap/trapentry.o
+ cc kern/mm/pmm.c
gcc -Ikern/mm/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/mm/pmm.c -o obj/kern/mm/pmm.o
+ cc libs/string.c
gcc -Ilibs/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -c libs/string.c -o obj/libs/string.o
+ cc libs/printfmt.c
gcc -Ilibs/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -c libs/printfmt.c -o obj/libs/printfmt.o
链接这些.o文件,生成kernel
# create kernel target
kernel = $(call totarget,kernel) $(kernel): tools/kernel.ld $(kernel): $(KOBJS)
@echo + ld $@
$(V)$(LD) $(LDFLAGS) -T tools/kernel.ld -o $@ $(KOBJS)
@$(OBJDUMP) -S $@ > $(call asmfile,kernel)
@$(OBJDUMP) -t $@ | $(SED) '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $(call symfile,kernel) $(call create_target,kernel)
执行的实际命令为:
+ ld bin/kernel
ld -m elf_i386 -nostdlib -T tools/kernel.ld -o bin/kernel obj/kern/init/init.o obj/kern/libs/stdio.o obj/kern/libs/readline.o obj/kern/debug/panic.o obj/kern/debug/kdebug.o obj/kern/debug/kmonitor.o obj/kern/driver/clock.o obj/kern/driver/console.o obj/kern/driver/picirq.o obj/kern/driver/intr.o obj/kern/trap/trap.o obj/kern/trap/vectors.o obj/kern/trap/trapentry.o obj/kern/mm/pmm.o obj/libs/string.o obj/libs/printfmt.o
$(bootblock)
:生成binblock。需要以下三步:
生成bootmain.o和bootasm.o
bootfiles = $(call listf_cc,boot) $(foreach f,$(bootfiles),$(call cc_compile,$(f),$(CC),$(CFLAGS) -Os -nostdinc))
执行的实际命令为
+ cc boot/bootasm.S
gcc -Iboot/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Os -nostdinc -c boot/bootasm.S -o obj/boot/bootasm.o
+ cc boot/bootmain.c
gcc -Iboot/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Os -nostdinc -c boot/bootmain.c -o obj/boot/bootmain.o
编译tools/sign.c,生成sign.o
# create 'sign' tools
$(call add_files_host,tools/sign.c,sign,sign)
$(call create_target_host,sign,sign)
执行的实际命令为:
+ cc tools/sign.c
gcc -Itools/ -g -Wall -O2 -c tools/sign.c -o obj/sign/tools/sign.o
gcc -g -Wall -O2 obj/sign/tools/sign.o -o bin/sign
链接以上的.o文件
bootblock = $(call totarget,bootblock) $(bootblock): $(call toobj,$(bootfiles)) | $(call totarget,sign)
@echo + ld $@
$(V)$(LD) $(LDFLAGS) -N -e start -Ttext 0x7C00 $^ -o $(call toobj,bootblock)
@$(OBJDUMP) -S $(call objfile,bootblock) > $(call asmfile,bootblock)
@$(OBJCOPY) -S -O binary $(call objfile,bootblock) $(call outfile,bootblock)
@$(call totarget,sign) $(call outfile,bootblock) $(bootblock) $(call create_target,bootblock)
执行的实际命令为:
+ ld bin/bootblock
ld -m elf_i386 -nostdlib -N -e start -Ttext 0x7C00 obj/boot/bootasm.o obj/boot/bootmain.o -o obj/bootblock.o
$(V)dd if=/dev/zero of=$@ count=10000
:生成一个有10000个块的文件,每个块默认512字节,用0填充。
执行的实际命令为:
dd if=/dev/zero of=bin/ucore.img count=10000
$(V)dd if=$(bootblock) of=$@ conv=notrunc
:把bootblock中的内容写到第一个块。
执行的实际命令为:
dd if=bin/bootblock of=bin/ucore.img conv=notrunc
$(V)dd if=$(kernel) of=$@ seek=1 conv=notrunc
:从第二个块开始写kernel中的内容。
执行的实际命令为:
dd if=bin/kernel of=bin/ucore.img seek=1 conv=notrunc
三、问题二的解答
引导扇区的大小为512字节,最后两个字节为标志性结束字节0x55,0xAA,做完这样的检查才能认为是符合规范的磁盘主引导扇区。
查看sign.c文件的代码
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h> int
main(int argc, char *argv[]) {
struct stat st;
if (argc != ) {
fprintf(stderr, "Usage: <input filename> <output filename>\n");
return -;
}
if (stat(argv[], &st) != ) {
fprintf(stderr, "Error opening file '%s': %s\n", argv[], strerror(errno));
return -;
}
printf("'%s' size: %lld bytes\n", argv[], (long long)st.st_size);
if (st.st_size > ) {
fprintf(stderr, "%lld >> 510!!\n", (long long)st.st_size);
return -;
}
char buf[];
memset(buf, , sizeof(buf));
FILE *ifp = fopen(argv[], "rb");
int size = fread(buf, , st.st_size, ifp);
if (size != st.st_size) {
fprintf(stderr, "read '%s' error, size is %d.\n", argv[], size);
return -;
}
fclose(ifp);
buf[] = 0x55;
buf[] = 0xAA;
FILE *ofp = fopen(argv[], "wb+");
size = fwrite(buf, , , ofp);
if (size != ) {
fprintf(stderr, "write '%s' error, size is %d.\n", argv[], size);
return -;
}
fclose(ofp);
printf("build 512 bytes boot sector: '%s' success!\n", argv[]);
return ;
}
35行到38行的代码说明sign.c文件是会作检查的
if (size != st.st_size) {
fprintf(stderr, "read '%s' error, size is %d.\n", argv[], size);
return -;
}
Lab_1:练习一——理解通过make生成执行文件的过程的更多相关文章
- Lab_1:练习1——理解通过make生成执行文件的过程
lab_0 清华大学ucore实验环境配置详细步骤!(小白入) lab_1 清华大学ucore bootload启动ucore os(预备知识) Lab_1:练习1--理解通过make生成执行文件的过 ...
- JNI初级:android studio生成so文件详细过程
本文主要参考blog:http://blog.csdn.net/jkan2001/article/details/54316375 下面是本人结合blog生成so包过程中遇到一些问题和解决方法 (1) ...
- 带您理解SQLSERVER是如何执行一个查询的
原文地址:http://www.cnblogs.com/lyhabc/p/3367274.html 看这篇文章之前,阁下可以先看一下下面的文章 SQLSERVER独特的任务调度算法"SQLO ...
- WF4.0以上使用代码完整自定义动态生成执行工作流Xaml文件
给大家分享一下,如何完全使用代码自定义的创建生成工作流文件(用代码创建Xaml文件),并且动态加载运行所生成的工作流. 工作流生成后 在Xaml文件里的主要节点如下: 输入输出参数 <x:Mem ...
- 10分钟理解JS引擎的执行机制
首先,请牢记2点: (1) JS是单线程语言 (2) JS的Event Loop是JS的执行机制.深入了解JS的执行,就等于深入了解JS里的event loop 1.灵魂三问 (1) JS为什么是单线 ...
- 为准确生成执行计划更新统计信息-analyze与dbms_stats
如果我们想让CBO利用合理利用数据的统计信息,正确判断执行任何SQL查询时的最快途径,需要及时的使用analyze命令或者dbms_stats重新统计数据的统计信息. 例如索引跳跃式扫描(INDEX ...
- Sphinx/Coreseek 4.1 执行 buildconf.sh 报错,无法生成configure文件
参考的网址: http://blog.csdn.net/jcjc918/article/details/39032689 错误现象: 执行 buildconf.sh 报错,无法生成configure文 ...
- 随机数生成 && 生成执行锁
生成随机数列: openssl rand -base64 uuidgen echo $RANDOM | md5sum echo $RANDOM | sha256sum 随机小写10个字母 随机数: [ ...
- VS2010 打包生成exe文件后 执行安装文件出现 TODO:<文件说明>已停止工作并已关闭
一.VS2010 打包生成exe文件后 执行安装文件出现 TODO:<文件说明>已停止工作并已关闭 TODO: <文件说明>已停止工作 原因: 打包的时候在文件系统中建立了 ...
随机推荐
- 转:int整数除以int整数一定得到的是int整数(易忽视)
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/u014053368/article/de ...
- C++ new和malloc的区别
1.new关键字是C++中的一部分,malloc是由C库提供的函数: 2.new是以具体类型为单位进行内存分配,malloc只能以字节为单位进行内存分配: 3.new在申请单个类型变量时可进行初始化, ...
- Spring Boot 2.x基础教程:构建RESTful API与单元测试
首先,回顾并详细说明一下在快速入门中使用的@Controller.@RestController.@RequestMapping注解.如果您对Spring MVC不熟悉并且还没有尝试过快速入门案例,建 ...
- 23种设计模式之模板方法(Template Pattern)
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤 AbstractClass:抽象类.用来定义算法骨架和原语操作,在这个类里 ...
- Asteroids POJ - 3041 二分图最小点覆盖
Asteroids POJ - 3041 Bessie wants to navigate her spaceship through a dangerous asteroid field in ...
- TP5安装workerman版本的坑
今天想在TP5上安装workerman,用于个人学习,然后悲剧的是,第一步就卡住了,根据手册里说的首先通过composer安装 composer require topthink/think-work ...
- ng执行css3动画
在组件html中 <div> <aside id="aside">侧边栏</aside> <div class="content ...
- [docker swarm] 从单容器走向负载均衡部署
背景 之前写过<<docker-compose真香>> 和<docker-compose.docker stack前世今生>两篇博客, 回顾一下思路: ① dock ...
- spring-boot-plus XSS跨站脚本攻击处理
XSS跨站脚本攻击处理 XSS:Cross Site Scripting 跨站脚本攻击(XSS),是目前最普遍的Web应用安全漏洞.这类漏洞能够使得攻击者嵌入恶意脚本代码到正常用户会访问到的页面中,当 ...
- 一文掌握在Word中快速编写公式
在使用Word编写文章时,总会遇到书写数学公式的情况.使用Word的公式输入工具需要频繁地使用鼠标,因而编写公式会显得繁琐麻烦,那么有什么办法可以优雅地在Word中书写公式呢?其实Word早在Word ...