Bei der Entwicklung einer gemeinsam genutzten Bibliothek Sie sollten öffentliche Symbole einschränken, um Missbrauch zu verhindern und die Leistung zu verbessern.
Wenn Sie es einfach auf den Dateibereich einstellen, können Sie es nicht einmal in der Bibliothek aus einer anderen Datei aufrufen. Auch im Fall von C ++ wird es, selbst wenn es sich um eine private Methode handelt, als Symbol nach außen angezeigt.
Daher werde ich drei Methoden einführen, um die Symbole zu steuern, die außerhalb der gemeinsam genutzten Bibliothek verfügbar sind.
__visibility__ (" default ")
hinzu angebenUnter Berücksichtigung der Wartungskosten und der Vermeidung von Leckagen [Methode 3](https://qiita.com/takeoverjp/items/d86fba2843faac955d4b#%E6%96%B9%E6%B3%953-%E3%83%87% E3% 83% 95% E3% 82% A9% E3% 83% AB% E3% 83% 88% E3% 82% 92% E9% 9D% 9E% E5% 85% AC% E9% 96% 8B% E3% 81% AB% E3% 81% 97% E3% 81% 9F% E4% B8% 8A% E3% 81% A7% E5% 85% AC% E9% 96% 8B% E9% 96% A2% E6% 95% B0% E3% 81% AB__visibility__default% E3% 82% 92% E6% 8C% 87% E5% AE% 9A% E3% 81% 99% E3% 82% 8B) ist die beste Methode.
Wir haben den Betrieb in der folgenden Umgebung bestätigt.
$ uname -m
x86_64
$ uname -r
5.5.8
$ lsb_release -d
Description: Ubuntu 18.04.5 LTS
$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/7/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 7.5.0-3ubuntu1~18.04' --with-bugurl=file:///usr/share/doc/gcc-7/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-7 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)
Die folgende "MyClass" ist in der gemeinsam genutzten Bibliothek definiert, und die folgenden Anforderungen sind erforderlich.
・ Konstruktor / Destruktor und öffentliche Methode sind öffentlich zugänglich ・ Private Methode ist privat
sample.h
class MyClass {
public:
MyClass();
~MyClass();
void PublicMethod();
int PublicMethodWithArgs(int argc, char* argv[]);
private:
void PrivateMethod();
int PrivateMethodWithArgs(int argc, char* argv[]);
};
Die öffentlichen Symbole lauten wie folgt: Sie können sehen, dass die private Methode ebenfalls veröffentlicht wird.
$ g++ -W -Werror -shared -fPIC -o libsample.so sample.cc
$ nm -gC libsample.so | awk '$2=="T"' | grep MyClass
0000000000000722 T MyClass::PublicMethod()
0000000000000740 T MyClass::PrivateMethod()
000000000000072e T MyClass::PublicMethodWithArgs(int, char**)
000000000000074c T MyClass::PrivateMethodWithArgs(int, char**)
000000000000070a T MyClass::MyClass()
000000000000070a T MyClass::MyClass()
0000000000000716 T MyClass::~MyClass()
0000000000000716 T MyClass::~MyClass()
Sie können die exponierten Symbole einschränken, indem Sie das Versionsskript für "ld" angeben.
Das in "global:" beschriebene Symbol wird veröffentlicht, und das in "local:" beschriebene Symbol ist privat.
Sie können die Platzhalter *
und ?
Verwenden.
Im Fall von C ++ ist es entstellt, also fügen Sie es in "extern" C ++ "" ein
Und Sie müssen den Platzhalter *
nach dem Methodennamen angeben.
Infolgedessen kann es auf unbeabsichtigte Methoden angewendet werden.
Die Zeile "MyClass ::? MyClass *" dient übrigens zum Offenlegen des Destruktors. Da "~" in der Grammatik des Versionsskripts ungültig ist, wird stattdessen der Platzhalter "?" Verwendet. Dies kann auch für unbeabsichtigte Methoden gelten.
sample.map
{
global:
extern "C++" {
MyClass::MyClass*;
MyClass::?MyClass*;
MyClass::PublicMethod*;
};
local:
*;
};
Das Ergebnis der Erstellung mit dem oben angegebenen Versionsskript und der Überprüfung der Symbole ist wie folgt. Die private Methode ist privat.
$ g++ -W -Werror -shared -fPIC -Wl,--version-script=sample.map -o libsample.so sample.cc
$ nm -gC libsample.so | awk '$2=="T"' | grep MyClass
00000000000005e2 T MyClass::PublicMethod()
00000000000005ee T MyClass::PublicMethodWithArgs(int, char**)
00000000000005ca T MyClass::MyClass()
00000000000005ca T MyClass::MyClass()
00000000000005d6 T MyClass::~MyClass()
00000000000005d6 T MyClass::~MyClass()
Öffentlich / privat kann als Attribut für jede Funktion in gcc angegeben werden.
Da der Standardwert öffentlich ist, möchten Sie für die Funktion, die Sie privat halten möchten, die folgenden Schritte ausführen Sie können Ihr Ziel erreichen, indem Sie "visibility (" hidden ")" angeben.
sample.cc
MyClass::MyClass() {}
MyClass::~MyClass() {}
void
MyClass::PublicMethod() {}
int
MyClass::PublicMethodWithArgs(int argc, char* argv[]) {}
void __attribute__((__visibility__("hidden")))
MyClass::PrivateMethod() {}
int __attribute__((__visibility__("hidden")))
MyClass::PrivateMethodWithArgs(int argc, char* argv[]) {}
Auch wenn Sie das Versionsskript nicht wie folgt angeben Die private Methode kann privat gehalten werden.
$ g++ -W -Werror -shared -fPIC -o libsample.so sample.cc
$ nm -gC libsample.so | awk '$2=="T"' | grep MyClass
0000000000000692 T MyClass::PublicMethod()
000000000000069e T MyClass::PublicMethodWithArgs(int, char**)
000000000000067a T MyClass::MyClass()
000000000000067a T MyClass::MyClass()
0000000000000686 T MyClass::~MyClass()
0000000000000686 T MyClass::~MyClass()
Ich kann mit Methode 2 machen, was ich will, aber mit der Blacklist-Methode gibt es definitiv Lecks. (Weil es verwendet werden kann, auch wenn es undicht ist)
Nachdem Sie die Standardeinstellung privat gemacht haben, Ich denke, es ist sicher, öffentliche Funktionen mithilfe von Attributen in einer Whitelist anzugeben.
Um den Standardwert privat zu halten, geben Sie beim Kompilieren "-fvisibility = hidden" an. Geben Sie danach im Gegensatz zu Plan 2 "visibility (" default ")" für die Funktion an, die Sie verfügbar machen möchten.
sample.cc
__attribute__((__visibility__("default")))
MyClass::MyClass() {}
__attribute__((__visibility__("default")))
MyClass::~MyClass() {}
void __attribute__((__visibility__("default")))
MyClass::PublicMethod() {}
int __attribute__((__visibility__("default")))
MyClass::PublicMethodWithArgs(int argc, char* argv[]) {}
void
MyClass::PrivateMethod() {}
int
MyClass::PrivateMethodWithArgs(int argc, char* argv[]) {}
Die private Methode kann wie folgt privatisiert werden.
$ g++ -W -Werror -shared -fPIC -fvisibility=hidden -o libsample.so sample.cc
$ nm -gC libsample.so | awk '$2=="T"' | grep MyClass
0000000000000692 T MyClass::PublicMethod()
000000000000069e T MyClass::PublicMethodWithArgs(int, char**)
000000000000067a T MyClass::MyClass()
000000000000067a T MyClass::MyClass()
0000000000000686 T MyClass::~MyClass()
0000000000000686 T MyClass::~MyClass()
Es ist unten platziert.
takeoverjp/hide_shared_lib_symbols
GNU Gnulib: Exported Symbols of Shared Libraries Visibility - GCC Wiki How To Write Shared Libraries GNU Gnulib: LD Version Scripts Using the GNU Compiler Collection (GCC): Common Function Attributes