Compiler un programme C utilisant dlopen et dlsym avec -fPIC

J'ai un problème sur un mauvais symbole de la résolution. Mon principal programme charge une bibliothèque partagée avec dlopen et un symbole de avec dlsym. À la fois le programme et la bibliothèque sont écrits en C.
Bibliothèque de code

int a(int b)
{
  return b+1;
}

int c(int d)
{
  return a(d)+1;
}

Afin de le faire fonctionner sur une machine 64 bits, -fPIC est passé à gcc lors de la compilation.

Le programme est:

#include <dlfcn.h>
#include <stdio.h>

int (*a)(int b);
int (*c)(int d);

int main()
{
  void* lib=dlopen("./libtest.so",RTLD_LAZY);
  a=dlsym(lib,"a");
  c=dlsym(lib,"c");
  int d = c(6);
  int b = a(5);
  printf("b is %d d is %d\n",b,d);
  return 0;
}

Tout se passe bien si le programme n'est PAS compilé avec -fPIC, mais il se bloque avec une erreur de segmentation lorsque le programme est compilé avec -fPIC. L'enquête a conduit à découvrir que le crash est dû à la mauvaise résolution d'un symbole. L'incident se produit lorsque l'un est appelé, peu importe si à partir de la bibliothèque ou le programme principal (le dernier est obtenu en commentant la ligne de l'appel de c() dans le programme principal).

Pas de problèmes de se produire lors de l'appel de c() elle-même, probablement parce que c() n'est pas appelée en interne par la bibliothèque elle-même, tandis que() est une fonction utilisée en interne par la bibliothèque et une fonction de l'API de la bibliothèque.

Une solution simple est de ne pas utiliser -fPIC lors de la compilation du programme. Mais ce n'est pas toujours possible, par exemple lorsque le code du programme principal doit être dans une bibliothèque partagée elle-même. Une autre solution consiste à renommer le pointeur à la fonction de quelque chose d'autre. Mais je ne trouve aucune solution réelle.

Remplacement RTLD_LAZY avec RTLD_NOW n'aide pas.

Merci de nous montrer la compilation des lignes que vous avez utilisé, ainsi que votre version de compilateur.
Je suggère de ne pas nommer un pointeur global de la fonction avec le même nom que le dlsym-ed fonction il indique. Ou tout simplement faire de votre pointeur de fonctions locales statiques ou variables, ou des champs de données.
Penser plus à ce sujet, il semble que, puisqu'il n'est pas autrement spécifié, le programme principal exporte également les symboles a et c à l'extérieur. Si un symbole est doublement marquée (par le programme principal et par l'objet partagé) et l'éditeur de liens dynamique trouve la bonne. À l'aide de la gcc spécifique de attribut ((visibilité ("caché"))) dans le programme principal est peut-être la bonne chose à faire... des conseils?
la version de gcc 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) Objet l'utilisation des fichiers par défaut Makefile règle: $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< lien la bibliothèque gcc-shared -o $@ $^ De lier le fichier exécutable gcc-o $@ $^ -g -ldl CFLAGS=-g ou CFLAGS='-g -fPIC " est ajouté à la ligne de commande
Le meilleur conseil est de ne pas utiliser le même nom pour commencer. C'est un comportement indéfini. Si vous souhaitez que les noms semblent être les mêmes, que vous pourriez faire int (*a_ptr)(int b); et #define a a_ptr (mais cela semble vraiment moche pour un nom comme a...), ou vous pouvez le faire à la fonction de pointeur n'ont pas de liaison externe.

OriginalL'auteur user377486 | 2012-05-26