2017-01-08 7 views
4

Je ne peux pas obtenir l'extension gnu à elf avec des fonctions indirectes pour travailler avec dladdr.Comment obtenir le nom de la fonction indirecte gnu en utilisant dladdr?

Dans l'exemple ci-dessous fabs et sin sont deux fonctions dynamiques dans libm, où sin est également une fonction indirecte. En levant fabs de son pointeur fonctionne bien, mais sin est introuvable. J'ai essayé divers drapeaux à dlopen et -rdynamic sans succès.

Le débogueur montre comment sin est évalué à partir d'un gnu-indirect-function variable à __sin_avx.

Ai-je manqué quelque chose ici ou est-ce que les fonctions indirectes ne sont pas supportées par dladdr?

/* 
    compiled with g++-5 -fPIC -ldl 
*/ 

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

char const * name (void * arg) 
{ 
    void * h = dlopen (NULL, RTLD_LAZY); 

    if (h) 
    { 
     Dl_info res; 
     int status = dladdr (arg, & res); 
     dlclose (h); 

     if (status && res.dli_sname && arg == res.dli_saddr) 
      return res.dli_sname; 
    } 

    return ""; 
} 

int main() 
{ 
    std::cout << fabs (0.0) << " " << name ((void *) fabs) << std::endl; // found 
    std::cout << sin (0.0) << " " << name ((void *) sin) << std::endl; // not found 
} 
+0

Intéressant, réussit à fonctionner si vous supprimez '-fPIC'. – yugr

Répondre

3

Suis-je manque quelque chose ici ou sont des fonctions indirectes non pris en charge par dladdr?

Ok, celui-ci était intéressant.

Ainsi, ifuncs fonctionne en remplaçant l'adresse de fonction d'origine (dans ce cas, sin) par celle résolue par l'éditeur de liens dynamique sur la plate-forme actuelle. sin peut être résolu à l'une des 4 mises en œuvre en fonction des capacités du processeur:

libm_ifunc (__sin, (HAS_ARCH_FEATURE (FMA4_Usable) ? __sin_fma4 : 
        HAS_ARCH_FEATURE (AVX_Usable) 
        ? __sin_avx : __sin_sse2)); 
weak_alias (__sin, sin) 

Maintenant chacun __sin_XXX est une fonction glibc interne qui est pasexportés de libm.so et c'est pourquoi dladdr ne parvient pas à trouver.

Donc, la réponse est essentiellement non, dladdr ne fonctionne pas bien avec ifuncs ...

parvient à travailler si vous supprimez -fPIC

Cela se produit parce que chaque fois que vous compilez w/o -fPIC Le compilateur sait que le fichier source actuel ira à l'exécutable principal et que l'adresse de la fonction d'exécution est donc garantie pour résoudre l'entrée PLT de l'exécutable. Ainsi, au lieu de le charger à partir de GOT, il passe simplement l'adresse PLT à name et dladdr puis localise heureusement sin dans le symtab de l'exécutable.

EDIT:

Confirmé par des gens glibc here.

+0

Merci beaucoup. J'ai trouvé quelques [posts] (https://gcc.gnu.org/ml/gcc/2016-08/msg00138.html) sur ifunc et la visibilité, mais le sujet est assez nouveau pour moi. En tant que solution de rechange, est-il possible de se référer à la fonction indirecte originale, celle avec le '__attribute__ ifunc'? – listcrawler

+0

Personnellement, je ne connais pas de méthode plus simple que l'analyse manuelle de la table GOT (par exemple décrite ici [http://vxheaven.org/lib/vrn00.html#c6]), mais c'est une entreprise assez complexe. Vous pouvez essayer de demander dans [libc-help] (https://sourceware.org/ml/libc-help/). – yugr

+0

Et [ici] (https://sourceware.org/ml/libc-help/2017-01/msg00010.html) est la réponse à ma question sur libc-help.En résumé, les informations sur le nom du symbole ifunc d'origine sont perdues lors de la résolution de son implémentation. En ce qui concerne l'analyse du GOT - pardon mon assembly - mais d'après ce que je peux lire du code généré, je ne suis pas sûr si les ifuncs ne sont pas résolus au démarrage du programme, et pas au premier appel. Si oui, il n'y aurait aucune possibilité d'analyser GOT pour l'adresse ifunc originale, non? – listcrawler