I am trying to compile the example code which is using APIs from libdl library:
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int
main(int argc, char **argv)
{
void *handle;
double (*cosine)(double);
char *error;
handle = dlopen("libm.so", RTLD_LAZY);
if (!handle) {
fprintf(stderr, "%s\n", dlerror());
exit(EXIT_FAILURE);
}
dlerror(); /* Clear any existing error */
/* Writing: cosine = (double (*)(double)) dlsym(handle, "cos");
would seem more natural, but the C99 standard leaves
casting from "void *" to a function pointer undefined.
The assignment used below is the POSIX.1-2003 (Technical
Corrigendum 1) workaround; see the Rationale for the
POSIX specification of dlsym(). */
*(void **) (&cosine) = dlsym(handle, "cos");
if ((error = dlerror()) != NULL) {
fprintf(stderr, "%s\n", error);
exit(EXIT_FAILURE);
}
printf("%f\n", (*cosine)(2.0));
dlclose(handle);
exit(EXIT_SUCCESS);
}
I used the following command to compile:
--> gcc -static -o foo foo.c -ldl
I got the following error:
foo.c:(.text+0x1a): warning: Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
After google, since I am trying to compile it statically, I can find the libdl.a in the lib directory. I am getting the same issue with gethostbyname API also..
What are the other libraries needs to add to compile dl_open statically.
One possible problem:
dlsym()
Should be declared or implemented before it is referenced in main().
dlopen() works only with shared libs. That means that you can't link it statically. Have you tried without -static ?
Related
Having this files:
plusone.c
int op(int i){ return i+1; }
main.c
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int main(int argc, char **argv){
if (argc<3){
printf("usage %s <library> <number>\n",argv[0]);
exit(1);
}
char *lname = argv[1];
int num = atoi(argv[2]);
void *handle = dlopen(lname, RTLD_LAZY);
if(!handle)
perror("dlopen");
int (*opp)(int);
opp=dlsym(handle, "op");
if(!opp)
perror("dlsym");
printf("number before:%i\nnumber after:%i\n",num,opp(num));
dlclose(handle);
}
Compiled as:
$cc -fPIC -shared -o plusone.so -ldl plusone.c
$cc -o main.exe -ldl -Wpedantic main.c
warning: ISO C forbids assignment between function pointer and ‘void *’ [-Wpedantic]
$ls
main.c main.exe plusone.so main.exe
$main.exe
usage main.exe <library> <number>
$main plusone.so 1
dlopen: Success
dlsym: Success
Segmentation fault
Why is segfault?
As could be seen from the bash output, both the dlopen and dlsym give success (but they should not even output, otherwise that mean, the condition was true, and the returned values from those functions was NULL? - as from condition). But even of the "success" the perror returned, I cannot reproduce the segfault, since do not know where is the bug.
Why is segfault?
Most likely because opp equals NULL the moment opp(num) is trying to be called.
You do not handle errors correctly for the calls to dlopen() and dlysym(), although the code tests the results it does not take the correct actions on failure of those two functions.
This code
void *handle = dlopen(lname, RTLD_LAZY);
if(!handle)
perror("dlopen");
correctly branches on dlopen() returning NULL which indicated an error, but then the code takes the wrong actions.
dlopen() does not set errno, so using perror() to log an error makes no sense, as perror() relies on errno indicating an error, which is does not. So on failure of dlopen() you see perror() printing
dlopen: Success
which is misleading and contractionary to the fact that perror() was called at all, which in fact only happened if dlopen() returned NULL, indicating a failure. If dlopen() would have succeeded, perror() would not have been called at all and nothing would have been printed.
The same mistake appears with the call to dlsym().
To retrieve error info on failure of a member of the dl*() family of functions use dlerror().
For an example on how to correctly and completely implement error handling see below:
void *handle = dlopen(...);
if (!handle)
{
fprintf(stderr, "dlopen: %s\n", dlerror());
exit(EXIT_FAILURE); /* Or do what ever to avoid using the value of handle. */
}
#ifdef DEBUG
else
{
fputs("dlopen: Success\n", stderr);
}
#endif
The same approach should be taken to handle the outcome of dlsym().
Aside of all this and unrelated to the observed behaviour the code misses to call dlclose() when done with using a valid handle.
I have one base library written in C. And other external extensions/definitions files. With a simple search tool the base library (when is used) can search in a directory for extensions libraries. Without telling the compiler which files it are. Then the C program can call a function in that external file.
So i want to run a function in a external file. I can choose which file I want to run the function from at running time. (Ex, I enter that the file is located at ./external_file at running time) (NOT COMPILE TIME!). Is this possible?
I need to read a return from the function, I need to wait until the function is finished, I need to call the function with arguments and it must be possible that the program at run time can choose the file and function.
Is this possible? Yes, program files does contains function names (with names). Only I need to know HOW do I call that function in a external file at run time.
Use dynamic libraries - most OS's provide support for loading a library given a name and getting the address of the function to call.
In windows see LoadLibrary and ProcAddress. In linux see dlopen and dlsym.
You can use the dlopen function to load a shared library (i.e. a .so file) at runtime, then use dlsym to get the functions to call.
For example, suppose you had the following library file:
mylib.c:
#include <stdio.h>
void f1(int a)
{
printf("in f1, a=%d\n", a);
}
int f2(char *s)
{
printf("in f2, s=%s\n", s);
return *s;
}
Then you compile it to a shared library:
gcc -g -Wall -Wextra -fPIC -c mylib.c
gcc -g -Wall -Wextra -fPIC -o libmylib.so mylib.o
You can call these functions as follows:
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int main()
{
// get a handle to the shared library
void *handle = dlopen("./libmylib.so", RTLD_LAZY);
if (!handle) {
printf("dlopen failed: %s\n", dlerror());
exit(1);
}
// get a pointer to the function to call
void (*myf1)(int) = dlsym(handle, "f1");
if (!myf1) {
printf("dlsym 1 failed: %s\n", dlerror());
exit(1);
}
myf1(4);
// get a pointer to another function to call
int (*myf2)(char *) = dlsym(handle, "f2");
if (!myf2) {
printf("dlsym 2 failed: %s\n", dlerror());
exit(1);
}
printf("rval=%d\n", myf2("hello"));
dlclose(handle);
return 0;
}
Note that you need to know at compile time what the function signatures look like so you can call them correctly.
I want to load a shared library with dlopen and have the symbols in it available without having to individually grab function pointers to them with dlsym. The man page says that the RTLD_DEEPBIND flag will place lookup of symbols in the library ahead of global scope, but evidently this does not mean it overrides existing symbols because this does not work. Consider this example:
main.c:
#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
int is_loaded(){return 0;}
int main(){
void *h = dlopen("./libimplementation.so", RTLD_NOW | RTLD_DEEPBIND);
if(!h){
printf("Could not load implementation: %s\n", dlerror());
return 1;
}
puts(is_loaded() ? "Implementation loaded" : "Implementation not loaded");
dlclose(h);
}
implementation.c:
int is_loaded(){return 1;}
Makefile:
all: main libimplementation.so
main: main.c
gcc -Wall -std=c99 -o $# $^ -ldl
lib%.so: %.c
gcc -Wall -std=c99 -o $# $^ -shared
clean:
-rm main *.so
When I build and run with make and ./main, I expect the test() function from libimplementation.so to override the test() function from main but it doesn't. I know I could also move all of the code in main() into another shared library run and then have main() dlopen libimplementation.so with RTLD_GLOBAL and then have librun.so refer to the symbols from libimplementation.so without having them defined so it loads them:
modified main.c:
#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
int main(){
void *impl_h = dlopen("./libimplementation.so", RTLD_LAZY | RTLD_GLOBAL);
if(!impl_h){
printf("Could not load implementation: %s\n", dlerror());
return 1;
}
void *run_h = dlopen("./librun.so", RTLD_LAZY);
if(!run_h){
printf("Could not load run: %s\n", dlerror());
dlclose(impl_h);
return 1;
}
void (*run)(void);
*(void**)&run = dlsym(run_h, "run");
if(!*(void**)&run){
printf("Could not find entry point in run: %s\n", dlerror());
dlclose(impl_h);
dlclose(run_h);
return 1;
}
run();
dlclose(impl_h);
dlclose(run_h);
}
run.c:
#include <stdio.h>
int is_loaded(void);
void run(void){
puts(is_loaded() ? "Implementation loaded" : "Implementation not loaded");
}
and the Makefile gets librun.so added as a prerequisite for all.
Is there a way to get the symbols from the shared library available all at once without dlsym or putting the actual code in another shared library like with librun.so?
There is fundamentally no way to do what you're asking for. Imagine the main program had something like:
static char *myptr = array_in_lib1;
Later, at the time you dlopen, myptr has some other value. Has the program just changed the variable to point to a different object? Or has it been incremented to point to some element later in the array - in which case, would you want it adjusted to account for the redefinition of array_in_lib1 with a new definition from the newly-opened library? Or is it just a random integer cast to char *? Deciding how to treat it is impossible without understanding programmer intent and full process history of how it arrived in the current state.
The above is a particulrly egregious sort of example I've constructed, but the idea of symbols changing definition at runtime is fundamentally inconsistent in all sorts of ways. Even RTLD_DEEPBIND, in what it already does, is arguably inconsitent and buggy. Whatever you're trying to do, you should find another way to do it.
I've got an issue I am not able to solve. Looked up everything I found so far.
My problem is, I create a dyn library in my program a want to dlopen it and dlsym a method out of that lib.
It seems that dlopen works but dlsym return me the error "undefined symbol: method"
where "method" is the name of the method I passed to dlsym.
Here is how I create the library:
execl("/usr/bin/gcc", "gcc", "-fPIC", "-Wall", "-g", "-c", "userinput.c", NULL);
and:
execl("/usr/bin/gcc", "gcc", "-ggdb3", "-shared",
"-Wl,-soname,libuserinput.so.1", "-o", "libuserinput.so.1.0",
"userinput.o", "-lc", NULL);
This should work as there is a library after running my code.
I open the library like this:
static void *my_load_dyn (const char *lib) {
static void *handle;
handle = dlopen ("./libuserinput.so.1.0", RTLD_NOW | RTLD_DEEPBIND);
if (handle == NULL) {
printf ("error at dlopen(): %s\n", dlerror ());
exit (EXIT_FAILURE);
}
return handle;
}
/* load func from dyn lib"*/
static void *my_load_func (void *handle, char *func) {
void *funcptr = dlsym (handle, func);
if (funcptr == NULL) {
printf ("error at dlsym(): %s\n", dlerror ());
exit (EXIT_FAILURE);
}
return funcptr;
}
and call those functions like this:
void *libhandle;
void (*userMethod) (unsigned char *d);
libhandle = my_load_dyn(LIBUSERINPUT);
userMethod = my_load_func(libhandle, "testMethod");
(*userMethod)(d);
EDIT:
here is the code from the userinput.c:
#include <stdio.h>
#include <unistd.h>
void testMethod(unsigned char *d)
{
d[0] = 'Z';
}
It is generated in my programm and also compiled and linked in the running programm
i can see two possible problems
there's a problem in the code
are you sure that you declare your method as a public function in userinput.c?
e.g. if your method is declared static, then it won't be accessible from "outside".
also there are other ways to hide functions from being seen outside of the library, but it's impossible to tell whether you are having that problem without seeing any code.
your compilation/linking of the library is broken
e.g. you seem to be linking in a header-file (userinput.h) into the resulting libray?
i'd suggest to use a proper build system until the problem is solved, and switch to on-the-fly compilation later (e.g. using make)
When loaded a shared library is opened via the function dlopen(), is there a way for it to call functions in main program?
Code of dlo.c (the lib):
#include <stdio.h>
// function is defined in main program
void callb(void);
void test(void) {
printf("here, in lib\n");
callb();
}
Compile with
gcc -shared -olibdlo.so dlo.c
Here the code of the main program (copied from dlopen manpage, and adjusted):
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
void callb(void) {
printf("here, i'm back\n");
}
int
main(int argc, char **argv)
{
void *handle;
void (*test)(void);
char *error;
handle = dlopen("libdlo.so", RTLD_LAZY);
if (!handle) {
fprintf(stderr, "%s\n", dlerror());
exit(EXIT_FAILURE);
}
dlerror(); /* Clear any existing error */
*(void **) (&test) = dlsym(handle, "test");
if ((error = dlerror()) != NULL) {
fprintf(stderr, "%s\n", error);
exit(EXIT_FAILURE);
}
(*test)();
dlclose(handle);
exit(EXIT_SUCCESS);
}
Build with
gcc -ldl -rdynamic main.c
Output:
[js#HOST2 dlopen]$ LD_LIBRARY_PATH=. ./a.out
here, in lib
here, i'm back
[js#HOST2 dlopen]$
The -rdynamic option puts all symbols in the dynamic symbol table (which is mapped into memory), not only the names of the used symbols. Read further about it here. Of course you can also provide function pointers (or a struct of function pointers) that define the interface between the library and your main program. It's actually the method what i would choose probably. I heard from other people that it's not so easy to do -rdynamic in windows, and it also would make for a cleaner communication between library and main program (you've got precise control on what can be called and not), but it also requires more house-keeping.
Yes, If you provide your library a pointer to that function, I'm sure the library will be able to run/execute the function in the main program.
Here is an example, haven't compiled it so beware ;)
/* in main app */
/* define your function */
int do_it( char arg1, char arg2);
int do_it( char arg1, char arg2){
/* do it! */
return 1;
}
/* some where else in main app (init maybe?) provide the pointer */
LIB_set_do_it(&do_it);
/** END MAIN CODE ***/
/* in LIBRARY */
int (*LIB_do_it_ptr)(char, char) = NULL;
void LIB_set_do_it( int (*do_it_ptr)(char, char) ){
LIB_do_it_ptr = do_it_ptr;
}
int LIB_do_it(){
char arg1, arg2;
/* do something to the args
...
... */
return LIB_do_it_ptr( arg1, arg2);
}
The dlopen() function, as discussed by #litb, is primarily provided on systems using ELF format object files. It is rather powerful and will let you control whether symbols referenced by the loaded library can be satisfied from the main program, and generally does let them be satisfied. Not all shared library loading systems are as flexible - be aware if it comes to porting your code.
The callback mechanism outlined by #hhafez works now that the kinks in that code are straightened out.