dlsym and function pointer ...

D

dkarthik

Hello All,

I am a newbie to C++. I was trying a sample program from internet which
demonstrates dynamic class loading in C++. Actually, I thought of using
this design, in one of the applications I am working on.

However, the compilation was through. But when ran, the program
generated a SIGSEGV error. I debugged it using gdb and found that ,when
the symbol returned by dlsym() was invoked, the resulting value was
null.

I couldn't understand clearly why it didn't worked. The problematic
location in the code
has been denoted below(calc.cpp):

calc.cpp:

#include "calculator.hpp"
typedef Math* (*factory)(void);

bool Calculator::load(char* library_name) {

factory make;

/* Open shared library */
handle = dlopen(library_name, RTLD_NOW);
if (!handle) {
cout << dlerror();
return false;
}

/* Load symbols from library */
make = (factory)dlsym(handle, "maker");
if (make = NULL) {
cout << dlerror() << "\n";
return false;
}

/* Construct object */
math = (*make)(); ===> *** This is Problem location***

cout << (void*)math << "\n";

return true;

}

bool Calculator::calculate() {

float a;
cout << "Enter float:\n";
fscanf(stdin,"%f",&a);

c = math->square(a);

cout << "Square: " << c << '\n";
return true;
}

bool Calculator::close() {
char *error;

dlerror();
dlclose(handle);
if ((error = dlerror()) != NULL) {
cout << error;
return false;
}
return true;
}

main.cpp:

#include "calculator.hpp"

int main (int argc, char* argv[]) {

if (argc != 2)
cout << "Usage: calc \n";

Calculator* c = new Calculator();

if (c->load(argv[1])) {
c->calculate();
c->close();
}

delete c;
return 0;
}

calculator.hpp:

#ifndef __CALCULATOR_H
#define __CALCULATOR_H

#include "math.hpp"

class Calculator {
public:
bool load(char* library);
bool calculate();
bool close();
private:
void* handle;
Math* math;
};

#endif

math.hpp:

#ifndef __MATH_H
#define __MATH_H

class Math {
public:
virtual float multiply(float a, float b);
virtual float square(float a);
};

#endif

math.cpp:

#include "math.hpp"

float Math::multiply(float a, float b) {
return a*b;
}

float Math::square(float a) {
return a*a;
}

extern "C" {
Math *maker() {
return new Math;
}
}


I'm using g++ 3.2.3 and below is the makefile used to compile the
program.

LIB_SRC = math.cpp
LIB_OBJ = math.o
LIB = math

BIN_SRC = main.cpp calc.cpp
BIN = calc

LIB_VER_MAJOR =
LIB_VER_MINOR =

CC = g++
LIB_OBJ_FLAGS = -fPIC -c -Wall -g
LIB_SO_FLAGS = -shared -lc -Wl,-soname
BIN_FLAGS = -rdynamic -ldl -Wall -g

all: lib.o lib.so bin

lib.o:
$(CC) $(LIB_OBJ_FLAGS) $(LIB_SRC)

lib.so:
$(CC) $(LIB_SO_FLAGS),$(LIB).so.$(LIB_VER_MAJOR) \
-o $(LIB).so$(LIB_VER_MAJOR)$(LIB_VER_MINOR) $(LIB_OBJ)

bin:
$(CC) $(BIN_FLAGS) -o $(BIN) $(BIN_SRC)

clean:
rm -f *.o *.so* $(BIN)


Any pointers/suggestions to solve this problem will be really
appreciated. The argument to calc exe is math.so

Thanks & Regards,

Karthik D
 
M

mlimber

Hello All,

I am a newbie to C++. I was trying a sample program from internet which
demonstrates dynamic class loading in C++. Actually, I thought of using
this design, in one of the applications I am working on.

However, the compilation was through. But when ran, the program
generated a SIGSEGV error. I debugged it using gdb and found that ,when
the symbol returned by dlsym() was invoked, the resulting value was
null.

I couldn't understand clearly why it didn't worked. The problematic
location in the code
has been denoted below(calc.cpp):

calc.cpp:

#include "calculator.hpp"
typedef Math* (*factory)(void);

bool Calculator::load(char* library_name) {

factory make;

/* Open shared library */
handle = dlopen(library_name, RTLD_NOW);
if (!handle) {
cout << dlerror();
return false;
}

/* Load symbols from library */
make = (factory)dlsym(handle, "maker");
if (make = NULL) {
cout << dlerror() << "\n";
return false;
}

/* Construct object */
math = (*make)(); ===> *** This is Problem location***

cout << (void*)math << "\n";

return true;

}

bool Calculator::calculate() {

float a;
cout << "Enter float:\n";
fscanf(stdin,"%f",&a);

c = math->square(a);

cout << "Square: " << c << '\n";
return true;
}

bool Calculator::close() {
char *error;

dlerror();
dlclose(handle);
if ((error = dlerror()) != NULL) {
cout << error;
return false;
}
return true;
}

main.cpp:

#include "calculator.hpp"

int main (int argc, char* argv[]) {

if (argc != 2)
cout << "Usage: calc \n";

Calculator* c = new Calculator();

if (c->load(argv[1])) {
c->calculate();
c->close();
}

delete c;
return 0;
}

calculator.hpp:

#ifndef __CALCULATOR_H
#define __CALCULATOR_H

