建構系統、函式庫與相依性

與位置無關的程式碼(position-independent code)

/ PIC /

共享函式庫被載入到另一個程式的記憶體裡,而事先無從得知它會落在哪個位址——一個程式可能把它映射到某處,另一個程式則映射到別處。與位置無關的程式碼,是寫成無論被擺在記憶體何處都能正確執行的機器碼。它從不說「跳到確切位址 0x401000」;它總是說「跳到相對於我此刻所在之處的某個位置」。

一般程式碼可能含有在建構時就烤死的絕對位址——「呼叫位於 0x401000 的函式」。對一個總是被載入到已知位址的主可執行檔來說這沒問題,但對一個可能被載入到任何地方的共享函式庫卻會壞掉:那些位址會指到錯誤的地方。與位置無關的程式碼避免寫死的絕對位址,改用相對參考(以及一些在載入期才填好的小型間接表)。在 Unix 工具鏈上,你在編譯要進共享函式庫的目的檔時,用 -fPIC 旗標(Position Independent Code)來要求它;少了它,建構共享函式庫可能會直接失敗。

為什麼重要:PIC 正是讓一份共享函式庫的副本能被映射進許多不同程式、落在許多不同位址、卻仍能運作的原因,它也是位址空間配置隨機化(一種刻意把程式碼載入到不可預測位址的安全防禦)的構件之一。代價很小:由於多了那層間接,PIC 可能比非 PIC 的程式碼稍慢或稍大,這也是為什麼你通常為共享函式庫使用它,卻不一定為一個單純的可執行檔使用。

為共享函式庫把目的檔編譯成與位置無關: gcc -fPIC -c util.c -o util.o gcc -shared util.o -o libutil.so 忘了 -fPIC 常會引發一個「recompile with -fPIC」的連結錯誤。

-fPIC 產生能在任何載入位址運作的程式碼,這正是共享函式庫所需。

PIC 主要對共享函式庫重要,因為它們可能被載入到不可預測的位址;一個單純的可執行檔通常不需要它。建構 .so 時忘了 -fPIC,常會產生一個叫你用它重新編譯的連結錯誤。

又稱
PIC-fPIC與位置無關碼