【PE】Windows和Linux平台下API符号导出方法
Date: 2018.6.23
1、参考:
https://blog.csdn.net/fengbingchun/article/details/78898623
https://blog.csdn.net/mutourenzhang/article/details/47803803
2、Windows下API符号导出方法
windows中的函数默认是内部的,如果希望某些函数对外部可见或者引用库函数,需要导出。
导出方法1:
#if defined(_MSC_VER) &&defined(_USRDLL)
#ifdef API_EXPORT
#define API __declspec(dllexport)
#else
#define API __declspec(dllimport)
#endif
#endif
对应动态库本身,打开_USRDLL宏和API_EXPORT宏,将希望对外部可见的函数或符号导出;
对应调用动态库的demo,只需要打开_USRLL宏,从而将动态库中对外部可见的函数导入。
导出方法2:
或者采用模块定义文件(.def),将需要导出的符号写到def文件中,格式如下:
EXPORTS FUNCTION
a
b
c
add
sub
mul
div
VS项目属性—》配置属性—》链接器—》输入—》模块定义文件中,配置def文件,在编译动态库时,就会将def中指定的符号导出。
3、Linux下API符号导出方法
在Linux下动态库(.so)中,通过GCC的C++ visibility属性可以控制共享文件导出符号。在GCC 4.0及以上版本中,有个visibility属性,可见属性可以应用到函数、变量、模板以及C++类。
限制符号可见性的原因:从动态库中尽可能少地输出符号是一个好的实践经验。输出一个受限制的符号会提高程序的模块性,并隐藏实现的细节。动态库装载和识别的符号越少,程序启动和运行的速度就越快。导出所有符号会减慢程序速度,并耗用大量内存。
“default”:用它定义的符号将被导出,动态库中的函数默认是可见的。
”hidden”:用它定义的符号将不被导出,并且不能从其它对象进行使用,动态库中的函数默认是被隐藏的。
default意味着该方法对其它模块是可见的。而hidden表面该函数/符号不会被放到动态符号表里,所以其它模块(可执行文件或者动态库)不可以通过符号表访问该方法。
要定义GNU属性,需要包含attribute和用括号括住的内容。可以将符号的可见性指定为visibility(“hidden”),这将不允许它们在库中被导出,但是可以在源文件之间共享。实际上,隐藏的符号将不会出现在动态符号表中,但是还被留在符号表中用于静态链接。
导出列表由编译器在创建共享库的时候自动生成,也可以由开发人员手工编写。导出列表的原理是显式地告诉编译器可以通过外部文件从对象文件导出的符号是哪些。GNU用户将此类外部文件称作为”导出映射”。
在linux中,动态库makefile中make cflag或ldflags配置为:CFLAGS+= -fvisibility=hidden 即默认动态库中的函数符号都是隐藏的。对于想要导出的函数符号,指定为:attribute((visibility(“default”))),在代码中指定:
#if __GNC__ >=4
#if defined(API_EXPORT)
#define API_OUT __attribute__((visibility("default")))
#define API_LOCAL __attribute__((visibility("hidden")))
#elif defined(API_IMPORT)
#define API __attribute__((visibility("default")))
#endif
#endif