I have been stuck in a problem for several days when using dlopen/dlsym to deal with the shared object. I desperately need your help!
There are three headers/source files: Animal.h, Animal.cpp and test.cpp, and two products: libanimal.so and a.out.
Here is the source code:
Animal.h:
// Animal.h
#ifndef STDLIB_ANIMAL_H
#define STDLIB_ANIMAL_H
#include <string>
class Animal {
public:
Animal();
std::string shout();
};
extern "C" Animal* createAnimal();
#endif //STDLIB_ANIMAL_H
Animal.cpp
// Animal.cpp
#include "Animal.h"
Animal::Animal() = default;
std::string Animal::shout() {
return "WOW";
}
Animal* createAnimal() {
return new Animal();
}
and the last one test.cpp which contained the main entry of the application:
// test.cpp
#include <cstdio>
#include <cstdlib>
#include <string>
#include <dlfcn.h>
#include <iostream>
#include "Animal.h"
int main(int argc, char** argv)
{
void *handle;
// Open shared library
handle = dlopen("./libanimal.so", RTLD_LAZY);
if (!handle) {
/* fail to load the library */
fprintf(stderr, "Handle Error: %sn", dlerror());
return EXIT_FAILURE;
}
auto spawnAnimal = reinterpret_cast<Animal* (*)()>(dlsym(handle, "createAnimal"));
if (!spawnAnimal) {
/* no such symbol */
fprintf(stderr, "No Such Symbol Error: %sn", dlerror());
dlclose(handle);
return EXIT_FAILURE;
}
auto animal = spawnAnimal();
std::cout << "call animal shout, the address of animal : " << animal <<std::endl;
std::cout << animal->shout() << std::endl;
std::cout << "after calling" << std::endl;
dlclose(handle);
return EXIT_SUCCESS;
}
First, I built libanimal.so shared library by the following command:
$ g++ -shared -fPIC -Wall -o libanimal.so Animal.cpp -std=c++0x
Then I built the executable, a.out:
$ g++ -Wall test.cpp -ldl -std=c++0x -Wl,--unresolved-symbols=ignore-in-object-files
# --unresolved-symbols=ignore-all: tell linker to stop complaining about missing symbols
Both the above commands ran well without any error, but when I execute a.out, errors came out:
$ ./a.out
call animal shout, the address of animal : 0x7fffe97a4520
Segmentation fault (core dumped)
I have searched lots of blogs/documentations, but all of them just post a really simple example:
The function they export always return like a std::string or char or int which is built-in type, not something like a object of a user-defined class, just like the showcase above (the createAnimal function).
So what’s wrong with this? Could you please help me figuring out ?
Thank you !
BTW, my environment is:
$ g++ --version
g++ (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Advertisement
Answer
Ok, my suspicion from the comment has confirmed itself. The problem is with the early binding on animal->shout()
which resolves at compile time to a call to _ZN6Animal5shoutB5cxx11Ev
and this symbol is nowhere to be found.
If I change it to virtual (late binding, resolved at runtime through a vtable):
// Animal.h
#ifndef STDLIB_ANIMAL_H
#define STDLIB_ANIMAL_H
#include <string>
class Animal {
public:
Animal();
virtual std::string shout();
virtual ~Animal() {} // always put a virtual destructor if you have any virtual methods
};
extern "C" Animal* createAnimal();
#endif //STDLIB_ANIMAL_H
Now it runs.