GNU/Linux >> Tutoriels Linux >  >> Linux

Comment faire un délai de bibliothèque partagée chargé sur Linux

Le chargement différé n'est PAS une fonctionnalité d'exécution. MSVC++ l'a implémenté sans l'aide de Windows. Et comme dlopen est le seul moyen sous Linux, GetProcAddress est la seule méthode d'exécution sous Windows.

Alors, qu'est-ce que le chargement différé alors ? C'est très simple :tout appel à une DLL doit passer par un pointeur (puisque vous ne savez pas où elle va se charger). Cela a toujours été géré par le compilateur et l'éditeur de liens pour vous. Mais avec le chargement différé, MSVC++ définit initialement ce pointeur sur un stub qui appelle LoadLibrary et GetProcAddress pour toi.

Clang peut faire la même chose sans l'aide de ld . Au moment de l'exécution, c'est juste un dlopen ordinaire appel, et Linux ne peut pas déterminer que Clang l'a inséré.


Pour ajouter à la réponse de MSalters, on peut facilement imiter l'approche Windows du chargement paresseux sous Linux en créant une petite bibliothèque de stub statique qui essaierait de dlopen bibliothèque nécessaire lors du premier appel à l'une de ses fonctions (en émettant un message de diagnostic et en se terminant si dlopen a échoué), puis en lui transférant tous les appels.

Ces bibliothèques stub peuvent être écrites à la main, générées par un script spécifique au projet/à la bibliothèque ou générées par l'outil universel Implib.so :

$ implib-gen.py libxyz.so
$ gcc myapp.c libxyz.tramp.S libxyz.init.c ...

Cette fonctionnalité peut être réalisée de manière portable à l'aide du modèle de conception Proxy.

Dans le code, cela peut ressembler à ceci :

#include <memory>

// SharedLibraryProxy.h
struct SharedLibraryProxy
{
    virtual ~SharedLibraryProxy() = 0;

    // Shared library interface begin.
    virtual void foo() = 0;
    virtual void bar() = 0;
    // Shared library interface end.

    static std::unique_ptr<SharedLibraryProxy> create();
};

// SharedLibraryProxy.cc
struct SharedLibraryProxyImp : SharedLibraryProxy
{
    void* shared_lib_ = nullptr;
    void (*foo_)() = nullptr;
    void (*bar_)() = nullptr;

    SharedLibraryProxyImp& load() {
        // Platform-specific bit to load the shared library at run-time.
        if(!shared_lib_) { 
            // shared_lib_ = dlopen(...);
            // foo_ = dlsym(...)
            // bar_ = dlsym(...)
        }
        return *this;
    }

    void foo() override {
        return this->load().foo_();
    }

    void bar() override {
        return this->load().bar_();
    }
};

SharedLibraryProxy::~SharedLibraryProxy() {}

std::unique_ptr<SharedLibraryProxy> SharedLibraryProxy::create() {
    return std::unique_ptr<SharedLibraryProxy>{new SharedLibraryProxyImp};
}

// main.cc
int main() {
    auto shared_lib = SharedLibraryProxy::create();
    shared_lib->foo();
    shared_lib->bar();
}

Linux
  1. Comment rendre un ancien ordinateur utile à nouveau

  2. Linux - Comment rendre Tr conscient des caractères non ascii (unicode) ?

  3. Introduction aux bibliothèques partagées Linux (comment créer des bibliothèques partagées)

  4. Comment initialiser une bibliothèque partagée sous Linux

  5. Comment afficher la liste des fonctions qu'une bibliothèque partagée Linux exporte ?

Comment rendre un fichier exécutable sous Linux

Comment créer une clé USB multiboot sous Linux et Windows

Comment répertorier les bibliothèques partagées utilisées par les exécutables sous Linux

Comment installer la bibliothèque Python PyBrain sous Linux

Comment rendre un fichier exécutable dans un terminal Linux ?

Comment créer un serveur Minecraft sur des distributions Linux