2013-12-17 84 views
8

在gcc目標機器上,當需要編譯共享庫時,需要指定-fpic或-fPIC來使事情正確工作。這是因爲默認情況下使用了絕對地址,它適用於完全控制自己地址空間的可執行文件,而不是共享庫,可以在可執行文件的地址空間中的任何位置加載。然而,現代內核現在正在實現地址空間隨機化,許多現代體系結構都支持PC相對尋址。這似乎使絕對尋址不可用(地址空間隨機化)或不需要(PC相對尋址)。編譯GCC時還需要用-fPIC嗎?

我也注意到叮噹沒有-fPIC選項,這使得我不再需要它。

那麼-fpic現在是多餘的,還是需要生成單獨的.o文件,一個用於靜態庫,另一個用於共享庫?

回答

0

您從不需要生成單獨的.o文件。始終指定編譯器選項以生成便攜式代碼(通常爲-fPIC)。

在某些系統上,編譯器可能配置爲強制啓用此選項,或者默認設置它。但無論如何,指定它並沒有什麼壞處。

注意:希望在PC相對尋址被支持並且性能良好時,-fPIC使用該模式而不是專用額外的寄存器。

+0

在大多數情況下,PIC代碼速度較慢,因爲通過PLT的額外跳轉需要在許多函數調用中使用額外的間接方向。建立沒有PIC的靜態庫是個好主意。 – Art

+0

@藝術:可能會變慢,但不會太多。我不同意沒有,建立靜態庫是有用的。靜態庫不僅被鏈接到可執行文件中,而且被鏈接到共享庫中。而且,正如所提到的問題,ASLR可執行文件還需要與位置無關。所以最安全的是總是指定'-fPIC'。 –

+0

@Art Intel上的問題不是函數調用或跳轉(無論哪種方式都是PC相關),而是訪問全局數據。 (在其他處理器上,問題會有所不同。) –

1

我同意你的觀點:在許多情況下,-fpic/-fPIC的選擇幾乎是多餘的,然而,我用它們來確保:

  • 可移植性(從不知道什麼特定的OS /內核將提供)
  • 向後兼容性:這些選項可以確保你想在老版本的內核
  • 習慣的行爲 - 硬的東西打破:)
  • 符合舊的代碼庫,可能需要它
5

您仍然需要使用-fPIC進行編譯。這個問題不能用pc相對尋址解決。問題是你如何解決外部符號。在動態鏈接的程序中,解析遵循不同的規則,特別是隨着地址空間的隨機化,在鏈接時間內無法解析。

和clang確實擁有-fPIC標誌,就像gcc一樣。

$ cat > foo.c 
void foo(void); 
void bar(void) { foo(); } 
$ gcc -S foo.c && grep call.*foo foo.s 
    call foo 
$ gcc -fPIC -S foo.c && grep call.*foo foo.s 
    call [email protected] 
$ clang -S foo.c && grep call.*foo foo.s 
    callq foo 
$ clang -fPIC -S foo.c && grep call.*foo foo.s 
    callq [email protected] 
$ 
+1

嗯-fPIC它不在手冊 – doron

+0

@doron我認爲這是(但可能不會在2013年):https://clang.llvm.org/docs/ClangCommandLineReference.html#target-independent-compilation-選項 –

0

gcc目標很多平臺和架構,而不是所有的人都支持原生PIC像x86架構一樣。在某些情況下,創建PIC意味着額外的開銷,這可能是不受歡迎的,並且您希望或需要這取決於您的項目和您的目標平臺。

0

這取決於目標。有些目標(如x86_64)默認位置無關,sp -fpic是noop,對生成的代碼沒有影響。所以在這些情況下,你可以忽略它,沒有任何變化。其他目標(如x86 32位)在默認情況下不是位置獨立的,因此在這些機器上,如果您爲可執行文件省略了-fpic,它將會禁用該映像文件的ASLR(但不適用於它使用的共享庫)。