一种跨平台的C/C++动态库的符号隐藏方式
源地址:http://blog.guorongfei.com/2018/04/11/symbol-visibility/
<h1 id="什么是符号隐藏"><a href="#什么是符号隐藏" class="headerlink" title="什么是符号隐藏"></a>什么是符号隐藏</h1><p>在同一个文件中,如果有一些函数我们并不想要让外部访问,我们通常会添加 static
修饰符,把它设置为内部链接属性。
1 |
static void foo(); |
但是通常库不太可能是单文件组成,这些文件中有些是做接口给外部使用,有些则单纯的只是库的内部实现。对于外部使用者来说,内部实现的这些符号没有实际的作用,理论上我们完全可以像对待文件内部符号一样把它们统统隐藏掉。但是在语言层面我们并没有相关的语法用于表达这个概念(Java中的包访问权限和C#中的internal类似这个概念)。不同的编译器提供了不同的方式来完成这件事情,这篇文章总结了一种跨平台的处理方式。
符号隐藏的作用
一般来说做符号隐藏有以下三个作用:
- 安全,去掉不必要的符号,可以增加逆向破解的难度。
- 压缩空间,符号实际上是放在 dll 中的,去掉这些符号可以缩减 dll 的大小
- 性能,符号隐藏掉意味着它不会参与到动态链接过程,编译器可以有更大的优化空间,可能会产生更好的性能。
如何做符号隐藏
符号隐藏可以采用下面几个步骤(文中假定你使用MSVC或者4.0以上版本的GCC,低版本GCC不支持符号隐藏):
1. 动态库
符号能否隐藏在于它在动态链接的过程中是否需要用到。静态库实际上是目标文件的集合,它并没有完成链接过程。所以符号隐藏通常都是基于动态库的,静态库的符号隐藏没有很好的跨平台方式,如果想要尝试,可以参考下面这些链接。
How to apply gcc -fvisibility option to symbols in static libraries?
Symbol hiding in static libraries built with Xcode/gcc
2. 默认隐藏所有的符号
MSVC和GCC在动态库符号的默认属性上面有较大的差别,MSVC默认所有的符号都是隐藏的,而GCC默认所有的符号都是可见的。虽然我不太喜欢臃肿的MSVC,但是我不得不承认在这一点上,我更倾向于MSVC的选择。
如果你使用MSVC
编译器,这个步骤你可以什么都不做,如果你使用GCC,你需要给你的编译器加上-fvisibility=hidden
选项,你也可以加上-fvisibility-inlines-hidden
把内联函数隐藏掉。如果你使用Autotool
,你可以通过设置LD_CXXFLAG
来控制默认隐藏,如果你使用CMake
,可以通过set(CMAKE_CXX_VISIBILITY_PRESET hidden)
来完成这一点。
3. 把你想要公开的接口的属性设置为外部可见
在MSVC中,我们通过在编译的时候设置__declspec(dllimport)
和使用的时候设置__declspec(dllexport)
来完成这一点,在GCC中则简单一些统一设置成__attribute__ ((visibility ("default")))
即可。
辅助宏
上面这些步骤比较繁琐,通常会定义宏来协助处理这一部分内容,下面是来自GCC WIKI
的一个模板
1234567891011121314151617181920212223242526272829303132 |
// Generic helper definitions for shared library support#if defined _WIN32 || defined __CYGWIN__ #define FOX_HELPER_DLL_IMPORT __declspec(dllimport) #define FOX_HELPER_DLL_EXPORT __declspec(dllexport) #define FOX_HELPER_DLL_LOCAL#else #if __GNUC__ >= 4 #define FOX_HELPER_DLL_IMPORT __attribute__ ((visibility ("default"))) #define FOX_HELPER_DLL_EXPORT __attribute__ ((visibility ("default"))) #define FOX_HELPER_DLL_LOCAL __attribute__ ((visibility ("hidden"))) #else #define FOX_HELPER_DLL_IMPORT #define FOX_HELPER_DLL_EXPORT #define FOX_HELPER_DLL_LOCAL #endif#endif // Now we use the generic helper definitions above to define FOX_API and FOX_LOCAL.// FOX_API is used for the public API symbols. It either DLL imports or DLL exports (or does nothing for static build)// FOX_LOCAL is used for non-api symbols. #ifdef FOX_DLL // defined if FOX is compiled as a DLL #ifdef FOX_DLL_EXPORTS // defined if we are building the FOX DLL (instead of using it) #define FOX_API FOX_HELPER_DLL_EXPORT #else #define FOX_API FOX_HELPER_DLL_IMPORT #endif // FOX_DLL_EXPORTS #define FOX_LOCAL FOX_HELPER_DLL_LOCAL#else // FOX_DLL is not defined: this means FOX is a static lib. #define FX_API #define FOX_LOCAL#endif // FOX_DLL |
我们想要导出一个符号的时候使用FOX_API
:
1 |
class FOX_API Fox {}; |
在编译动态库的时候,设置FOX_DLL
和FOX_DLL_EXPORTS
这两个宏。在使用动态库的是,定义FOX_DLL
这个宏。
</div>
一种跨平台的C/C++动态库的符号隐藏方式相关推荐
- 分析Windows和Linux动态库
摘要:动态链接库技术实现和设计程序常用的技术,在Windows和Linux系统中都有动态库的概念,采用动态库可以有效的减少程序大小,节省空间,提高效率,增加程序的可扩展性,便于模块化管理.但不同操作系 ...
- Windows和Linux动态库比较 (Zhuan)
Windows和Linux动态库比较 Description: 摘要:动态链接库技术实现和设计程序常用的技术,在Windows和Linux系统中都有动态库的概念,采用动态库 可以有效的减少程序大小,节 ...
- Linux动态库(.so)搜索路径
众所周知,Linux动态库的默认搜索路径是/lib和/usr/lib.动态库被创建后,一般都复制到这两个目录中.当程序执行时需要某动态库,并且该动 态库还未加载到内存中,则系统会自动到这两个默认搜索路 ...
- Linux中gcc的编译、静态库和动态库的制作
欢迎大家关注笔者,你的关注是我持续更博的最大动力 Linux中gcc的编译.静态库.动态库 文章目录: 1 gcc的编译过程 1.1 gcc的编译过程 1.2 gcc的常用参数 2 gcc 静态库的制 ...
- linux命令之查看动态库符号-nm
在调用动态库的时候,经常出现由于动态库接口修改或者版本不匹配导致调用动态库找不到函数接口符号的情况. 原因可能有如下几种: 1.由于c++动态库编译没有加extern c导致函数编译时加了c++的前缀 ...
- linux定位so快捷方式_Linux动态库(.so)搜索路径 | 学步园
众所周知,Linux动态库的默认搜索路径是/lib和/usr/lib.动态库被创建后,一般都复制到这两个目录中.当程序执行时需要某动态库, 并且该动 态库还未加载到内存中,则系统会自动到这两个默认搜索 ...
- Linux库概念及相关编程(动态库、静态库、环境变量)
分文件编程: 好处:分模块编程思想,功能和责任划分清楚便与调试,main函数简洁,代码易于阅读. 编程时头文件有的是使用<>这个符号括起来的,有的是" "使用的是双引号 ...
- 计算机科学基础知识(四): 动态库和位置无关代码
一.前言 本文主要描述了动态库以及和动态库有紧密联系的位置无关代码的相关资讯.首先介绍了动态库和位置无关代码的源由,了解这些背景知识有助于理解和学习动态库.随后,我们通过加-fPIC和不加这个编译选项 ...
- linux下生成静态库和动态库
linux下生成静态库和动态库 一.动态库.静态库简介 库是写好的现有的,成熟的,可以复用的代码.现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常.本质上 ...
- Visual Studio 2010 Win32 Usb HID 动态库创建
一.概述 最近在项目中使用md5和sh1 算法,发现在原来的工程上,加上这两个算法的源代码竟然编译不能通过,出现100 多个bug.后来上来发现错误都是源于两个算法使用的一个头文件"StdI ...
最新文章
- 关于JS阶乘,首字母大写,最长单词计算,重复说话次数等简单基础算法练习...
- 2021-9-下旬 数据结构-线性表-队列-java代码实现(复习用)
- 【杂谈】篇篇精华,有三AI不得不看的技术综述(超过100篇核心干货)
- 大厂经验(二):多端可视化埋点解决方案
- ubuntu 下载速度快但网页打开慢的解决方法
- Android NDK开发之 NDK 局部 全局引用
- jQuery 生成随机字符
- windows8 初始界面和功能
- 迅雷下载百度网盘的资源
- c++多线程detach函数用法的实例
- 清华大学计算机相关夏令营,夏令营报名
- 小米高通系列清串号打开写号端口工具_手机sn码序列号修改工具,高通串号永久写入!...
- MLC的寿命是否真如厂商标称的只有3000次?论原装芯片测试的重要性!
- Linux的root权限安装nvm后可用,切换用户以后报nvm: command not found解决办法
- 建模语言UML在软件开发中的应用
- 双球坐标系_天球坐标系 - 中文百科
- 智能家居DIY之智能吸顶灯
- 心系冬奥 翰墨传情 |当代书画名家为奥运加油书画推介展【戴志军篇】
- 能运行Linux电脑,国外达人亲手打造可以运行Linux的名片
- 全国区号与邮政编码XML文件