2019独角兽企业重金招聘Python工程师标准>>>
我们知道,GCC/G++编译出来的二进制文件默认情况下会导出所有的符号表。在实际应用过程中,我们也许出于安全或者其他的原因,不想导出内部所有的符号表,只导出必要的接口给用户使用。此时我们可以利用 GCC/G++ 的 -fvisibility=hidden 选项配合代码的 __attribute__ ((visibility("default"))) 实现。
(1)默认情况,导出所有符号表:
示例代码如下:
test.h:
#ifndef __TEST_H__
#define __TEST_H__
#ifdef __cplusplus
extern "C" {
#endif
void globalDump1();
void globalDump2();
class Dump {
public:
Dump();
~Dump();
void classDump1();
void classDump2();
};
#ifdef __cplusplus
}
#endif
#endif
test.cc:
#include
#include "test.h"
void globalDump1() {
std::cout << "globalDump1" << std::endl;
}
void globalDump2() {
std::cout << "globalDump2" << std::endl;
}
Dump::Dump() {}
Dump::~Dump() {}
void Dump::classDump1() {
std::cout << "classDump1" << std::endl;
}
void Dump::classDump2() {
std::cout << "classDump2" << std::endl;
}
编译命令如下:$ g++ -v -I. -fPIC -shared -o libtest.so test.cc
可以使用 nm 命令查看符号表,如下:
$ nm -CD libtest.so
0000000000201050 B __bss_start
U __cxa_atexit
w __cxa_finalize
0000000000201050 D _edata
0000000000201058 B _end
0000000000000bc0 T _fini
0000000000000a86 T globalDump1
0000000000000ab4 T globalDump2
w __gmon_start__
0000000000000908 T _init
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
w _Jv_RegisterClasses
0000000000000af6 T Dump::classDump1()
0000000000000b2c T Dump::classDump2()
0000000000000ae2 T Dump::Dump()
0000000000000ae2 T Dump::Dump()
0000000000000aec T Dump::~Dump()
0000000000000aec T Dump::~Dump()
U std::ostream::operator<<(std::ostream& (*)(std::ostream&))
U std::ios_base::Init::Init()
U std::ios_base::Init::~Init()
U std::cout
U std::basic_ostream
U std::basic_ostream
(2)增加 -fvisibility=hidden 选项和 __attribute__(("default")),只导出 globalDump1() 和 classDump1() 两个接口:
test.h修改如下:
#ifndef __TEST_H__
#define __TEST_H__
#ifdef __cplusplus
extern "C" {
#endif
__attribute__ ((visibility("default"))) void globalDump1();
void globalDump2();
class Dump {
public:
__attribute__ ((visibility("default"))) Dump();
__attribute__ ((visibility("default"))) ~Dump();
__attribute__ ((visibility("default"))) void classDump1();
void classDump2();
};
#ifdef __cplusplus
}
#endif
#endif
编译命令修改如下:$ g++ -v -I. -fPIC -shared -fvisibility=hidden -o libtest.so test.cc
此时,再次查看编译出来的libtest.so符号表如下:
$ nm -CD libtest.so
0000000000201050 B __bss_start
U __cxa_atexit
w __cxa_finalize
0000000000201050 D _edata
0000000000201058 B _end
0000000000000b50 T _fini
0000000000000a16 T globalDump1
w __gmon_start__
00000000000008a0 T _init
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
w _Jv_RegisterClasses
0000000000000a86 T Dump::classDump1()
0000000000000a72 T Dump::Dump()
0000000000000a72 T Dump::Dump()
0000000000000a7c T Dump::~Dump()
0000000000000a7c T Dump::~Dump()
U std::ostream::operator<<(std::ostream& (*)(std::ostream&))
U std::ios_base::Init::Init()
U std::ios_base::Init::~Init()
U std::cout
U std::basic_ostream
U std::basic_ostream
由此可见,只有 globalDump1() 和 classDump1() 被导出,globalDump2() 和 classDump2() 被隐藏,可以通过编写个可执行文件来测试。