《程式設計師的自我修養》筆記(1)

2021-07-24 14:04:04 字數 2427 閱讀 2728

又開了新的坑,這學期的目標就是 作業系統+組合語言(8086)+鏈結+cpp, 希望能完整了了解在作業系統下,乙個c程式從執行到結束這背後的故事。

筆記主要是第二章和第三章,編譯和鏈結初步及目標檔案裡有什麼。

以linux為例,我們寫乙個程式,最簡單就是gcc 1.c 然後生成乙個可執行的a.out檔案,這中間經歷了 預處理—編譯—彙編—鏈結 的過程。

最早的程式都是直接在紙上打孔,直接寫機器語言的,也就是一條條指令。指令的執行可能會有跳轉,但如果每次跳轉都是絕對位址,一旦程式有所改變,意味著所有的位址都發生了變化,必須要一條條的改。可以模擬巨集定義,比如你不使用巨集定義乙個常量,萬一需要改變它的值,就要把每個使用到它的地方都改一遍,非常麻煩。

但如果我們將跳轉的位置用乙個名字表示,每次都由機器去計算名字代表的位址是多少來找到正確的位址就很方便了。

乙個很大的程式是由多個不同的模組組成,將各個模組組裝起來的過程就是鏈結,而模組之間的互相呼叫要找到正確的位址,這就是鏈結器幫我們完成的,找到跳轉需要的正確位址,方便了我們的開發。

目標檔案就是**經過上面前三部後生成的檔案,從結構上講,它和可執行檔案的結構稍有,只是還沒有鏈結,無法執行,但就是按照可執行檔案的格式進行儲存的。

pc平台流行的可執行檔案格式主要是linux下的elf和windows下的pe。他們都有共同的祖先unix下的coff格式。

目標檔案中的資訊主要是按照不同的屬性,以段(segment)的格式進行儲存的,也叫節,略有不同,後面針對再說。像我們知道的**段(.text)和資料段(.data),為什麼是段呢,將指令和資料分開,集中到一起,方便對其設定許可權,比如**唯讀,資料可讀寫。最重要的是將指令共享,節省記憶體空間 。我自己還有一種想法,就是在學習組合語言時,也是按照段編寫程式的,cpu不知道哪是**,哪是資料,把它們分類,讓cpu方便執行。

以elf檔案為例,主要分為兩部分,檔案頭和各種段。我們主要使用readelf和objdump來檢視目標檔案。

這裡我們寫了乙個非常簡單的程式******section.c作為例子

/*****

*****

*****

*****

*****

*****

*****

*****

*****

*****

*****

*****

*****

*****

***> file name: ******section.c

> author: jack kang

> mail: [email protected]

> created time: 2023年11月07日 星期一 14時16分54秒

*****

*****

*****

*****

*****

*****

*****

*****

*****

*****

*****

*****

*****

*******/

int printf(const char *format, ...);

int global_init_var = 84;

int global_uninit_var;

void func1(int i)

int main(void)

檔案頭結構位於/etc/elf.h,主要有檔案型別,平台屬性,程式入口,段表的位置及長度,段的個數,其他資訊我們此處忽略,有興趣可以自行研究。

我們用readelf檢視檔案頭的資訊

檔案型別分為四類,可重定位檔案(目標檔案,靜態庫),可執行檔案,共享目標檔案(動態庫),核心轉儲檔案。

平台屬性,在elf.h中有大量的巨集,包括386 arm等。

程式入口,作業系統載入完程式後,從這裡開始執行程序指令。

段表的位置及長度,段表是elf檔案中除了檔案頭最重要的結構,在段表中記錄了各個段的名字,位置,長度和段的屬性,elf的段結構就是由段表定義的,編譯器,鏈結器,裝載器都是通過段表找到段的和訪問段的。段表是以以結構體「elf32_shdr」(32位)為元素的陣列。「elf32_shdr」又被稱為段描述符。

那麼讓我們各個段的資訊看一看

這些段的名字都是以『.』開頭的,表示這些段的名字是系統預留的,我們也可以通過objcopy將自己的檔案作為乙個段插入其中。

第乙個段是預設的什麼都沒有,我們不去管他。

段名後面就是型別,出現的幾個型別含義如下:

null 無效段。

progbits 程式段。 **段、資料段都是這樣的型別。

symtab 符號表

rela 重定位表

strtab 字串表

《程式設計師的自我修養》筆記

以下是我讀此書時作的一些筆記,當然書中還有很多值得參考的想法,就不一一枚舉了。一萬小時說法 這個說法很普遍了,它再次提醒了我如何去做乙個領域的專家。如果平均每天八小時在這個領域上,那麼一年300天 300 8 2400,保持這種學習激情在上面,五年內就可以成為專家了,我算了算自己在這個領域投入的時間...

程式設計師的自我修養

一忌 輕易言敗,沒有自信 沒有永不放棄精神的程式設計師,只是乙個有程式設計師名號的假程式設計師。乙個真正的程式設計師,知道在程式設計的過程中,可能會遇到不計其數的困難和問題,可能有極多的挫折和失敗,而成功只有一次。就為解決乙個問題,我們可能連續十幾甚至幾十小時的坐在計算機前不停的工作。乙個問題解決了...

程式設計師的自我修養

一忌 輕易言敗,沒有自信 沒有永不放棄精神的程式設計師,只是乙個有程式設計師名號的假程式設計師。乙個真正的程式設計師,知道在程式設計的過程中,可能會遇到不計其數的困難和問題,可能有極多的挫折和失敗,而成功只有一次。就為解決乙個問題,我們可能連續十幾甚至幾十小時的坐在計算機前不停的工作。乙個問題解決了...