Pokud svou soukromou část zabalíte do anonymního jmenného prostoru, pak ani std::abs
ani private_function
lze vidět v tabulce symbolů:
namespace{
#include<cmath>
float private_function(float f)
{
return std::abs(f);
}
}
extern "C" float public_function(float f)
{
return private_function(f);
}
kompilace (g++ 4.3.3):
g++ -shared -o libtest.so test.cpp -s
kontrola:
# nm -DC libtest.so
w _Jv_RegisterClasses
0000200c A __bss_start
w __cxa_finalize
w __gmon_start__
0000200c A _edata
00002014 A _end
000004a8 T _fini
000002f4 T _init
00000445 T public_function
Jen pro povšimnutí, že Ulrich Drepper napsal esej týkající se (všech?) aspektů psaní sdílených knihoven pro Linux/Unix, která kromě mnoha dalších témat zahrnuje kontrolu exportovaných symbolů.
To bylo velmi užitečné, protože bylo jasné, jak exportovat pouze funkce na whitelistu ze sdílené knihovny.
Vaše použití výchozího atributu viditelnosti a -fvisibility=hidden by mělo být rozšířeno o -fvisibility-inlines-hidden.
Měli byste také zapomenout na pokusy skrýt exporty stdlib, proč se podívejte na tuto chybu GCC.
Pokud máte všechny své veřejné symboly v konkrétních záhlavích, můžete je zabalit do #pragma GCC visibility push(default)
a #pragma GCC visibility pop
místo použití atributů. I když vytváříte knihovnu pro více platforem, podívejte se na Controlling Exported Symbols of Shared Libraries, kde najdete techniku pro sjednocení vaší exportní strategie Windows DLL a Linux DSO.
Takže řešení, které nyní máme, je následující:
test.cpp
#include <cmath>
#include <vector>
#include <typeinfo>
struct private_struct
{
float f;
};
float private_function(float f)
{
return std::abs(f);
}
void other_private_function()
{
std::vector<private_struct> f(1);
}
extern "C" void __attribute__ ((visibility ("default"))) public_function2()
{
other_private_function();
}
extern "C" float __attribute__ ((visibility ("default"))) public_function1(float f)
{
return private_function(f);
}
exports.version
LIBTEST
{
global:
public*;
local:
*;
};
zkompilováno s
g++ -shared test.cpp -o libtest.so -fvisibility=hidden -fvisibility-inlines-hidden -s -Wl,--version-script=exports.version
dává
00000000 A LIBTEST
w _Jv_RegisterClasses
U _Unwind_Resume
U std::__throw_bad_alloc()
U operator delete(void*)
U operator new(unsigned int)
w __cxa_finalize
w __gmon_start__
U __gxx_personality_v0
000005db T public_function1
00000676 T public_function2
Což je docela blízko tomu, co hledáme. Existuje však několik problémů:
- Musíme zajistit, abychom v interním kódu nepoužili předponu „exportovaný“ (v tomto jednoduchém příkladu „veřejné“, ale v našem případě zjevně něco užitečnějšího).
- Mnoho názvů symbolů stále končí v tabulce řetězců, což se zdá být až na RTTI, -fno-rtti je v mých jednoduchých testech odstraní, ale je to spíše nukleární řešení.
Rád přijmu každé lepší řešení, se kterým kdokoli přijde!