程式設計師的自我修養總結(一)
第二章 編譯和連結
1. gcc hello.c
./a.out
預處理——編譯——彙編——連結
2. 預處理:預編譯 gcc –E hello.c –o hello.i或者hello.c >hello.i
原始檔和標頭檔案被預編譯器cpp編譯成.ii(c++) .i(c)檔案,預編譯處理規則:
[1] 將#define刪除,展開所有巨集定義
[2] 處理所有條件預編譯指令,比如“#if”,“#ifndef”,“endif”,“else”
[3] 處理“#include”預編譯指令,將包含的檔案插入到預編譯指令的位置
[4] 刪除所有的註釋“//”“/****/”
[5] 新增行號和檔名標識,比如#2“hello.c”2,便於編譯時報錯警告便以其產生條使用的行號資訊
[6] 保留所有的#pragma編譯器指令
3. 編譯:gcc –S hello.i -o hello.s
編譯就是把預處理完的檔案進行一系列的詞法分析、語法分析、語義分析及優化後生產相應的彙編程式碼檔案。預編譯和編譯合併成一個cc1的程式
4. 彙編ashello.s –o hello.o或者gcc –c hello.s –o hello.o
將彙編程式碼轉變成及其可移植性的指令。
直接從原始檔開始經過預編譯、編譯和彙編生成目標檔案:gcc -c hello.c –o hello.o
5. 連結
一個生成的可執行檔案包含很多目標.o檔案。包括地址和空間分配、符號決議(地址繫結)和重定位等步驟。就是把目標檔案和庫函式連結起來,最常見的庫是runtime library即執行時庫。
6. 編譯器的工作
[1] 詞法分析:掃描程式,產生一些記號:關鍵字、標示符、字面量和特殊符號
[2] 語法分析:將掃描器產生的記號生成以表示式為節點的語法樹
[3] 語義分析:主要是靜態語義,包括生命和型別的匹配,轉換。經過語義分析,語法樹的表示式被標識了型別,(有的要隱式轉換)
7. 中間語言生成
原始碼級優化器,產生中間程式碼,程式碼生成器把中間程式碼轉換成目標機器程式碼,目的碼優化器對目的碼優化、選擇合適的定址方式等
第三章 目標檔案
8.
[1] 程式碼段:程式碼、函式被放在數程式碼段.text或者.code
[2] 資料段:已初始化區域性靜態變數和全域性變數被放在資料段.data
[3] 未初始化的全域性和區域性靜態變數預設為0,放在.bss中,因為為0所以在.data中分配空間沒有必要。
[4] 只讀資料段:.rodata就是隻讀變數const和字串常量。
[5]
9. 目標檔案包括一個檔案頭、描述了檔案屬性,如是否可執行、動態還是靜態、入口地址、等,檔案頭包括一個段表,記錄了各個段在檔案中的偏移和短的屬性。