C++ 隐藏所有函数符号,除了我在共享库中指定的
C++ hide all function symbols except for what I specify in a shared library
在我的示例代码中:
main.cpp
#include <iostream>
#if defined(_WIN32) || defined(__WIN32__)
#define EXPORT extern "C" __declspec(dllexport)
#elif defined(linux) || defined(__linux)
#define EXPORT __attribute__((visibility("default")))
#endif
EXPORT void hello()
{
std::cout<<"Hello world!"<<std::endl;
}
/* not exported */ void goodbye()
{
std::cout<<"Goodbye!"<<std::endl;
}
通过如下选项编译:
CMakeLists.txt
cmake_minimum_required(VERSION 2.8.9)
project(my_test)
add_library(output SHARED
main.cpp
)
set(CMAKE_CXX_COMPILER "g++")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s -Wall -Wextra -std=c++17 -fvisibility=hidden -fvisibility-inlines-hidden")
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdata-sections -ffunction-sections")
#set (CMAKE_SHARED_LINKER_FLAGS "-Wl,--gc-sections -Wl,--strip-all")
我看到的是符号而不是 hello
函数:
nm -D liboutput.so
结果:
U __cxa_atexit
w __cxa_finalize
w __gmon_start__
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
0000000000001179 T _Z5hellov
U _ZNSolsEPFRSoS_E
U _ZNSt8ios_base4InitC1Ev
U _ZNSt8ios_base4InitD1Ev
U _ZSt4cout
U _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
U _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
我不希望 _ZSt4cout
等功能从外部可见。即使我启用了cmake配方的最后两行,我的问题也没有解决。
我怎样才能做到这一点?
您的方法是正确的,但您的程序包含一些未定义的符号,需要在启动时从 libstdc++
导入(例如 std::cout
)。链接器必须在你的库的符号中插入这样的符号 table,否则加载器将不知道它们需要被导入。
您可以 link 针对静态版本的 STL(通过 -static-libstdc++
)并应用版本脚本来防止 link 用户从您的共享库中导出 STL 符号:
$ cat foo.map
{
global:
_Z3foov; # Export only foo
local: *; # Hide everything else
};
$ g++ tmp.o -fPIC -shared -static-libstdc++ -Wl,--version-script=foo.map
请注意,link静态使用 STL 会导致代码膨胀。
在我的示例代码中:
main.cpp
#include <iostream>
#if defined(_WIN32) || defined(__WIN32__)
#define EXPORT extern "C" __declspec(dllexport)
#elif defined(linux) || defined(__linux)
#define EXPORT __attribute__((visibility("default")))
#endif
EXPORT void hello()
{
std::cout<<"Hello world!"<<std::endl;
}
/* not exported */ void goodbye()
{
std::cout<<"Goodbye!"<<std::endl;
}
通过如下选项编译:
CMakeLists.txt
cmake_minimum_required(VERSION 2.8.9)
project(my_test)
add_library(output SHARED
main.cpp
)
set(CMAKE_CXX_COMPILER "g++")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s -Wall -Wextra -std=c++17 -fvisibility=hidden -fvisibility-inlines-hidden")
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdata-sections -ffunction-sections")
#set (CMAKE_SHARED_LINKER_FLAGS "-Wl,--gc-sections -Wl,--strip-all")
我看到的是符号而不是 hello
函数:
nm -D liboutput.so
结果:
U __cxa_atexit
w __cxa_finalize
w __gmon_start__
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
0000000000001179 T _Z5hellov
U _ZNSolsEPFRSoS_E
U _ZNSt8ios_base4InitC1Ev
U _ZNSt8ios_base4InitD1Ev
U _ZSt4cout
U _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
U _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
我不希望 _ZSt4cout
等功能从外部可见。即使我启用了cmake配方的最后两行,我的问题也没有解决。
我怎样才能做到这一点?
您的方法是正确的,但您的程序包含一些未定义的符号,需要在启动时从 libstdc++
导入(例如 std::cout
)。链接器必须在你的库的符号中插入这样的符号 table,否则加载器将不知道它们需要被导入。
您可以 link 针对静态版本的 STL(通过 -static-libstdc++
)并应用版本脚本来防止 link 用户从您的共享库中导出 STL 符号:
$ cat foo.map
{
global:
_Z3foov; # Export only foo
local: *; # Hide everything else
};
$ g++ tmp.o -fPIC -shared -static-libstdc++ -Wl,--version-script=foo.map
请注意,link静态使用 STL 会导致代码膨胀。