2013-05-14 98 views
3

由於顯而易見的原因,C編譯器必須編譯所有對其他共享庫可見的函數,以便它們符合平臺的調用約定和其他ABI要求。但是,我已經瞭解到,對於可以保證永遠不會從外部模塊調用的函數,並不一定需要這樣做。在哪種情況下C編譯器允許忽略調用約定?

編譯器如何以及何時可以確定給定函數是否適用?

  • 靜態函數是在同一個編譯單元只等功能可見的,因此,將是這樣的ABI破優化一個很好的候選人。但是指向靜態函數的函數指針仍然可以傳遞給其他模塊。編譯器是否嘗試確定函數指針是否傳遞到代碼中的任何位置?

  • gcc編譯器具有some extensions允許符號被聲明爲默認,隱藏或甚至內部,並且該文檔特別提到,此信息可用於執行一些種類的優化不可能外部可見funcitons。如果將函數指針傳遞給註釋爲內部函數的外部代碼,會發生什麼情況?

什麼是最好的方式來幫助編譯器執行儘可能多的優化,同時仍然保證與其他庫的互操作性?我是否應該只使用編譯器選項來將所有函數定義爲內部函數,並用所有需要在外部可見的函數的屬性覆蓋它?

回答

0

靜態函數僅對同一編譯單元中的其他函數可見,因此對於這樣的ABI中斷優化來說是一個很好的候選。但是指向靜態函數的函數指針仍然可以傳遞給其他模塊。編譯器是否嘗試確定函數指針是否傳遞到代碼中的任何位置?

是的,編譯器會做「逃避分析」來查看給定的函數是否真的只在內部使用,或者如果它通過它的指針逃逸。

gcc編譯器有一些擴展,允許符號被聲明爲默認,隱藏或甚至內部,並且該文檔特別提到,此信息可用於執行一些種類的優化不可能外部可見funcitons。如果將函數指針傳遞給註釋爲內部函數的外部代碼,會發生什麼情況?

看到我的答案你的第一點。

1

C標準要求在所有情況下,指向同一函數的兩個指針比較相等。

如果您將符號聲明爲外部符號,則指針永遠不會傳遞到外部代碼,編譯器只能執行ABI分解技巧。

編譯器是否試圖確定函數指針是否在代碼中的任何位置傳遞 ?

是的,它確實,如果它想要執行此優化。編譯器可以簡單地知道哪些函數對它們執行了函數指針衰減,所以知道你是否已經使用函數的地址並不重要。保守地說,編譯器可以假設所有的函數指針都被傳遞給外部代碼,或者他們可能會嘗試更高級的東西。

如果函數指針被傳遞給外部代碼 ,那麼註釋爲內部函數會發生什麼?

沒有什麼興趣 - 它必須工作。

內部/外部可視性主要是關於可見性。編譯器只能在相對較少的情況下將其變成許可證來打破ABI。

我應該使用編譯器選項來定義所有的功能 內,並覆蓋與該 需要在外部可見的所有功能的屬性?

除非您的圖書館只包含一個翻譯單元,否則您會期望幾乎所有功能都需要在外部可見。 「外部但只在我的圖書館內」和「外部對所有人」之間的C沒有明顯的區別。但是,從理論上講,你可以試試這個。然而,我懷疑你會獲得更多的加速,這對於一個不重要的代碼庫來說是一個很大的努力。

+0

在某些ARM系統上,在需要以與其他參數相同的方式或在FP寄存器中傳遞浮點值的代碼之間可能存在兼容性問題。如果不是函數指針,我想這個問題可以通過讓一個編譯器生成代碼來解決,該編譯器使用FPU生成一個帶有使用FPU寄存器的錯誤名稱的函數版本,以及一個「弱鏈接」一個未經修改的名稱,它將普通參數複製到FPU寄存器並調用損壞名稱的版本。 – supercat 2013-12-06 16:37:57

+0

使用FPU並想要調用FPU寄存器版本的編譯器proudicng代碼將生成對mangled-name版本的調用以及將FPU寄存器複製到普通參數並調用非受損版本的弱鏈接包裝器。這應該允許調用者和被調用的代碼FPU使用的任何組合之間的「通用」行爲。至於函數指針,我認爲可以避免ABI方差的問題,除非聲明「特別」,否則它們總是指向使用最基本的ABI的方法。這似乎可行嗎? – supercat 2013-12-06 16:40:47

相關問題