Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

undefined symbol lors d'un dlopen

2 réponses
Avatar
James Kanze
J'ai un .so que j'ai cr=E9e qui ne comporte qu'une seule instance
d'une classe d=E9riv=E9e (en C++), la classe de base faisant partie
du fichier ex=E9cutable qui le charge. Lors du chargement, j'ai
l'erreur (de dlerr, apr=E8s le dlopen) =AB
/home/team02/jakan/generated/i80x86-linux-gcc/component/
UTF8InputStream/libISO8859_1.so: undefined symbol:
_ZN12gabi_2007v014UTF815InputTranslatorC2ERKSs".
Or, si je r=E9garde l'ex=E9cutable, le symbole y est :

$nm /home/team02/jakan/generated/i80x86-linux-gcc/component/
UTF8InputStream/test | egrep
_ZN12gabi_2007v014UTF815InputTranslatorC2ERKSs
0805d1da T _ZN12gabi_2007v014UTF815InputTranslatorC2ERKSs

D'apr=E8s ce que j'ai cru comprendre, lors du dlopen (avec mode =3D=3D
RTLD_NOW | RTLD_LOCAL) : =AB Any object loaded by dlopen() that
requires relocations against global symbols can reference the
symbols in the original process image file,[...] =BB, c-=E0-d que
le .so que je charge doit pouvoir utiliser la fonction (le
constructeur de la classe de base, en l'occurance) dans l'image
ex=E9cutable qui le charge.

Est-ce qu'il y a un d=E9tail qui m'=E9chappe, ou quelque chose que
j'ai oubli=E9 ?

--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34

2 réponses

Avatar
James Kanze
Pour revenir à mon problème :

J'ai réussi à le réproduire dans un exemple tout court (trois
fichiers) :

========== base.hh ==========
#ifndef base_hh_200710173cbGNbiIkCsh0lm4jdDDdPNj
#define base_hh_200710173cbGNbiIkCsh0lm4jdDDdPNj

#include <string>

class Base
{
protected:
Base( std::string const& name ) ;
public:
virtual void f() const = 0 ;
} ;

#endif
========== main.cc ==========
#include "base.hh"
#include <map>
#include <iostream>
#include <dlfcn.h>
#include <link.h>

namespace {
typedef std::map< std::string, Base* >
Map ;
Map map ;
}

Base::Base(
std::string const& name )
{
map.insert( Map::value_type( name, this ) ) ;
}

class First : public Base
{
public:
First() : Base( "first" ) {}
virtual void f() const ;
} aFirst ;

void
First::f() const
{
std::cout << "I'm first" << std::endl ;
}

void
listElements()
{
for ( Map::const_iterator iter = map.begin() ;
iter != map.end() ;
++ iter ) {
std::cout << iter->first << ":n " ;
iter->second->f() ;
}
}

int
main()
{
listElements() ;
void* handle
= dlopen( "./second.so", RTLD_NOW | RTLD_GLOBAL ) ;
if ( handle == NULL ) {
std::cerr << "Could not load second.so" << std::endl ;
std::cerr << " error was: " << dlerror() << std::endl ;
} else {
std::cout << "===== After dlopen =====" << std: :endl ;
listElements() ;
}
return 0 ;
}
========== second.cc ==========
#include "base.hh"
#include <iostream>

class Second : public Base
{
public:
Second() : Base( "second" ) {}
virtual void f() const ;
} aSecond ;

void
Second::f() const
{
std::cout << "I'm second" << std::endl ;
}
========================= ====

Selon le système et le compilateur, j'ai trois comportements
différents :

linux 2.6.9/g++ 4.1.0:
----------------------
$ g++ -o second.so -shared second.cc
$ g++ -o main main.cc -ldl
$ main
first:
I'm first
Could not load second.so
error was: ./second.so: undefined symbol: _ZN4BaseC2ERKSs

C'est le problème initial.

Solaris 2.8/CC 5.8:
-------------------
$ CC -G -o second.so second.cc
$ CC -o main main.cc -ldl
$ main
first:
I'm first
===== After dlopen =====
first:
I'm first
second:
I'm second

C'est le comportement correct, selon ce que je comprends de
Posix.

Solaris 2.8/g++ 4.1.0:
----------------------
$ g++ -shared -o second.so second.cc

Plein d'erreur de compilation (ou plutôt de l'édition de liens).
Il y aurait donc un problème dans gcc et la façon qu'il appelle
l'éditeur de liens (qui est natif Solaris) sous Solaris.