#include "math.hpp"

class Calculator {
public:
bool load(char* library);
bool calculate();
bool close();
private:
void* handle;
Math* math;
};

#endif

math.hpp:

#ifndef __MATH_H
#define __MATH_H

class Math {
public:
virtual float multiply(float a, float b);
virtual float square(float a);
};

#endif

math.cpp:

#include "math.hpp"

float Math::multiply(float a, float b) {
return a*b;
}

float Math::square(float a) {
return a*a;
}

extern "C" {
Math *maker() {
return new Math;
}
}


I'm using g++ 3.2.3 and below is the makefile used to compile the
program.

LIB_SRC = math.cpp
LIB_OBJ = math.o
LIB = math

BIN_SRC = main.cpp calc.cpp
BIN = calc

LIB_VER_MAJOR =
LIB_VER_MINOR =

CC = g++
LIB_OBJ_FLAGS = -fPIC -c -Wall -g
LIB_SO_FLAGS = -shared -lc -Wl,-soname
BIN_FLAGS = -rdynamic -ldl -Wall -g

all: lib.o lib.so bin

lib.o:
$(CC) $(LIB_OBJ_FLAGS) $(LIB_SRC)

lib.so:
$(CC) $(LIB_SO_FLAGS),$(LIB).so.$(LIB_VER_MAJOR) \
-o $(LIB).so$(LIB_VER_MAJOR)$(LIB_VER_MINOR) $(LIB_OBJ)

bin:
$(CC) $(BIN_FLAGS) -o $(BIN) $(BIN_SRC)

clean:
rm -f *.o *.so* $(BIN)


Any pointers/suggestions to solve this problem will be really
appreciated. The argument to calc exe is math.so

Thanks & Regards,

Karthik D

Greetings and welcome to comp.lang.c++. Unfortunately, because dlsym()
is not a standard library function, this question is outside the scope
of this newsgroup, which is intended for discussions of the language
itself rather than third-party library or platform-specific questions.
I'd suggest you post in a newsgroup for your platform or compiler. See
the FAQ for some suggestions of where to post:

http://www.parashift.com/c++-faq-lite/how-to-post.html#faq-5.9

Cheers! --M
 
A

Artie Gold

Hello All,

I am a newbie to C++. I was trying a sample program from internet which
demonstrates dynamic class loading in C++. Actually, I thought of using
this design, in one of the applications I am working on.

However, the compilation was through. But when ran, the program
generated a SIGSEGV error. I debugged it using gdb and found that ,when
the symbol returned by dlsym() was invoked, the resulting value was
null.

Though dlsym() is not part of standard C++ (and therefore off topic) you
have a rather different problem in your code -- of the `Doh!' variety.

See below. You've been thinking too hard. ;-)
I couldn't understand clearly why it didn't worked. The problematic
location in the code
has been denoted below(calc.cpp):

calc.cpp:

#include "calculator.hpp"
typedef Math* (*factory)(void);

bool Calculator::load(char* library_name) {

factory make;

/* Open shared library */
handle = dlopen(library_name, RTLD_NOW);
if (!handle) {
cout << dlerror();
return false;
}

/* Load symbols from library */
make = (factory)dlsym(handle, "maker");
if (make = NULL) {

No matter *what* dlsym() returned, you just set it to NULL in the above
line!!!! [Hint: *Turn up the warning level on your compile*!!]
cout << dlerror() << "\n";
return false;
}

/* Construct object */
math = (*make)(); ===> *** This is Problem location***

Well, no it's not. See above.

[snip]

HTH,
--ag
 
G

Gianni Mariani

Any pointers/suggestions to solve this problem will be really
appreciated. The argument to calc exe is math.so

Don't use dlsym. Look at somthing like Austria C++ generic factories.
It is a standard C++ way of doing the same thing. No need to use extern
"C".

The documentation has alot to be desired.
http://austria.sourceforge.net/dox/html/group__GenericFactories.html

Basically, you define an interface class.

class MakerIF
{
public:
virtual void f() = 0;
};

Then in the file that makes the shared object (.so or .dll file).

----------------- impl.cpp -------------------------
#include "at_factory.h"
#include "app_interface.h"
class MakerImpl
: public MakerIF
{
public:
virtual void f()
{
Stuff();
}
};

// Register the factory
AT_MakeFactory0P( "NameOfImpl", MakerIF, MakerImpl, at::DKy );
----------------------------------------------------

------------------ main app code -------------------
#include "at_factory.h"
#include "app_interface.h"

int main()
{

void * dlhnd = dlopen( "impl.so" );

MakerIF * obj = at::FactoryRegister< MakerIF >
::Get().Create( "NameOfImpl" )();

if ( obj )
{
obj->f();
}
}
-----------------------------------------------------

Admitedly, it's been a while since I tested using dlopen(), but it
should be no issue. You will need to use Austria C++ as a .so/dll to
make this work or there needs to be exactly one place where the
FactoryRegisterRegistry::Get() function gets installed, otherwise it
won't work with multiple factory registries.
 
D

dkarthik

Hi Ag,

Thanks for pointing it out. It didn't striked me. Once I modified that,
it worked fine. Once again thanks.


Thanks & Regards,

Karthik D
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,997
Messages
2,570,241
Members
46,831
Latest member
RusselWill

Latest Threads

Top