Proper C++ Visibility Support

C++可見性控制支持 是GCC編譯器從4.0版本提供的特性

一歧蒋、背景

In ordinary C, if you want to limit the visibility of a function or variable to the current file, you apply the static keyword to it. In a shared library containing many files, though, if you want a symbol to be available in several files inside the library, but not available outside the library, hiding that symbol is more difficult. Most linkers provide convenient ways to hide or show all symbols in a module, but if you want to be more selective, it takes a lot more work.

引用自Controlling Symbol Visibility.

在C語言中阐虚,可以使用static關鍵字奥秆,用于限制函數(shù)或變量的可見性避矢,但只作用于當前文件。而共享庫(或動態(tài)庫)可能包含多個文件尺上,如果需要將某個符號在庫內的多文件間可見卑吭,隱藏符號會變得比較棘手富稻。許多鏈接器提供了將一個模塊的所有符號進行隱藏或導出的方法,但這卻失去了對符號的可見性控制宣蔚。

二向抢、目的

Put simply, it hides most of the ELF symbols which would have previously (and unnecessarily) been public.

主要用于隱藏某些ELF符號,而這些符號只有在之前某時段需要甚至完全不需要Be pulibc.

ELF說明:

ELF(Executable Linkable Format)是UNIX類操作系統(tǒng)中普遍采用的目標文件格式文件包含了代碼胚委、數(shù)據(jù)挟鸠,而有些更包含了符號表、調試信息篷扩、行號信息兄猩、字符串等茉盏。

目標形式:
目標文件有三種類型:

  1. 可重定位文件(Relocatable File) 包含適合于與其他目標文件鏈接來創(chuàng)建可執(zhí)行文件或者共享目標文件的代碼和數(shù)據(jù)鉴未。 (Linux的*.o 文件 Windows的 *.obj文件)
  2. 可執(zhí)行文件(Executable File) 包含適合于執(zhí)行的一個程序,此文件規(guī)定了 exec() 如何創(chuàng)建一個程序的進程映像鸠姨。(比如/bin/bash文件铜秆;Windows的*.exe)
  3. 共享目標文件(Shared Object File) 包含可在兩種上下文中鏈接的代碼和數(shù)據(jù)。首先鏈接編輯器可以將它和其它可重定位文件和共享目標文件一起處理讶迁,生成另外一個目標文件连茧。其次,動態(tài)鏈接器(Dynamic Linker)可能將它與某個可執(zhí)行文件以及其它共享目標一起組合巍糯,創(chuàng)建進程映像啸驯。
    目標文件全部是程序的二進制表示,目的是直接在某種處理器上直接執(zhí)行(Linux的.so祟峦,如/lib/ glibc-2.5.so罚斗;Windows的DLL)

三、優(yōu)點

It very substantially improves load times of your DSO (Dynamic Shared Object). For example, a huge C++ template-based library which was tested (the TnFOX Boost.Python bindings library) now loads in eight seconds rather than over six minutes!

可減少動態(tài)共享庫的載入時間

It lets the optimiser produce better code. PLT indirections (when a function call or variable access must be looked up via the Global Offset Table such as in PIC code) can be completely avoided, thus substantially avoiding pipeline stalls on modern processors and thus much faster code. Furthermore when most of the symbols are bound locally, they can be safely elided (removed) completely through the entire DSO. This gives greater latitude especially to the inliner which no longer needs to keep an entry point around "just in case".

可完全避免過程鏈接表(PLT)的間接性訪問過程:在PIC代碼中的函數(shù)調用或者變量的訪問需要通過全局偏移表用于物理位置的查找宅楞。因此可大幅減少對于處理器的管線停滯针姿,并且,大部分符號是本地綁定的厌衙,DSO可進行安全的移除操作距淫。

It reduces the size of your DSO by 5-20%. ELF's exported symbol table format is quite a space hog, giving the complete mangled symbol name which with heavy template usage can average around 1000 bytes. C++ templates spew out a huge amount of symbols and a typical C++ library can easily surpass 30,000 symbols which is around 5-6Mb! Therefore if you cut out the 60-80% of unnecessary symbols, your DSO can be megabytes smaller!
Much lower chance of symbol collision. The old woe of two libraries internally using the same symbol for different things is finally behind us with this patch. Hallelujah!

減少動態(tài)庫大小。由于ELF導入的符號表格式中的完全獨立的標識使用了重量級的模板婶希,導致符號表格式所占空間甚大榕暇。基于此喻杈,減少不必要的全局符號將大大縮減動態(tài)共享庫彤枢,并且調用者的解析成本隨之而降;與此同時奕塑,還將大幅度降低符號沖突的幾率堂污。哈利路亞!龄砰!

四盟猖、使用

GCC4.0提供了-fvisibility編譯選項讨衣,其可選取值為default或者hidden:前者表示,編譯對象中對于沒有顯式地設置為隱藏的符號式镐,其屬性均表示對外可見反镇;后者則將隱藏沒有進行顯式設置的符號。對于編譯沒有顯式指定的情況娘汞,則GCC編譯前將使用-fvisibility=default歹茶,表示庫的符號均對外可見。