Donc, a priori, il s'agit d'une part d'une erreur dans Linux, et
de l'autre d'un problème g++. Je vais poster dans des groupes
qui conviennent, mais en attendant, si quelqu'un connaît un
work-around, ou s'il s'apperçoit d'une erreur dans ce que j'ai
fait, j'écoute. (Pour l'instant, j'ai besoin surtout sur Linux,
mais à la long, ça doit marcher sur tous les systèmes -- y
compris Windows avec VC++, mais là, je sais que d'autres
problèmes m'attendent.)

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Avatar
Gilles Civario
man dlopen :

Les références externes de la bibliothèque sont résolues en utilisant
les bibliothèqujes mentionnées dans sa liste de dépendances, et toutes
les autres bibliothèques éventuellement ouvertes auparavant avec
l'attribut RTLD_GLOBAL. Si l'édition des liens de l'exécutable a été
faite avec l'option "-rdynamic", alors ses symboles globaux seront
également employés pour résoudre les références de la bibliothèque
chargée dynamiquement.

Il semble manquer -rdynamic à l'édition de liens.

:~/tmp/KANZE> g++ -o second.so -shared second.cc -fpic
:~/tmp/KANZE> g++ -o main main.cc -ldl
:~/tmp/KANZE> g++ -o main_rdynamic main.cc -ldl -rdynamic
:~/tmp/KANZE> ./main
first:
I'm first
Could not load second.so
error was: ./second.so: undefined symbol: _ZN4BaseC2ERKSs
:~/tmp/KANZE> ./main_rdynamic
first:
I'm first
===== After dlopen ==== first:
I'm first
second:
I'm second


Pour revenir à mon problème :

J'ai réussi à le réproduire dans un exemple tout court (trois
fichiers) :

========== base.hh ========= > #ifndef base_hh_200710173cbGNbiIkCsh0lm4jdDDdPNj
#define base_hh_200710173cbGNbiIkCsh0lm4jdDDdPNj

#include <string>

class Base
{
protected:
Base( std::string const& name ) ;
public:
virtual void f() const = 0 ;
} ;

#endif
========== main.cc ========= > #include "base.hh"
#include <map>
#include <iostream>
#include <dlfcn.h>
#include <link.h>

namespace {
typedef std::map< std::string, Base* >
Map ;
Map map ;
}

Base::Base(
std::string const& name )
{
map.insert( Map::value_type( name, this ) ) ;
}

class First : public Base
{
public:
First() : Base( "first" ) {}
virtual void f() const ;
} aFirst ;

void
First::f() const
{
std::cout << "I'm first" << std::endl ;
}

void
listElements()
{
for ( Map::const_iterator iter = map.begin() ;
iter != map.end() ;
++ iter ) {
std::cout << iter->first << ":n " ;
iter->second->f() ;
}
}

int
main()
{
listElements() ;
void* handle
= dlopen( "./second.so", RTLD_NOW | RTLD_GLOBAL ) ;
if ( handle == NULL ) {
std::cerr << "Could not load second.so" << std::endl ;
std::cerr << " error was: " << dlerror() << std::endl ;
} else {
std::cout << "===== After dlopen =====" << std::endl ;
listElements() ;
}
return 0 ;
}
========== second.cc ========= > #include "base.hh"
#include <iostream>

class Second : public Base
{
public:
Second() : Base( "second" ) {}
virtual void f() const ;
} aSecond ;

void
Second::f() const
{
std::cout << "I'm second" << std::endl ;
}
============================ >
Selon le système et le compilateur, j'ai trois comportements
différents :

linux 2.6.9/g++ 4.1.0:
----------------------
$ g++ -o second.so -shared second.cc
$ g++ -o main main.cc -ldl
$ main
first:
I'm first
Could not load second.so
error was: ./second.so: undefined symbol: _ZN4BaseC2ERKSs

C'est le problème initial.

Solaris 2.8/CC 5.8:
-------------------
$ CC -G -o second.so second.cc
$ CC -o main main.cc -ldl
$ main
first:
I'm first
===== After dlopen ==== > first:
I'm first
second:
I'm second

C'est le comportement correct, selon ce que je comprends de
Posix.

Solaris 2.8/g++ 4.1.0:
----------------------
$ g++ -shared -o second.so second.cc

Plein d'erreur de compilation (ou plutôt de l'édition de liens).
Il y aurait donc un problème dans gcc et la façon qu'il appelle
l'éditeur de liens (qui est natif Solaris) sous Solaris.

Donc, a priori, il s'agit d'une part d'une erreur dans Linux, et
de l'autre d'un problème g++. Je vais poster dans des groupes
qui conviennent, mais en attendant, si quelqu'un connaît un
work-around, ou s'il s'apperçoit d'une erreur dans ce que j'ai
fait, j'écoute. (Pour l'instant, j'ai besoin surtout sur Linux,
mais à la long, ça doit marcher sur tous les systèmes -- y
compris Windows avec VC++, mais là, je sais que d'autres
problèmes m'attendent.)

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34