Hello World Odyssey - Part 0. Introduction
# WTF - Welcome To executable and linkable Format
# 序論、為何想寫這篇專欄 ?
受到下列五本寫的非常好的書籍啟發,很推薦大家把他們啃完
- 程式設計師的自我修養 連結、載入、程式庫
- CSAPP - Computer Systems: A Programmer's Perspective
- 計算機系統基礎 (中國袁春風老師撰寫)
- Computer science from the bottom up
- Binary hack
剛開始接觸到程式設計師的自我修養時,裡面專門探討 hello world 背後的高深,老實說,在沒有任何技術底子下,真的是覺得滿紙荒唐言,讀的一把辛酸淚,但有些基礎回去看後,發現書中自有顏如玉,越陳越香,含金量非常高,也勾起了我寫這篇專欄的興致。
我會從 ELF 的檔案格式,以及需要理解ELF的原因跟影響。開始介紹到 linker 的機制, 再來介紹 hello world 更深入的原理,最後做出一個綜觀導覽。
# 一、你好,世界
先上三張迷因
meme 1 | meme 2 | meme 3 |
---|---|---|
在豐富多變的科技時代,我們時常踩在巨人的肩膀上,利用別人開發的函式庫、套件、工具來撰寫或測試自己的程式。我們在學習一門新的語言,時常以 hello world 作為濫觴,正式開啟我們的學習語言之路,而 hello world 宛若一個陳腔濫調的開場舞,受到很多人嗤之以鼻,甚至認為跟呼吸一樣簡單。
#include <stdio.h>
int main()
{
printf("Hello World!\n");
}
2
3
4
5
2
3
4
5
雖說跟呼吸一樣簡單,但你真的了解人類怎麼呼吸的嗎 ? 大腦、腦幹、呼吸系統怎麼協調合作,才可以讓你正常呼吸 ? 回到我們的 hello world,其實從輸入到執行背後隱含很多技術精隨,一句 hello world 乘載了百年的前人智慧,才能讓我們行雲流水的寫出言簡意賅的程式碼。從原始的 C 語言,需要經過 compiler、assembler、 linker、loader 這四個工具,才能真正執行程式。這四個部分,每個部分都可以獨自寫成一本厚厚的專書。而如同呼吸一般,我們知其然,卻不知其所然,著實可惜。
# 二、拋磚引玉說教時間
下列問題,可以回答得出來嗎 ?
- hello world 在被編譯成 object file ,怎麼幫我們做符號表的配置及符號引用 ?
- Symbol relocation 怎麼做的?
- ELF 檔案格式 ?
- Linker 幫我們做什麼 ?
- 動態連結技術是什麼 ? PLT, GOT 是什麼 ?
- Loader 幫我們做什麼 ? 如何將 ELF 檔案擺進記憶體使其可以正常執行 ?
甚至最後一問,你知道 hello world 從編譯成 object file 後的人生,每分每秒怎麼渡過的嗎 ? 你可以跟一個國中生,說明這個生命週期,並讓他快速了解 ?
如果你都不會(沒有不太會,只有會跟不會),也別氣餒,相信很多資工系出身的學生,對於 hello world 的認知也僅止於編譯跟執行。你會粗俗的說這與我何干 ? 會這個也不會比較厲害。去面試、或是工作開發程式時誰會問你這個 ? 頂多成為掉書袋的知識。
有鑑於此,我很推薦大家閱讀這兩本課外讀物
身為程式設計師,我認為無止盡的求知慾才是走這行的長久之道,以功利取向去看待一門學問略顯膚淺。如同很多奇幻動漫,都想找到魔法的根源,掌握魔法的根源意謂掌握強大的力量。但往往尋找的路途都十分艱辛,或是魔法書晦澀難懂,人人望而生畏。計算機科學亦復如是,越接近底層的東西,越難懂晦澀。如同作業系統光是記憶體管理,就運用到像是紅黑樹、slab allocator、buddy system、虛擬記憶體管理、copy on write等技術。這些技術日新月異,但是核心原理卻是亙古不變的,不像前端技術般,絢麗多彩的套件跟框架,每經過一小段時間就要重學,著實身心俱疲。因此,我們需要扎實學習這些基礎但不變的知識,才能在反覆的潮流中,以不變應萬變。
如同我們國中國文課本,有一篇叫做 <兒時記趣>,文章開頭
余憶童稚時,能張目對日,明察秋毫,見藐小微物,必細察其紋理, 故時有物外之趣
一沙一世界,一花一天堂。又恰如王國維的<人間詞話>
詩人對宇宙人生,須入乎其內,又須出乎其外。入乎其內,故能寫之;出乎其外,故能觀之。入乎其內,故有生氣;出乎其外,故有高致。
程式設計師如同詩人,需要深入去體會這些如同 hello world 的細節,才能知道運作原理,且要及時抽身,不能迷失於小細節中,綜觀整體流程,深入淺出表達自身之經歷。把所見化為所得,方為學習之樂。
最後,古哲學三大終極問題
我是誰,從哪裡來,又該往何方 ?
在學習時,時常要問自己為什麼 ? 程式設計師理應追求穩健的內功而非華而不實的功夫,儘管表面功夫也需要不少的時間學習,但我們一旦掌握內功,之後面對任何一種學問都能更快上手,我們也能活的更踏實、更沉穩。例如 socket programming,你如果知道從哪裡來 - I/O 多工跟非同步 I/O 的機制、抑或是 IPC 機制,不論是 python、java、javascript、C 語言,何種語言 API 都可以應用得心應手,也就知道該往何方去使用。倘若你不想成為知其然不知其所以然的人,須捨棄外在顯學,追求真正的本質,在程式之路上,才能細水長流。