Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

dlsym returns NULL, even though the symbol exists

Tags:

c

linux

dlsym

I am using dlsym to look up symbols in my program, but it always returns NULL, which I am not expecting. According to the manpage, dlsym may return NULL if there was an error somehow, or if the symbol indeed is NULL. In my case, I am getting an error. I will show you the MCVE I have made this evening.

Here is the contents of instr.c:

#include <stdio.h>

void * testing(int i) {
    printf("You called testing(%d)\n", i);
    return 0;
}

A very simple thing containing only an unremarkable example function.

Here is the contents of test.c:

#include <dlfcn.h>
#include <stdlib.h>
#include <stdio.h>

typedef void * (*dltest)(int);

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

    /* Declare and set a pointer to a function in the executable */
    void * handle = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL);
    dlerror();
    dltest fn = dlsym(handle, "testing");

    if(fn == NULL) {
        printf("%s\n", dlerror());
        dlclose(handle);
        return 1;
    }
    dlclose(handle);
    return 0;
}

As I step through the code with the debugger, I see the dlopen is returning a handle. According to the manpage, If filename is NULL, then the returned handle is for the main program. So if I link a symbol called testing into the main program, dlsym should find it, right?

Here is the way that I am compiling and linking the program:

all: test

instr.o: instr.c
    gcc -ggdb -Wall -c instr.c

test.o: test.c 
    gcc -ggdb -Wall -c test.c

test: test.o instr.o
    gcc -ldl -o test test.o instr.o 

clean:
    rm -f *.o test

And when I build this program, and then do objdump -t test | grep testing, I see that the symbol testing is indeed there:

08048632 g     F .text  00000020              testing

Yet the output of my program is the error:

./test: undefined symbol: testing

I am not sure what I am doing wrong. I would appreciate if someone could shed some light on this problem.

like image 345
OmarL Avatar asked May 08 '16 21:05

OmarL


2 Answers

I don't think you can do that, dlsym works on exported symbols. Because you're doing dlsym on NULL (current image), even though the symbols are present in the executable ELF image, they're not exported (since it's not a shared library).

Why not call it directly and let the linker take care of it? There's no point in using dlsym to get symbols from the same image as your dlsym call. If your testing symbol was in a shared library that you either linked against or loaded using dlopen then you would be able to retrieve it.

I believe there's also a way of exporting symbols when building executables (-Wl,--export-dynamic as mentioned in a comment by Brandon) but I'm not sure why you'd want to do that.

like image 150
Kristina Brooks Avatar answered Oct 06 '22 02:10

Kristina Brooks


I faced the similar issue in my code.

I did the following to export symbols

  #ifndef EXPORT_API
  #define EXPORT_API __attribute__ ((visibility("default")))
  #endif 

Now for each of the function definition I used the above attribute.

For example the earlier code was

     int func() { printf(" I am a func %s ", __FUNCTION__ ) ;

I changed to

     EXPORT_API int func() { printf(" I am a func %s ", __FUNCTION__ ) ;

Now it works.

dlsym gives no issues after this.

Hope this works for you as well.

like image 45
AnotherDeveloper Avatar answered Oct 06 '22 02:10

AnotherDeveloper