Xavier Lamorlette
arlddnmobjdumpreadelfFichiers .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.arListe les fichiers objets d'une bibliothèque archive.
lddListe les dépendances d'un exécutable.
Pour voir les dépendances superflues :
ldd -u -r foo.so
nmListe 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.
objdumpListe les informations d'un fichier objet.
readelfListe 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.