C/C++程序隐藏符号
使用visibility
#if defined _WIN32 || defined __CYGWIN__
#ifdef MY_NO_EXPORT
#define API
#else
#define API __declspec(dllexport)
#endif
#else
#ifdef __GNUC__
#define API __attribute__((visibility("default")))
#else
#define API
#endif
#endif
#if defined __cplusplus
#define EXTERN extern "C"
#else
#include <stdarg.h>
#include <stdbool.h>
#define EXTERN extern
#endif
#define MY_API EXTERN API
GNU C 的一大特色就是attribute 机制。
试想这样的情景,程序调用某函数A,A函数存在于两个动态链接库liba.so,libb.so中,并且程序执行需要链接这两个库,此时程序调用的A函数到底是来自于a还是b呢?
这取决于链接时的顺序,比如先链接liba.so,这时候通过liba.so的导出符号表就可以找到函数A的定义,并加入到符号表中,链接libb.so的时候,符号表中已经存在函数A,就不会再更新符号表,所以调用的始终是liba.so中的A函数。
为了避免这种混乱,所以使用
__attribute__((visibility("default"))) //默认,设置为:default之后就可以让外面的类看见了。
__attribute__((visibility("hideen"))) //隐藏
设置这个属性。
visibility
用于设置动态链接库中函数的可见性,将变量或函数设置为hidden
,则该符号仅在本so中可见,在其他库中则不可见。
g++在编译时,可用参数-fvisibility
指定所有符号的可见性(不加此参数时默认外部可见,参考man g++中-fvisibility部分);若需要对特定函数的可见性进行设置,需在代码中使用attribute设置visibility属性。
编写大型程序时,可用-fvisibility=hidden
设置符号默认隐藏,针对特定变量和函数,在代码中使用attribute ((visibility("default")))
另该符号外部可见,这种方法可用有效避免so之间的符号冲突。
经在代码中测试,
C++的extern __attribute__((visibility("default")))
会导出函数参数,
C的extern "C" __attribute__((visibility("default")))
的方式不会导出函数参数,两者不能通用。
使用version-script
set_target_properties(your_so_or_exe PROPERTIES LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/symbol.version")
symbol.version:
{
global:JNI_OnLoad;JNI_OnUnload;Java_*;usedFun;
local:*;
};
我最擅长从零开始创造世界,所以从来不怕失败,它最多也就让我一无所有。