GNU/Linux >> Linux Esercitazione >  >> Linux

Come fare in modo che un ritardo di libreria condivisa venga caricato su Linux

Il caricamento ritardato NON è una funzionalità di runtime. MSVC++ lo ha implementato senza l'aiuto di Windows. E come dlopen è l'unico modo su Linux, GetProcAddress è l'unico metodo di runtime su Windows.

Allora, cos'è il caricamento ritardato? È molto semplice:qualsiasi chiamata a una DLL deve passare attraverso un puntatore (poiché non sai dove verrà caricata). Questo è sempre stato gestito dal compilatore e dal linker per te. Ma con il caricamento ritardato, MSVC++ inizialmente imposta questo puntatore su uno stub che chiama LoadLibrary e GetProcAddress per te.

Clang può fare lo stesso senza l'aiuto di ld . In fase di esecuzione, è solo un normale dlopen chiama e Linux non può determinare che Clang l'ha inserita.


Per aggiungere alla risposta di MSalters, si può facilmente imitare l'approccio di Windows al caricamento pigro su Linux creando una piccola libreria stub statica che proverebbe a dlopen libreria necessaria alla prima chiamata a una qualsiasi delle sue funzioni (emissione di messaggi diagnostici e terminazione se dlopen fallisce) e quindi inoltro di tutte le chiamate ad essa.

Tali librerie di stub possono essere scritte a mano, generate da script specifici del progetto/libreria o generate dallo strumento universale Implib.so:

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

Questa funzionalità può essere ottenuta in modo portatile utilizzando il modello di progettazione proxy.

Nel codice potrebbe assomigliare a questo:

#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. Come installare la libreria Ncurses in Linux

  2. Come rendere accessibile una directory condivisa tramite Sftp?

  3. Introduzione alle librerie condivise Linux (come creare librerie condivise)

  4. Come inizializzare una libreria condivisa su Linux

  5. Come posso visualizzare l'elenco delle funzioni che una libreria condivisa di Linux sta esportando?

Come rendere eseguibile un file in Linux

Come realizzare una USB multiboot in Linux e Windows

Come elencare le librerie condivise utilizzate dagli eseguibili in Linux

Come installare la libreria Python PyBrain in Linux

Come rendere eseguibile un file nel terminale Linux?

Come creare un server Minecraft su distribuzioni Linux