Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use dlsym on a static binary

Is there any hope of running dlopen(NULL, ...) and getting symbols for a statically compiled binary?

For example, with the following code I can get symbols if the program is compiled dynamically and I use -rdynamic.

$ gcc -o foo foo.c -ldl -rdynamic
$ ./foo bar
In bar!

But with -static I get a cryptic error message:

$ gcc -static -o foo foo.c -ldl -rdynamic
/tmp/cc5LSrI5.o: In function `main':
foo.c:(.text+0x3a): warning: Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
$ ./foo bar
/lib/x86_64-linux-gnu/: cannot read file data: Is a directory

The source for foo.c follows:

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

int foo() { printf("In foo!\n"); }
int bar() { printf("In bar!\n"); }

int main(int argc, char**argv)
{
  void *handle;
  handle = dlopen(NULL, RTLD_NOW|RTLD_GLOBAL);
  if (handle == NULL) {
    fprintf(stderr, "%s\n", dlerror());
    return 1;
  }

  typedef void (*function)();
  function f = (function) dlsym(handle, argv[1]);
  if (f == NULL) {
    fprintf(stderr, "%s\n", dlerror());
    return 2;
  }
  f();

  return 0;
}
like image 524
bfroehle Avatar asked Jan 12 '13 02:01

bfroehle


1 Answers

Is there any hope of running dlopen(NULL, ...) and getting symbols for a statically compiled binary?

No.

On most UNIXes you can't even link with -static and -ldl at the same time. Using glibc you can, but the utility of doing so is very limited. Basically, this ability is present only to support /etc/nsswitch.conf, and nothing else.

There is also no point in doing the dynamic lookup you did.

If you are trying to allow one of foo, bar or baz be called depending on command line arguments, just put a table in, e.g.

struct { const char *fname, void (*fn)(void) } table[] =
  { {"foo", &foo}, {"bar", &bar}, ...};

for (int i = 0; i < ...; ++i)
  if (strcmp(argv[1], table[i].fname) == 0)
    // found the entry, call it
    (*table[i].fn)();

If you are trying to "maybe" call foo if it is linked in, and do nothing otherwise, then use weak references:

extern void foo(void) __attribute((weak));

if (&foo != 0) {
  // foo was linked in, call it
  foo();
}
like image 189
Employed Russian Avatar answered Oct 07 '22 02:10

Employed Russian