程式設計師的自我修養(2)----靜態連結
程式設計師的自我修養(2)—-靜態連結
本章介紹,靜態連結的過程,首先總體介紹了,四個基本步驟,預編譯,編譯,彙編,連結,接著詳細介紹了每個過程做了什麼,以及如何做到的.
1 預編譯
預編譯過程很簡單,就是一些簡單的預處理過程,我們使用的巨集和條件預編譯指令都在這個階段被處理.
- 將巨集展開 即替換所有#define 定義的巨集
- 處理#if #else #elif等預編譯處理命令,刪除掉,不需要編譯的程式碼
- 處理#include 將,包含的標頭檔案遞迴,插入到該語句坐在的位置
- 刪除所有註釋
最後生成”.i”檔案
2 編譯
編譯過程簡單來說就是,將預處理完的”.i”檔案經過
詞法分析—->語法分析—->語義分析及優化—->彙編程式碼檔案
2.1 詞法分析
原始碼輸入掃描器,就原始碼分割成一系列的記號,有如下幾類:關鍵字 識別符號 字面量(數字 字串等) 特殊符號(加號 減號)
2.2 語法分析
對詞法分析產生的記號進行語法分析,按照符號表達式的優先順序生成語法樹,符號和數字樹語法樹的葉子節點.
2.3 語義分析
編譯器只能做到靜態語義分析,包括,宣告和型別匹配和轉換,語義分析會對,語法書的每個表示式標識型別.
2.4 中間程式碼生成
這裡生成最接近目的碼的中間程式碼,例如三位元組碼,中間程式碼還是與目標機器無關的,編譯器其實分為前端和後端,前端負責生成與目標機器無關的程式碼,後端根據機器生成目標機器程式碼,不同的硬體機器程式碼標準不一樣,跨平臺的編譯器,就是一個前端,和多個不同的後端來組成.
2.5 目的碼生成和優化
現在的編譯器優化非常複雜,,舉個例子,常量的相加,可以非常方便的直接優化,具體的優化細節這裡不講,這一步就是編譯器的後端部分了,他會生成目標機器程式碼,也就是彙編程式碼,就是mov jmp之類的.這裡有一個問題,一個專案是分模組的,A模組用的B模組的變數和函式等,編譯器對每個模組是單獨編譯的,那麼編譯A模組的時候,這個時候是不知道使用B中的函式foo_B的地址的,怎麼在彙編程式碼中表示呢?這就是後面要講的連結要解決的事情了.
3 彙編
彙編這個操作也很簡單,就是根據機器將彙編程式碼按照彙編程式碼與機器碼對應的一個表,一個個將彙編程式碼對映為機器碼的過程.
4 連結
回到剛才2.5中提出的問題,因為工程複雜,各個工能模組有自己的實現函式和介面,其他模組呼叫的時候並不知道呼叫的函式的地址的,這裡採取的解決方案,就是在這些不知道地址的地方,放上一個標記,這個標記就是表示,這個地方會在連結的時候進行替換,替換為呼叫模組中那個函式實際的地址,這個過程叫做重定位,舉個例子,就是呼叫其他模組的地方留出一個坑,連結的時候,就拿正確的東西來填這個坑.
5 靜態連結
回到本章主題,靜態連結,主要工作如下
1. 地址和空間分配:給每個函式和變數分配地址
2 .符號決議:我的理解是給每個函式和變數命名為獨一無二可區分的符號
3. 重定位:就是更新函式中用到的函式對應的地址,就是第一條中所分配的地址
注意,在靜態連結前,各個模組引用其他模組的函式或者變數,是可以不關注定義的,只需要包含其他模組的標頭檔案,而靜態庫.a就是多個.o檔案的集合,這樣的靜態庫也是合法的,但是在連結(包括靜態連結和動態連結)的過程中,如果之前應用的函式或者變數沒有找到定義,會報錯某某函式或者變數未定義錯誤!(靜態庫一定要連結成功之後才能保證可用)
本章結束,時間不夠,要更加好好的利用時間,不要浪費時間!!