2

I am working with a legacy C library that can be extended by writing user defined function(s) and then recompiling the source. I want to avoid the compilation requirement, and instead extend it ONCE with a function (see pseudocode below):

This function will be implemented like this:

VARIANT_TYPE CallSharedLibFunction(const char* library_name, const char* funcname, const char *params, const char* return_type){
// parse arguments and get data types and count
// initiate variable of data type indicated by return_type, to hold returned variable

/* this is the part I need help with */
// lptr = LoadSharedLibrary(library_name);
// funcptr = GetFunctionAddress(lptr, funcname);

// call function and pass it arguments
retvalue = funcptr(param1, param2, param3);

// wrap up returned value in the VARIANT_TYPE
VARIANT_TYPE ret;
setVariantValue(ret, retvalue, return_type);

return ret;

}

Note: despite the "Windows sounding" names (VARIANT_TYPE, LoadSharedLibrary and GetFunctionAddress), I am developing on Linux (Ubuntu 9.10). Ideally, I would like the library loading implementation to be cross platform (since I am using ANSI C code). But if I have to choose one platform, it will have to be the Linux platform.

I would be very grateful if anyone could shed some light on how I can invoke functions in arbitrary shared libraries (ideally, in a cross platform way - failing that, on Linux), so that I can implement the above function.

3 Answers 3

5

You might want to have a look at the dlopen, dlsym and similar functions. These work on POSIX (linux, OSX, win32+cygwin etc...).

With dlopen(), you can open a shared library. Your LoadSharedLibrary can be a wrapper around dlopen(). You GetFuncPtr() function can be a wrapper around dlsym(). What you can do is write code around the dl*() functions to make it robust - like do some error checking. You also might want to define an interface in the shared library, i.e. a struct that 'exports' supported functions. This way you can get a list of methods without the need to resorting to reading elf files.

There is also a nice page about function pointers in C and C++.

Here's a quick example on the usage:

void* LoadSharedLibrary(const char* name)
{
   return dlopen(name, RTLD_LOCAL | RTLD_LAZY);
}    

void* GetFunctionAddress(void* h, const char* name)
{
   return dlsym(h, name);
}

const char** GetFunctionList(void* h)
{
   return (char**)dlsym(h, "ExportedFunctions");
}

// Declare a variable to hold the function pointer we are going to retrieve.
// This function returns nothing (first void) and takes no parameters (second void).
// The * means we want a pointer to a function.
void (*doStuff)(void);

// Here we retrieve the function pointer from the dl.
doStuff = GetFunctionAddress(h, "doStuff");

// And this how we call it. It is a convention to call function pointers like this.
// But you can read it as 'take contents of the doStuff var and call that function'.
(*doStuff)();
Sign up to request clarification or add additional context in comments.

1 Comment

Hi Johan, this looks like what I'm looking for (shame I cant bump up your answer!). However, could you explain this, (its a bit cryptic to me): (void*)(&doStuff) = GetFunctionAddress(h, "doStuff"); (*doStuff)();
2

For Linux/POSIX, you use the dlopen() family of functions to load shared libraries at runtime, look up symbol addresses, and so on.

If you want to add a library dependency to make working with loadable code a bit easier (and more portable), look into glib's module API.

Comments

0

use dlopen/dlsym as well as compile it with -fPIC / FPIC code

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.