2010-12-13 83 views
0

Bonjour J'ai un programme avec une fonction globale que j'aimerais personnaliser lors de l'exécution. Dis, il existe de nombreuses versions de la fonction foo() dispersées sur des bibliothèques partagées. Maintenant, en fonction de la configuration du système détectée au moment de l'exécution, je voudrais utiliser la fonction de la bibliothèque appropriée.Fonctions de substitution des bibliothèques dynamiques

fichier loader.cpp:

#include <dlfcn.h> 
#include <iostream> 

void __attribute__((weak)) foo(); 

    int main(int argc, char *argv[]) 
    { 
     void* dl = dlopen("./other.so", RTLD_NOW | RTLD_GLOBAL); 
     if (!dl) 
     { 
      std::cerr << dlerror() << std::endl; 
      return 1; 
     } 
     if (foo) 
     { 
      foo(); 
     } 
     else 
     { 
      std::cerr << "No foo?" << std::endl; 
     } 
     dlclose(dl); 
     return 0; 
    } 

fichier other.cpp:

#include <iostream> 

void foo() 
{ 
    std::cout << "FOO!" << std::endl; 
} 

je compile le programme avec

g++ -Wall -fPIC -o loaded loader.cpp -ldl 
g++ -Wall -fPIC -shared -o other.so other.cpp 

Cependant le symbole faible n'est pas outrepassée. Des indices?

Répondre

4

Les symboles sont résolus pendant le temps de chargement de l'image dans laquelle ils sont référencés. Ainsi, lorsque votre exécutable est chargé, la référence à foo est déjà résolue. Un dlopen ultérieur n'ira pas et reliera tous les symboles - cela ne peut affecter que les chargements ultérieurs.

Vous devez utiliser dlsym à la place, ou un ensemble LD_PRELOAD:

[email protected]:/tmp$ LD_PRELOAD=/tmp/other.so ./loaded 
FOO! 
0

Vous avez compilé le répertoire lib partagé avec g ++. En conséquence, le nom de la fonction est mutilée:

$ nm -S other.so |grep foo 
0000000000000690 000000000000002e T _Z3foov 

Si vous faites un pur code C et compilez avec gcc au lieu de g ++, vous trouverez fonctionner comme prévu.

Vous pouvez également définir comme suit:

extern "C" void foo() 
{ 
    std::cout << "FOO!" << std::endl; 
}