gcc 的visibility 使用

本文深入探讨GCC编译器的-fvisibility属性,解释如何通过设置默认ELF图像符号可见性来优化共享对象库,减少链接和加载时间,提供近乎完美的API导出并防止符号冲突。文章通过实际示例演示了如何使符号默认为隐藏,仅标记特定符号为公开,从而实现更高效的代码生成。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转:

-fvisibility=default|internal|hidden|protected

-fvisibility=[default|internal|hidden|protected]
           Set the default ELF image symbol visibility to the specified option---all symbols are marked with this unless overridden within the code.  Using this
           feature can very substantially improve linking and load times of shared object libraries, produce more optimized code, provide near-perfect API export
           and prevent symbol clashes.  It is strongly recommended that you use this in any shared objects you distribute.

           Despite the nomenclature, default always means public; i.e., available to be linked against from outside the shared object.  protected and internal are
           pretty useless in real-world usage so the only other commonly used option is hidden.  The default if -fvisibility isn't specified is default, i.e., make
           every symbol public.

           A good explanation of the benefits offered by ensuring ELF symbols have the correct visibility is given by "How To Write Shared Libraries" by Ulrich
           Drepper (which can be found at <http://www.akkadia.org/drepper/>)---however a superior solution made possible by this option to marking things hidden
           when the default is public is to make the default hidden and mark things public.  

gcc的visibility是说,如果编译的时候用了这个属性,那么动态库的符号都是visibility指定的属性,除非强制声明。


1.创建一个c源文件,内容简单

#include<stdio.h>
#include<stdlib.h>


__attribute ((visibility("default"))) void not_hidden ()
{
printf("exported symbol\n");
}

void is_hidden ()
{
printf("hidden one\n");
}

想要做的是,第一个函数符号可以被导出,第二个被隐藏。
先编译成一个动态库,使用到属性-fvisibility

gcc -shared -o libvis.so -fvisibility=hidden vis.c

现在查看

# readelf -s libvis.so |grep hidden
48: 00000420    20 FUNC    LOCAL  HIDDEN   11 is_hidden
51: 0000040c    20 FUNC    GLOBAL DEFAULT   11 not_hidden


可以看到,属性确实有作用了。

现在试图link

vi main.c
int main()
{
not_hidden();
is_hidden();
return 0;
}

试图编译成一个可执行文件,链接到刚才生成的动态库,

gcc -o exe main.c -L ./ -lvis


结果提示:

/tmp/cckYTHcl.o: In function `main':
main.c:(.text+0x17): undefined reference to `is_hidden'

说明了hidden确实起到作用了。

自己实测参数情况

//__attribute__ ((visibility ("internal")))  调用地方会被优化成内嵌汇编,没有函数
//__attribute__ ((visibility ("hidden")))    调用地方会被优化成内嵌汇编,没有函数

//__attribute__ ((visibility ("protected"))) 调用地方会被优化成内嵌汇编,有函数,使用dlsym可以找到
//14: 00005491    36 FUNC    GLOBAL PROTECTED   12 add

//__attribute__ ((visibility ("default")))     调用地方会被优化成内嵌汇编,有函数,使用dlsym可以找到
//  14: 00005461    36 FUNC    GLOBAL DEFAULT   12 add



void JNICALL analyzor(void)
{
	CLog::setHookedProcessName("HookModule");
	add(3);
}

void add(int a)
{
	CLog::logInfo("add");
	a = a+ 1;
	CLog::logInfo("add %d",a);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值