Xavier Lamorlette
Sommaire :
ar
ldd
nm
objdump
readelf
Fichiers .a
: archive.
Créés par ar
: « concaténation » de fichiers objets .o
.
Windows : .lib
.
Fichiers .so
: shared object
Windows : .dll
: dynamic link libraries
Vocabulaire :
Un DSO n'a pas d'adresse fixe de chargement. Il a donc besoin du dynamic linker, qui charge les dépendances d'une application et fait les relocalisations nécessaires.
Pour générer un DSO (plutôt qu'une application), il faut ajouter l'option --shared
au linker ld
.
Il faut compiler avec l'option -fpic
: Position Independent Code. Si la GOT devient trop grosse, il faut utiliser -fPIC
.
À l'édition de lien, on peut donner le chemin vers la bibliothèque avec l'option -L
, sinon il faudra le mettre dans le LD_LIBRARY_PATH
.
LD_PRELOAD
perment de faire de l'interposition de définition.
À l'édition de lien, on peut aussi définir un run path, qui sera examiné après le LD_LIBRARY_PATH
.
Il faut donner l'option -rpath
(ou -R
) au linker :
gcc -Wl,-rpath,/dir1:/foo/dir2,-R,/dir3 file.o
Note : pour passer une option au linker via gcc
: gcc -Wl,option
Le dynamic string token, DST, permet de spécifier un run path relatif au fichier execétable : -R $ORIGIN/../lib
.
static
, en C, indique de ne pas exporter une variable ou une fonction.
Les namespaces anonymes, en C++, font la même chose.
Si une variable est const
, le compilateur peut mettre son contenu dans en mémoire partagée en lecture seule.
Options du linker :
--as-needed
indique de n'inclure les dépendances suivantes que si elles sont nécessaires.-z defs
: génère une erreur s'il reste un symbole indéfini.ar
Liste les fichiers objets d'une bibliothèque archive.
ldd
Liste les dépendances d'un exécutable.
Pour voir les dépendances superflues :
ldd -u -r foo.so
nm
Liste les symboles d'un fichier objet, d'une bibliothèque archive ou d'une bibliothèque partagée.
T
: text section symbolU
: undefined symbolI
: indirect symbolt
/ u
/ i
minuscule : symbole localnm -u
: liste les symboles non définis.
objdump
Liste les informations d'un fichier objet.
readelf
Liste les symboles d'une biliothèque partagée.
dlopen()
, dlsym()
, dlclose()
.LoadLibrary()
, GetProcAddress()
, FreeLibrary()
.Références :
Interface :
class Base {
public:
virtual ~Base() {}
virtual void foo() const = 0;
};
using Base_creator_t = Base *(*)();
Bibliothèque :
class Derived: public Base {
public:
void foo() const override {}
};
extern "C" {
Base * create() {
return new Derived;
}
}
Client :
#ifdef _WINDOWS
#include <windows.h>
class Derived_factory {
public:
Derived_factory() {
handler = LoadLibrary("derived.dll");
if (! handler) {
throw std::runtime_error(Get_error_message());
}
FARPROC farproc = GetProcAddress(handler, "create");
if (! farproc) {
throw std::runtime_error(Get_error_message());
}
creator = reinterpret_cast<Base_creator_t>(farproc);
}
std::unique_ptr<Base> create() const {
return std::unique_ptr<Base>(creator());
}
~Derived_factory() {
if (handler) {
FreeLibrary(handler);
}
}
private:
HINSTANCE handler = nullptr;
Base_creator_t creator = nullptr;
static std::string Get_error_message() {
LPVOID message_buffer;
DWORD dw = GetLastError();
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, dw, 0, (LPTSTR) & message_buffer, 0, NULL);
std::string error_message(static_cast<char *>(message_buffer));
LocalFree(message_buffer);
return error_message;
}
};
#else
#include <dlfcn.h>
class Derived_factory {
public:
Derived_factory() {
handler = dlopen("libderived.so", RTLD_NOW);
if (! handler) {
throw std::runtime_error(dlerror());
}
Reset_dlerror();
creator = reinterpret_cast<Base_creator_t>(dlsym(handler, "create"));
Check_dlerror();
}
std::unique_ptr<Base> create() const {
return std::unique_ptr<Base>(creator());
}
~Derived_factory() {
if (handler) {
dlclose(handler);
}
}
private:
void * handler = nullptr;
Base_creator_t creator = nullptr;
static void Reset_dlerror() {
dlerror();
}
static void Check_dlerror() {
const char * dlsym_error = dlerror();
if (dlsym_error) {
throw std::runtime_error(dlsym_error);
}
}
};
#endif
{
Derived_factory factory;
std::unique_ptr<Base> base = factory.create();
base->foo();
}
“HowTo Write Shared Libraries” d'Ulrich Drepper
La dernière mise à jour de cette page date d'avril 2019.
Le contenu de ce site est, en tant qu'œuvre originale de l'esprit, protégé par le droit d'auteur.
Pour tout commentaire, vous pouvez m'écrire à xavier.lamorlette@gmail.com.