[LINUX] Begrenzen Sie öffentliche Symbole in gemeinsam genutzten Bibliotheken

Einführung

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.

Unter 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) 

Thema

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()

Methode 1. Listen Sie öffentliche Funktionen mit [LD-Versionsskript] auf (https://www.gnu.org/software/gnulib/manual/html_node/LD-Version-Scripts.html).

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()

Methode 2: Geben Sie "visibility (" hidden ")" für eine private Funktion an

Ö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()

Methode 3: Machen Sie den Standard privat und geben Sie in der öffentlichen Funktion "visibility (" default ")" an

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()

Experimenteller Code

Es ist unten platziert.

takeoverjp/hide_shared_lib_symbols

Referenz

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

Recommended Posts

Begrenzen Sie öffentliche Symbole in gemeinsam genutzten Bibliotheken
Verwenden Sie gemeinsam genutzten Speicher mit gemeinsam genutzten Bibliotheken
Fehler beim Laden von gemeinsam genutzten Bibliotheken
Debuggen Sie gemeinsam genutzte Bibliotheken mit VScode