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:*;
};
posted @ 2023-02-23 11:49  至尊王者  阅读(822)  评论(0编辑  收藏  举报