dlsym () une variable globale en C ++

Je veux créer un programme capable de dlopen() une série de bibliothèques (écrites par moi-même) et d’exécuter toutes les fonctions stockées dans une variable globale appelée test_suite dans ce fichier .so, qui est un tableau de pointeurs de fonctions terminés par NULL. (les signatures des fonctions sont prédéfinies par moi-même, pas besoin de m’en soucier).

Le problème est que g ++ modifie cette variable. La bibliothèque est compilée comme suit:

 g++ -Wall -shared -rdynamic -fPIC foo.cpp -o foo.so 

et le “index de fonction” est déclaré et affecté statiquement comme:

 const testunit_testcase test_suite = { ... } 

encore

 objdump -t foo.so | grep test_suite 

montre:

 0000000000200940 l O .data.rel.ro 0000000000000020 _ZL10test_suite 

Ce dont j’ai besoin est

 0000000000200940 l O .data.rel.ro 0000000000000020 test_suite 

Donc je peux dlsym(dlh, "test_suite") dans le programme dlopen() ‘ing foo.so

Merci


Addenda

Oui, extern "C" était la première chose que j’ai essayé:

 extern "C" { const testunit_testcase test_suite[] = { //TESTUNIT_DEF_TESTCASE(doTest), {NULL, NULL}, }; } 

J’utilise:

g ++ -v Utilisation des spécifications intégrées. COLLECT_GCC = g ++ COLLECT_LTO_WRAPPER = / usr / lib / gcc / x86_64-inconnu-linux-gnu / 4.5.2 / lto-wrapper Cible: x86_64-unknown-linux-gnu Configuré avec: / build / src / gcc-4.5-20110127 / configure –prefix = / usr –enable-languages ​​= c, c ++, fortran, objc, obj-c ++, ada –enable-shared –enable-threads = posix –enable -__ cxa_atexit –enable-clocale = gnu –enable-gnu-unique-object –enable-lto –enable-plugin –enable-gold –avec-plugin-ld = ld.gold –disable-multilib –disable-libstdcxx-pch –avec -system-zlib –with-ppl –with-cloog –with-cloog-include = / usr / include / cloog-ppl –libdir = / usr / lib –libexecdir = / usr / lib –mandir = / usr / share / man –infodir = / usr / share / info Modèle de thread: posix gcc version 4.5.2 20110127 (version préliminaire) (GCC)


Addendum 2

Pour quelque raison que ce soit

 extern "C" { const testunit_testcase test_suite = { ... } } 

ne fonctionne pas , MAIS celui-ci fait:

 extern "C" const testunit_testcase test_suite = { ... } 

Ma question maintenant : Comme je peux le voir dans certaines de vos réponses, joindre extern "C" { ... } fonctionne pour vous. Existe-t-il des indicateurs de compilation que je pourrais utiliser pour vérifier que test_suite ne sera jamais test_suite , quelle que soit la version 4.x (au moins) de g ++?

Le problème n’est pas un problème de dénigrement. (Ou ce n’est probablement pas le cas: les noms de variables publiques ne sont généralement pas mutilés.) Le vrai problème est que le terme “const” signifie “statique implicite”, ce qui rend la variable invisible en dehors de l’unité de traduction. Pour éviter cela, la variable doit être explicitement déclarée extern. Et “La forme de spécification de liaison contenant une déclaration-seq entourée d’une accolade n’affecte pas le fait que les déclarations contenues soient des définitions ou non (3.1); la forme de spécification de liaison contenant directement une seule déclaration est traitée comme un spécificateur externe ( 7.1.1) afin de déterminer si la déclaration contenue est une définition. ” Qui, bien qu’il ne semble pas traiter directement votre problème (la présence d’un initialiseur garantit que la déclaration est une définition), semble indiquer l’intention: dans un spécificateur de liaison entre accolades, les règles habituelles s’appliquent; Si le spécificateur de liaison s’applique directement à la déclaration, c’est comme si la déclaration était explicitement externe. Donc, vous pouvez écrire soit:

 extern "C" { testunit_testcase const test_suite[] // ... } 

ou

 extern "C" testunit_testcase const test_suite[] // ... 

Mais il doit y avoir un extern qui s’applique explicitement à la définition, afin de remplacer le “statique” implicite de “const”.

Ce

x.cxx:

  extern "C" { extern const int test_suite[] = { 0 }; } 

travaille pour moi:

 ~/ec% g++ -Wall -rdynamic -shared x.cxx -o x.so ~/ec% objdump -t x.so | grep test_suite 00000444 g O .rodata 00000004 test_suite 

Si je ne test_suite pas test_suite il n’est pas du tout exporté. Cela a du sens car const à la scope du fichier ou de l’espace de noms implique static . Cela n’a aucun sens parce que je m’attendrais à ce que le bloc extern "C" “compte” pour cela. Je ne sais pas si c’est un bug de gcc ou non. Pouvez-vous réduire votre problème à une taille similaire?

Vous utilisez un compilateur C ++, le nom est donc déchiré. Essayez d’utiliser gcc (si possible) ou utilisez

 extern "C" { const testunit_testcase test_suite = { ... } } 

L’ extern "C" désactive la dénomination.

Ne pas rendre cette variable static .

static signifie que la variable est locale à l’unité de compilation en cours, c’est pourquoi g ++ modifie son nom. Si vous souhaitez que la variable soit accessible “de l’extérieur”, vous ne devez pas la rendre static . Donc, dans le fichier .cpp, définissez la variable comme ceci:

 const testunit_testcase test_suite = { ... } 

Si vous déclarez également la variable dans un fichier .h correspondant, faites cette déclaration extern :

 extern const testunit_testcase test_suite;