參考網站:html
https://www.cnblogs.com/chaunceyctx/p/7188779.htmllinux
https://cloud.tencent.com/developer/article/1415004shell
https://www.runoob.com/linux/linux-comm-dd.html緩存
https://www.jianshu.com/p/49c6433fd6d2ide
https://www.cnblogs.com/cyx-b/p/11750020.html工具
練習1:理解經過make生成執行文件的過程。(要求在報告中寫出對下述問題的回答)優化
列出本實驗各練習中對應的OS原理的知識點,並說明本實驗中的實現部分如何對應和體現了原理中的基本概念和關鍵知識點。網站
在此練習中,你們須要經過靜態分析代碼來了解:ui
1、操做步驟this
一、進入/moocos/ucore_lab/labcodes_answer/lab1_result目錄
cd ./moocos/ucore_lab/labcodes_answer/lab1_result
二、執行make qemu
Ctrl+C退出
三、make clean
清除上次的make命令所產生的object文件(後綴爲「.o」的文件)及可執行文件
四、查看Makefile
cat Makefile
1 PROJ := challenge 2 EMPTY := 3 SPACE := $(EMPTY) $(EMPTY) 4 SLASH := / 5 6 V := @ 7 #need llvm/cang-3.5+ 8 #USELLVM := 1 9 # try to infer the correct GCCPREFX 10 ifndef GCCPREFIX 11 GCCPREFIX := $(shell if i386-elf-objdump -i 2>&1 | grep '^elf32-i386$$' >/dev/null 2>&1; \ 12 then echo 'i386-elf-'; \ 13 elif objdump -i 2>&1 | grep 'elf32-i386' >/dev/null 2>&1; \ 14 then echo ''; \ 15 else echo "***" 1>&2; \ 16 echo "*** Error: Couldn't find an i386-elf version of GCC/binutils." 1>&2; \ 17 echo "*** Is the directory with i386-elf-gcc in your PATH?" 1>&2; \ 18 echo "*** If your i386-elf toolchain is installed with a command" 1>&2; \ 19 echo "*** prefix other than 'i386-elf-', set your GCCPREFIX" 1>&2; \ 20 echo "*** environment variable to that prefix and run 'make' again." 1>&2; \ 21 echo "*** To turn off this error, run 'gmake GCCPREFIX= ...'." 1>&2; \ 22 echo "***" 1>&2; exit 1; fi) 23 endif 24 25 # try to infer the correct QEMU 26 ifndef QEMU 27 QEMU := $(shell if which qemu-system-i386 > /dev/null; \ 28 then echo 'qemu-system-i386'; exit; \ 29 elif which i386-elf-qemu > /dev/null; \ 30 then echo 'i386-elf-qemu'; exit; \ 31 elif which qemu > /dev/null; \ 32 then echo 'qemu'; exit; \ 33 else \ 34 echo "***" 1>&2; \ 35 echo "*** Error: Couldn't find a working QEMU executable." 1>&2; \ 36 echo "*** Is the directory containing the qemu binary in your PATH" 1>&2; \ 37 echo "***" 1>&2; exit 1; fi) 38 endif 39 40 # eliminate default suffix rules 41 .SUFFIXES: .c .S .h 42 43 # delete target files if there is an error (or make is interrupted) 44 .DELETE_ON_ERROR: 45 46 # define compiler and flags 47 ifndef USELLVM 48 HOSTCC := gcc 49 HOSTCFLAGS := -g -Wall -O2 50 CC := $(GCCPREFIX)gcc 51 CFLAGS := -march=i686 -fno-builtin -fno-PIC -Wall -ggdb -m32 -gstabs -nostdinc $(DEFS) 52 CFLAGS += $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector) 53 else 54 HOSTCC := clang 55 HOSTCFLAGS := -g -Wall -O2 56 CC := clang 57 CFLAGS := -march=i686 -fno-builtin -fno-PIC -Wall -g -m32 -nostdinc $(DEFS) 58 CFLAGS += $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector) 59 endif 60 61 CTYPE := c S 62 63 LD := $(GCCPREFIX)ld 64 LDFLAGS := -m $(shell $(LD) -V | grep elf_i386 2>/dev/null | head -n 1) 65 LDFLAGS += -nostdlib 66 67 OBJCOPY := $(GCCPREFIX)objcopy 68 OBJDUMP := $(GCCPREFIX)objdump 69 70 COPY := cp 71 MKDIR := mkdir -p 72 MV := mv 73 RM := rm -f 74 AWK := awk 75 SED := sed 76 SH := sh 77 TR := tr 78 TOUCH := touch -c 79 80 OBJDIR := obj 81 BINDIR := bin 82 83 ALLOBJS := 84 ALLDEPS := 85 TARGETS := 86 87 include tools/function.mk 88 89 listf_cc = $(call listf,$(1),$(CTYPE)) 90 91 # for cc 92 add_files_cc = $(call add_files,$(1),$(CC),$(CFLAGS) $(3),$(2),$(4)) 93 create_target_cc = $(call create_target,$(1),$(2),$(3),$(CC),$(CFLAGS)) 94 95 # for hostcc 96 add_files_host = $(call add_files,$(1),$(HOSTCC),$(HOSTCFLAGS),$(2),$(3)) 97 create_target_host = $(call create_target,$(1),$(2),$(3),$(HOSTCC),$(HOSTCFLAGS)) 98 99 cgtype = $(patsubst %.$(2),%.$(3),$(1)) 100 objfile = $(call toobj,$(1)) 101 asmfile = $(call cgtype,$(call toobj,$(1)),o,asm) 102 outfile = $(call cgtype,$(call toobj,$(1)),o,out) 103 symfile = $(call cgtype,$(call toobj,$(1)),o,sym) 104 105 # for match pattern 106 match = $(shell echo $(2) | $(AWK) '{for(i=1;i<=NF;i++){if(match("$(1)","^"$$(i)"$$")){exit 1;}}}'; echo $$?) 107 108 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 109 # include kernel/user 110 111 INCLUDE += libs/ 112 113 CFLAGS += $(addprefix -I,$(INCLUDE)) 114 115 LIBDIR += libs 116 117 $(call add_files_cc,$(call listf_cc,$(LIBDIR)),libs,) 118 119 # ------------------------------------------------------------------- 120 # kernel 121 122 KINCLUDE += kern/debug/ \ 123 kern/driver/ \ 124 kern/trap/ \ 125 kern/mm/ 126 127 KSRCDIR += kern/init \ 128 kern/libs \ 129 kern/debug \ 130 kern/driver \ 131 kern/trap \ 132 kern/mm 133 134 KCFLAGS += $(addprefix -I,$(KINCLUDE)) 135 136 $(call add_files_cc,$(call listf_cc,$(KSRCDIR)),kernel,$(KCFLAGS)) 137 138 KOBJS = $(call read_packet,kernel libs) 139 140 # create kernel target 141 kernel = $(call totarget,kernel) 142 143 $(kernel): tools/kernel.ld 144 145 $(kernel): $(KOBJS) 146 @echo + ld $@ 147 $(V)$(LD) $(LDFLAGS) -T tools/kernel.ld -o $@ $(KOBJS) 148 @$(OBJDUMP) -S $@ > $(call asmfile,kernel) 149 @$(OBJDUMP) -t $@ | $(SED) '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $(call symfile,kernel) 150 151 $(call create_target,kernel) 152 153 # ------------------------------------------------------------------- 154 155 # create bootblock 156 bootfiles = $(call listf_cc,boot) 157 $(foreach f,$(bootfiles),$(call cc_compile,$(f),$(CC),$(CFLAGS) -Os -nostdinc)) 158 159 bootblock = $(call totarget,bootblock) 160 161 $(bootblock): $(call toobj,$(bootfiles)) | $(call totarget,sign) 162 @echo + ld $@ 163 $(V)$(LD) $(LDFLAGS) -N -e start -Ttext 0x7C00 $^ -o $(call toobj,bootblock) 164 @$(OBJDUMP) -S $(call objfile,bootblock) > $(call asmfile,bootblock) 165 @$(OBJCOPY) -S -O binary $(call objfile,bootblock) $(call outfile,bootblock) 166 @$(call totarget,sign) $(call outfile,bootblock) $(bootblock) 167 168 $(call create_target,bootblock) 169 170 # ------------------------------------------------------------------- 171 172 # create 'sign' tools 173 $(call add_files_host,tools/sign.c,sign,sign) 174 $(call create_target_host,sign,sign) 175 176 # ------------------------------------------------------------------- 177 178 # create ucore.img 179 UCOREIMG := $(call totarget,ucore.img) 180 181 $(UCOREIMG): $(kernel) $(bootblock) 182 $(V)dd if=/dev/zero of=$@ count=10000 183 $(V)dd if=$(bootblock) of=$@ conv=notrunc 184 $(V)dd if=$(kernel) of=$@ seek=1 conv=notrunc 185 186 $(call create_target,ucore.img) 187 188 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 189 190 $(call finish_all) 191 192 IGNORE_ALLDEPS = clean \ 193 dist-clean \ 194 grade \ 195 touch \ 196 print-.+ \ 197 handin 198 199 ifeq ($(call match,$(MAKECMDGOALS),$(IGNORE_ALLDEPS)),0) 200 -include $(ALLDEPS) 201 endif 202 203 # files for grade script 204 205 TARGETS: $(TARGETS) 206 207 .DEFAULT_GOAL := TARGETS 208 209 .PHONY: qemu qemu-nox debug debug-nox 210 qemu-mon: $(UCOREIMG) 211 $(V)$(QEMU) -no-reboot -monitor stdio -hda $< -serial null 212 qemu: $(UCOREIMG) 213 $(V)$(QEMU) -no-reboot -parallel stdio -hda $< -serial null 214 log: $(UCOREIMG) 215 $(V)$(QEMU) -no-reboot -d int,cpu_reset -D q.log -parallel stdio -hda $< -serial null 216 qemu-nox: $(UCOREIMG) 217 $(V)$(QEMU) -no-reboot -serial mon:stdio -hda $< -nographic 218 TERMINAL :=gnome-terminal 219 debug: $(UCOREIMG) 220 $(V)$(QEMU) -S -s -parallel stdio -hda $< -serial null & 221 $(V)sleep 2 222 $(V)$(TERMINAL) -e "gdb -q -tui -x tools/gdbinit" 223 224 debug-nox: $(UCOREIMG) 225 $(V)$(QEMU) -S -s -serial mon:stdio -hda $< -nographic & 226 $(V)sleep 2 227 $(V)$(TERMINAL) -e "gdb -q -x tools/gdbinit" 228 229 .PHONY: grade touch 230 231 GRADE_GDB_IN := .gdb.in 232 GRADE_QEMU_OUT := .qemu.out 233 HANDIN := proj$(PROJ)-handin.tar.gz 234 235 TOUCH_FILES := kern/trap/trap.c 236 237 MAKEOPTS := --quiet --no-print-directory 238 239 grade: 240 $(V)$(MAKE) $(MAKEOPTS) clean 241 $(V)$(SH) tools/grade.sh 242 243 touch: 244 $(V)$(foreach f,$(TOUCH_FILES),$(TOUCH) $(f)) 245 246 print-%: 247 @echo $($(shell echo $(patsubst print-%,%,$@) | $(TR) [a-z] [A-Z])) 248 249 .PHONY: clean dist-clean handin packall tags 250 clean: 251 $(V)$(RM) $(GRADE_GDB_IN) $(GRADE_QEMU_OUT) cscope* tags 252 -$(RM) -r $(OBJDIR) $(BINDIR) 253 254 dist-clean: clean 255 -$(RM) $(HANDIN) 256 257 handin: packall 258 @echo Please visit http://learn.tsinghua.edu.cn and upload $(HANDIN). Thanks! 259 260 packall: clean 261 @$(RM) -f $(HANDIN) 262 @tar -czf $(HANDIN) `find . -type f -o -type d | grep -v '^\.*$$' | grep -vF '$(HANDIN)'` 263 264 tags: 265 @echo TAGS ALL 266 $(V)rm -f cscope.files cscope.in.out cscope.out cscope.po.out tags 267 $(V)find . -type f -name "*.[chS]" >cscope.files 268 $(V)cscope -bq 269 $(V)ctags -L cscope.files
五、輸入make V=
查看make執行的命令
1 moocos-> make V= 2 + cc kern/init/init.c 3 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 4 + cc kern/libs/readline.c 5 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 6 + cc kern/libs/stdio.c 7 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 8 + cc kern/debug/kdebug.c 9 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 10 + cc kern/debug/kmonitor.c 11 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 12 + cc kern/debug/panic.c 13 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 14 + cc kern/driver/clock.c 15 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 16 + cc kern/driver/console.c 17 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 18 + cc kern/driver/intr.c 19 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 20 + cc kern/driver/picirq.c 21 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 22 + cc kern/trap/trap.c 23 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 24 + cc kern/trap/trapentry.S 25 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 26 + cc kern/trap/vectors.S 27 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 28 + cc kern/mm/pmm.c 29 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 30 + cc libs/printfmt.c 31 gcc -Ilibs/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -c libs/printfmt.c -o obj/libs/printfmt.o 32 + cc libs/string.c 33 gcc -Ilibs/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -c libs/string.c -o obj/libs/string.o 34 + ld bin/kernel 35 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 36 + cc boot/bootasm.S 37 gcc -Iboot/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Os -nostdinc -c boot/bootasm.S -o obj/boot/bootasm.o 38 + cc boot/bootmain.c 39 gcc -Iboot/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Os -nostdinc -c boot/bootmain.c -o obj/boot/bootmain.o 40 + cc tools/sign.c 41 gcc -Itools/ -g -Wall -O2 -c tools/sign.c -o obj/sign/tools/sign.o 42 gcc -g -Wall -O2 obj/sign/tools/sign.o -o bin/sign 43 + ld bin/bootblock 44 ld -m elf_i386 -nostdlib -N -e start -Ttext 0x7C00 obj/boot/bootasm.o obj/boot/bootmain.o -o obj/bootblock.o 45 'obj/bootblock.out' size: 488 bytes 46 build 512 bytes boot sector: 'bin/bootblock' success! 47 dd if=/dev/zero of=bin/ucore.img count=10000 48 10000+0 records in 49 10000+0 records out 50 5120000 bytes (5.1 MB) copied, 0.0601803 s, 85.1 MB/s 51 dd if=bin/bootblock of=bin/ucore.img conv=notrunc 52 1+0 records in 53 1+0 records out 54 512 bytes (512 B) copied, 0.000141238 s, 3.6 MB/s 55 dd if=bin/kernel of=bin/ucore.img seek=1 conv=notrunc 56 146+1 records in 57 146+1 records out 58 74923 bytes (75 kB) copied, 0.00356787 s, 21.0 MB/s
2、問題一的解答
問題:操做系統鏡像文件ucore.img是如何一步一步生成的?(須要比較詳細地解釋Makefile中每一條相關命令和命令參數的含義,以及說明命令致使的結果)
答:
(1)make V=
一、整體概述
①首先把C的源代碼編譯爲目標文件(.o文件)
比方說下面這樣:
1 + cc kern/init/init.c 2 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 3 + cc kern/libs/readline.c 4 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命令將這些目標文件轉變成可執行文件
好比像下面這樣的:
1 + ld bin/kernel 2 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的虛擬硬盤中
1 dd if=/dev/zero of=bin/ucore.img count=10000 2 10000+0 records in 3 10000+0 records out 4 5120000 bytes (5.1 MB) copied, 0.0601803 s, 85.1 MB/s 5 dd if=bin/bootblock of=bin/ucore.img conv=notrunc 6 1+0 records in 7 1+0 records out 8 512 bytes (512 B) copied, 0.000141238 s, 3.6 MB/s 9 dd if=bin/kernel of=bin/ucore.img seek=1 conv=notrunc 10 146+1 records in 11 146+1 records out 12 74923 bytes (75 kB) copied, 0.00356787 s, 21.0 MB/s
④還生成了兩個軟件,一個是bootloader,另外一個是kernel
二、具體分析
須要生成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:刪除全部本地符號
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:顯示版本信息
1 + ld bin/kernel 2 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文件編譯生成
1 + ld bin/bootblock 2 ld -m elf_i386 -nostdlib -N -e start -Ttext 0x7C00 obj/boot/bootasm.o obj/boot/bootmain.o -o obj/bootblock.o 3 'obj/bootblock.out' size: 488 bytes 4 build 512 bytes boot sector: 'bin/bootblock' success!
同理ld也將.o文件整合成可執行文件bootblock,大小爲488字節,但仍是放入512字節扇區中,可是,而這些.o文件也是Makefile文件經過命令使用gcc把有關bootloader的.c文件編譯生成
1 dd if=/dev/zero of=bin/ucore.img count=10000 2 10000+0 records in 3 10000+0 records out 4 5120000 bytes (5.1 MB) copied, 0.0601803 s, 85.1 MB/s
建立10000塊扇區,每一個扇區512字節,製成ucore.img虛擬磁盤
1 dd if=bin/bootblock of=bin/ucore.img conv=notrunc 2 1+0 records in 3 1+0 records out 4 512 bytes (512 B) copied, 0.000141238 s, 3.6 MB/s
將bootblock存到ucore.img虛擬磁盤的第一塊
1 dd if=bin/kernel of=bin/ucore.img seek=1 conv=notrunc 2 146+1 records in 3 146+1 records out 4 74923 bytes (75 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的代碼爲
1 # create ucore.img 2 UCOREIMG := $(call totarget,ucore.img) 3 4 $(UCOREIMG): $(kernel) $(bootblock) 5 $(V)dd if=/dev/zero of=$@ count=10000 6 $(V)dd if=$(bootblock) of=$@ conv=notrunc 7 $(V)dd if=$(kernel) of=$@ seek=1 conv=notrunc 8 9 $(call create_target,ucore.img)
逐條分析:
$(kernel)
:生成kernel。須要如下兩步
編譯kern/目錄下的C程序,生成kernel須要的.o文件
$(call add_files_cc,$(call listf_cc,$(KSRCDIR)),kernel,$(KCFLAGS))
實際執行的命令爲:
1 + cc kern/init/init.c 2 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 3 + cc kern/libs/stdio.c 4 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 5 + cc kern/libs/readline.c 6 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 7 + cc kern/debug/panic.c 8 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 9 + cc kern/debug/kdebug.c 10 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 11 + cc kern/debug/kmonitor.c 12 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 13 + cc kern/driver/clock.c 14 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 15 + cc kern/driver/console.c 16 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 17 + cc kern/driver/picirq.c 18 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 19 + cc kern/driver/intr.c 20 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 21 + cc kern/trap/trap.c 22 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 23 + cc kern/trap/vectors.S 24 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 25 + cc kern/trap/trapentry.S 26 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 27 + cc kern/mm/pmm.c 28 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 29 + cc libs/string.c 30 gcc -Ilibs/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -c libs/string.c -o obj/libs/string.o 31 + cc libs/printfmt.c 32 gcc -Ilibs/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -c libs/printfmt.c -o obj/libs/printfmt.o
連接這些.o文件,生成kernel
1 # create kernel target 2 kernel = $(call totarget,kernel) 3 4 $(kernel): tools/kernel.ld 5 6 $(kernel): $(KOBJS) 7 @echo + ld $@ 8 $(V)$(LD) $(LDFLAGS) -T tools/kernel.ld -o $@ $(KOBJS) 9 @$(OBJDUMP) -S $@ > $(call asmfile,kernel) 10 @$(OBJDUMP) -t $@ | $(SED) '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $(call symfile,kernel) 11 12 $(call create_target,kernel)
執行的實際命令爲:
1 + ld bin/kernel 2 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
1 bootfiles = $(call listf_cc,boot) 2 $(foreach f,$(bootfiles),$(call cc_compile,$(f),$(CC),$(CFLAGS) -Os -nostdinc))
執行的實際命令爲
1 + cc boot/bootasm.S 2 gcc -Iboot/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Os -nostdinc -c boot/bootasm.S -o obj/boot/bootasm.o 3 + cc boot/bootmain.c 4 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
3、問題二的解答
引導扇區的大小爲512字節,最後兩個字節爲標誌性結束字節0x55,0xAA,作完這樣的檢查才能認爲是符合規範的磁盤主引導扇區。
查看sign.c文件的代碼
1 #include <stdio.h> 2 #include <errno.h> 3 #include <string.h> 4 #include <sys/stat.h> 5 6 int 7 main(int argc, char *argv[]) { 8 struct stat st; 9 if (argc != 3) { 10 fprintf(stderr, "Usage: <input filename> <output filename>\n"); 11 return -1; 12 } 13 if (stat(argv[1], &st) != 0) { 14 fprintf(stderr, "Error opening file '%s': %s\n", argv[1], strerror(errno)); 15 return -1; 16 } 17 printf("'%s' size: %lld bytes\n", argv[1], (long long)st.st_size); 18 if (st.st_size > 510) { 19 fprintf(stderr, "%lld >> 510!!\n", (long long)st.st_size); 20 return -1; 21 } 22 char buf[512]; 23 memset(buf, 0, sizeof(buf)); 24 FILE *ifp = fopen(argv[1], "rb"); 25 int size = fread(buf, 1, st.st_size, ifp); 26 if (size != st.st_size) { 27 fprintf(stderr, "read '%s' error, size is %d.\n", argv[1], size); 28 return -1; 29 } 30 fclose(ifp); 31 buf[510] = 0x55; 32 buf[511] = 0xAA; 33 FILE *ofp = fopen(argv[2], "wb+"); 34 size = fwrite(buf, 1, 512, ofp); 35 if (size != 512) { 36 fprintf(stderr, "write '%s' error, size is %d.\n", argv[2], size); 37 return -1; 38 } 39 fclose(ofp); 40 printf("build 512 bytes boot sector: '%s' success!\n", argv[2]); 41 return 0; 42 }
35行到38行的代碼說明sign.c文件是會做檢查的
if (size != st.st_size) { fprintf(stderr, "read '%s' error, size is %d.\n", argv[1], size); return -1; }