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关键字,用于限制函数或变量的可见性,但只作用于当前文件。而共享库(或动态库)可能包含多个文件,如果需要将某个符号在库内的多文件间可见,隐藏符号会变得比较棘手。许多链接器提供了将一个模块的所有符号进行隐藏或导出的方法,但这却失去了对符号的可见性控制。

二、目的

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类操作系统中普遍采用的目标文件格式文件包含了代码、数据,而有些更包含了符号表、调试信息、行号信息、字符串等。

目标形式:
目标文件有三种类型:

  1. 可重定位文件(Relocatable File) 包含适合于与其他目标文件链接来创建可执行文件或者共享目标文件的代码和数据。 (Linux的*.o 文件 Windows的 *.obj文件)
  2. 可执行文件(Executable File) 包含适合于执行的一个程序,此文件规定了 exec() 如何创建一个程序的进程映像。(比如/bin/bash文件;Windows的*.exe)
  3. 共享目标文件(Shared Object File) 包含可在两种上下文中链接的代码和数据。首先链接编辑器可以将它和其它可重定位文件和共享目标文件一起处理,生成另外一个目标文件。其次,动态链接器(Dynamic Linker)可能将它与某个可执行文件以及其它共享目标一起组合,创建进程映像。
    目标文件全部是程序的二进制表示,目的是直接在某种处理器上直接执行(Linux的.so,如/lib/ glibc-2.5.so;Windows的DLL)

三、优点

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!

可减少动态共享库的载入时间

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代码中的函数调用或者变量的访问需要通过全局偏移表用于物理位置的查找。因此可大幅减少对于处理器的管线停滞,并且,大部分符号是本地绑定的,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!

减少动态库大小。由于ELF导入的符号表格式中的完全独立的标识使用了重量级的模板,导致符号表格式所占空间甚大。基于此,减少不必要的全局符号将大大缩减动态共享库,并且调用者的解析成本随之而降;与此同时,还将大幅度降低符号冲突的几率。哈利路亚!!

四、使用

GCC4.0提供了-fvisibility编译选项,其可选取值为default或者hidden:前者表示,编译对象中对于没有显式地设置为隐藏的符号,其属性均表示对外可见;后者则将隐藏没有进行显式设置的符号。对于编译没有显式指定的情况,则GCC编译前将使用-fvisibility=default,表示库的符号均对外可见。

针对于编译选项,GCC使用优先级更高的attribute机制用于设置符号的可见性属性,其设置对象包括变量、函数、模板、C++类等。所以,一般在共享库,尤其是大型的动态库中,编译使用-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++接口,与其关联的符号必须设置为可见。

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,异常,动态转换等,那么在希望处理由其他库发起的请求的时候,该符号必须设置为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.

如果希望不同模块都使用的某一内嵌函数其地址保持一致,则该函数必须设置为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.

如果某一内嵌函数包含了一个静态对象,且希望该对象为单例,则该对象必须设置为visible。

七、引申

关于GCC的attribute机制:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容