GNU/Linux >> Tutoriales Linux >  >> Linux

Cómo hacer que una biblioteca compartida se retrase cargada en Linux

La carga diferida NO es una función de tiempo de ejecución. MSVC++ lo implementó sin la ayuda de Windows. Y como dlopen es la única forma en Linux, GetProcAddress es el único método de tiempo de ejecución en Windows.

Entonces, ¿qué es la carga retrasada entonces? Es muy simple:cualquier llamada a una DLL tiene que pasar por un puntero (ya que no sabes dónde se cargará). Esto siempre ha sido manejado por el compilador y el enlazador por usted. Pero con la carga retrasada, MSVC ++ establece este puntero inicialmente en un código auxiliar que llama a LoadLibrary y GetProcAddress para ti.

Clang puede hacer lo mismo sin la ayuda de ld . En tiempo de ejecución, es solo un dlopen ordinario llamada, y Linux no puede determinar que Clang la insertó.


Para agregar a la respuesta de MSalters, uno puede imitar fácilmente el enfoque de Windows para la carga diferida en Linux mediante la creación de una pequeña biblioteca de código auxiliar estático que intentaría dlopen biblioteca necesaria en la primera llamada a cualquiera de sus funciones (emitir un mensaje de diagnóstico y finalizar si falla dlopen) y luego reenviar todas las llamadas.

Estas bibliotecas de código auxiliar pueden escribirse a mano, generarse mediante un script específico de proyecto/biblioteca o generarse mediante la herramienta universal Implib.so:

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

Esta funcionalidad se puede lograr de forma portátil utilizando el patrón de diseño Proxy.

En el código puede ser algo como esto:

#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. Cómo hacer que una computadora vieja vuelva a ser útil

  2. Introducción a las bibliotecas compartidas de Linux (Cómo crear bibliotecas compartidas)

  3. Biblioteca compartida dinámica de C++ en Linux

  4. ¿Cómo hacer el control de versiones de una biblioteca compartida en Linux?

  5. ¿Cómo hacer una copia de seguridad diferencial en Linux?

Cómo hacer un archivo ejecutable en Linux

Cómo hacer un USB de arranque múltiple en Linux y Windows

Cómo enumerar las bibliotecas compartidas utilizadas por los ejecutables en Linux

Cómo instalar la biblioteca Python de PyBrain en Linux

¿Cómo hacer un archivo ejecutable en la terminal de Linux?

Cómo hacer un servidor de Minecraft en distribuciones de Linux