dlsym returns NULL, even though the symbol exists
Asked Answered
R

2

10

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.

Retiform answered 8/5, 2016 at 21:19 Comment(3)
coliru.stacked-crooked.com/a/3048847bea8edb97 Adding: -Wl,--export-dynamic makes your program work. Without it, you get the error undefined symbol: 'testing'.Tonicity
Using "-rdynamic" while linking will also solve the problemKannada
@RahulSreeram You want to write an answer then? It'd get an upvote from me.Retiform
C
6

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.

Cristobal answered 8/5, 2016 at 21:41 Comment(4)
There's little or no real distinction between ELF programs and ELF shared libraries. In fact, some shared libraries contain a main() function and can be run as programs. There is no particular reason why an ELF "program" could not be loaded as a shared library. All the same, I'm sure you're right that the problem is that the symbol in question is not exported.Furbelow
There's no point in using dlsym to get symbols from the same image as your dlsym call and I'm not sure why you'd want to do that. are very counterproductive things to say. There are use-cases.Bicentenary
I don't think they are, for shared libraries interposition is a use case but if you're the main binary your symbols (strong aliases) take precedence over anything if you want to interpose something which makes dlsym on self redundant. Unless you want to go into the edge case territory of LD_PRELOAD libraries or lazy loaded dynamic libs hooking explicitly exported symbols by an executable, anything can be done through attributes that influence how static linker treats some symbols. If there are other use cases, feel free to add them as an answer, I'm genuinely curious myself as I'm not aware.Cristobal
@KristinaBrooks There do exist certain valid cases, e.g. by the symbol resolution RTDyldObjectLinkingLayer used in LLVM ORC JIT, where the symbol is known statically (not in an external dynamic library) but referenced in some LLVM IR generated at runtime.Murrey
T
1

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.

Thoraco answered 24/4, 2019 at 3:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.