系列文章 : [6.1810] 跟著 MIT 6.1810 學習基礎作業系統觀念
很簡單的用 printf 來列印出 hello !
最後記得要用 exit(0) 結束程式。
_hello
需要在 Makefile 裡面表明說,現在多一個檔案需要編譯了 !
ls 之後,可以看到 hello 這個 ELF 已經在裡面了!$ ls
. 1 1 1024
.. 1 1 1024
README 2 2 2425
cat 2 3 36784
echo 2 4 35600
forktest 2 5 17488
grep 2 6 40224
init 2 7 36072
kill 2 8 35536
ln 2 9 35344
ls 2 10 38896
mkdir 2 11 35600
rm 2 12 35576
sh 2 13 58632
stressfs 2 14 36464
usertests 2 15 188592
grind 2 16 51816
wc 2 17 37680
zombie 2 18 34952
logstress 2 19 37520
forphan 2 20 36408
dorphan 2 21 35872
hello 2 22 35064
console 3 23 0
$ ./hello
hello xv6-riscv!!
編譯 hello.c 之後,toolchain 會產生一些檔案。
_%: %.o $(ULIB) $U/user.ld
$(LD) $(LDFLAGS) -T $U/user.ld -o $@ $< $(ULIB)
$(OBJDUMP) -S $@ > $*.asm
$(OBJDUMP) -t $@ | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $*.sym
這一段是用來 link user program 的,這邊來閱讀程式碼。
_%: %.o $(ULIB) $U/user.ld
underscore ( _ ) 是 xv6-riscv 為了辨識 user program 所設定的前綴。例如 _ls, _cat … 但要注意的是,我們的 source file 不需要這個前綴 ( e.g. ls.c, cat.c ): 左邊的是 target ,右邊的是 prerequisites ( dependencies )。在產生 target 前,需要先產生所有的 prerequisites。假如 prerequisites 終於集齊了,才會執行下面的程式碼,以便產生 target。_%
這邊介紹一些 Makefile 裡面會使用到的符號
user/_ls: user/ls.o $(ULIB) $U/user.ld
_ 的字串 $(LD) $(LDFLAGS) -T $U/user.ld -o $@ $< $(ULIB)
riscv64-xxx-ld
-T 並指定 linker script。user/user.ld。 $(OBJDUMP) -S $@ > $*.asm
>
$(OBJDUMP) -t $@ | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $*.sym
這邊的 rule 是從 object file ( e.g. ls.o ) 產生 ELF ( e.g. _ls )。
那 object file ( e.g. ls.o ) 又是從哪個 rule 產生的呢 ???
我們可以用 command make -W user/ls.c -n user/_ls 去觀察 user/_ls 從頭到尾是怎麼產生的。
可以看到 %.o : %.c 這個 rule 並不在 Makefile 裡面!
其實我們在 Makefile 裡面明確設定的 rule,被稱為 explicit rule,而沒有被我們明確設定的 rule,且有在 GNU Make 裡面 built-in 的 rule 被稱為 implicit rule。
當 implicit rule 存在,且不存在相對應的 explicit rule 的時候,就會去使用 implicit rule
想知道當前的 Makefile 有哪些 implicit rule,可以使用 command make -p -f /dev/null > default_rules.txt
這邊使用的 implicit rule 會是
%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
ls.o
ls.o: ls.c aaa bbb,則 $< 的值會是 ls.c
ls.o: ls.c aaa bbb,則 $^ 的值會是 ls.c aaa bbb
OUTPUT_ARCH( "riscv" )
表示 output binary 的 target architecture 是 RISC-V
SECTIONS
標示出一個 memory layout section
{
. = 0x0;
. : location counter .text : {
*(.text .text.*)
}
.rodata : {
. = ALIGN(16);
*(.srodata .srodata.*) /* do not need to distinguish this from .rodata */
. = ALIGN(16);
*(.rodata .rodata.*)
}
.eh_frame : {
*(.eh_frame)
*(.eh_frame.*)
}
. = ALIGN(0x1000);
.data : {
. = ALIGN(16);
*(.sdata .sdata.*) /* do not need to distinguish this from .data */
. = ALIGN(16);
*(.data .data.*)
}
.bss : {
. = ALIGN(16);
*(.sbss .sbss.*) /* do not need to distinguish this from .bss */
. = ALIGN(16);
*(.bss .bss.*)
}
PROVIDE(end = .);
}
end 這個 symbol 的話,linker 就會提供 end 這個 global symbol。