針對于編譯選項你弦,GCC使用優(yōu)先級更高的attribute機制用于設置符號的可見性屬性惊豺,其設置對象包括變量、函數(shù)禽作、模板尸昧、C++類等。所以旷偿,一般在共享庫烹俗,尤其是大型的動態(tài)庫中,編譯使用-fvisibility=default用于進行全局符號的隱藏設置萍程,將需要向外展示的符號則用attribute((visibility("default"))進行覆蓋性的設置幢妄。

代碼示例:

int a(int n) {return n;}  
   
__attribute__((visibility("hidden"))) int b(int n) {return n;}  
   
__attribute__((visibility("default"))) int c(int n) {return n;}  
   
class X  
{  
    public:  
        virtual ~X();  
};  
   
class __attribute__((visibility("hidden"))) Y  
{  
    public:  
        virtual ~Y();  
};  
   
class __attribute__((visibility("default"))) Z  
{  
    public:  
        virtual ~Z();  
};  
   
X::~X() { }  
Y::~Y() { }  
Z::~Z() { }  

五、批量設置--pragmas

Another way to mark symbols as default or hidden is with a new pragma in GCC 4.0. The GCC visibility pragma has the advantage of being able to mark a block of functions quickly, without the need to apply the visibility attribute to each one.

GCC還提供了批量設置的方法茫负,即使用pragmas關鍵字剂娄,進行快速的塊符號標記寸谜。

void f() { }  
   
# pragma GCC visibility push(default)  
void g() { }  
void h() { }  
# pragma GCC visibility pop

六翰撑、符號可見性設置的場景

If your library exports a C++ interface, the symbols associated with that interface must be visible.

如果導出某c++接口犁嗅,與其關聯(lián)的符號必須設置為可見。

If your symbol uses runtime type identification (RTTI) information, exceptions, or dynamic casts for an object that is defined in another library, your symbol must be visible if it expects to handle requests initiated by the other library. For example, if you define a catch handler for a type in the C++ standard library, and you want to catch exceptions of that type thrown by the C++ standard library, you must make sure that your typeinfo object is visible.

如果某一符號使用了定義于其他庫的對象信息缔赠,RTTI衍锚,異常,動態(tài)轉換等嗤堰,那么在希望處理由其他庫發(fā)起的請求的時候戴质,該符號必須設置為visible。

If you expect the address of an inline function used in different code modules to be the same for each module, the function must be exported from each code module.

如果希望不同模塊都使用的某一內嵌函數(shù)其地址保持一致踢匣,則該函數(shù)必須設置為visibile告匠。

If your inline function contains a static object and you expect there to be only one copy of that object, your symbol for that static object must be visible.

如果某一內嵌函數(shù)包含了一個靜態(tài)對象,且希望該對象為單例离唬,則該對象必須設置為visible后专。

七、引申

關于GCC的attribute機制:

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末输莺,一起剝皮案震驚了整個濱河市戚哎,隨后出現(xiàn)的幾起案子裸诽,更是在濱河造成了極大的恐慌,老刑警劉巖型凳,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件丈冬,死亡現(xiàn)場離奇詭異,居然都是意外死亡甘畅,警方通過查閱死者的電腦和手機埂蕊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來疏唾,“玉大人蓄氧,你說我怎么就攤上這事≥┦担” “怎么了匀们?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長准给。 經常有香客問我,道長重抖,這世上最難降的妖魔是什么露氮? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮钟沛,結果婚禮上畔规,老公的妹妹穿的比我還像新娘。我一直安慰自己恨统,他們只是感情好叁扫,可當我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著畜埋,像睡著了一般莫绣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上悠鞍,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天对室,我揣著相機與錄音,去河邊找鬼咖祭。 笑死掩宜,一個胖子當著我的面吹牛,可吹牛的內容都是我干的么翰。 我是一名探鬼主播牺汤,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼浩嫌!你這毒婦竟也來了檐迟?” 一聲冷哼從身側響起戴已,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎锅减,沒想到半個月后糖儡,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡怔匣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年握联,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片每瞒。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡金闽,死狀恐怖,靈堂內的尸體忽然破棺而出剿骨,到底是詐尸還是另有隱情代芜,我是刑警寧澤,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布浓利,位于F島的核電站挤庇,受9級特大地震影響,放射性物質發(fā)生泄漏贷掖。R本人自食惡果不足惜嫡秕,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望苹威。 院中可真熱鬧昆咽,春花似錦、人聲如沸牙甫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽窟哺。三九已至泻轰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間脏答,已是汗流浹背糕殉。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留殖告,地道東北人阿蝶。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像黄绩,于是被迫代替她去往敵國和親羡洁。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內容

  • PLEASE READ THE FOLLOWING APPLE DEVELOPER PROGRAM LICENSE...
    念念不忘的閱讀 13,471評論 5 6
  • **2014真題Directions:Read the following text. Choose the be...
    又是夜半驚坐起閱讀 9,497評論 0 23
  • 十年爽丹,說長不長筑煮,說短不短辛蚊。百歲老人,不過是眨眼之間真仲,短壽者已經死了好幾回了袋马。憨山大師說:死生晝夜,水流花謝秸应。今日乃...
    8724a133b8a3閱讀 619評論 1 3
  • 剛剛更新了公眾號虑凛,就有一個朋友在后臺給我們發(fā)消息。 她告訴我她和一個男生聊了很久的天软啼,很依賴他桑谍,想戒又戒不掉,每天...
    ZY工作室閱讀 310評論 0 0