Peter T.B. Brett
Peter T.B. Brett

Reputation: 1280

Using dlsym() to look for a variable in a statically linked library

We have a program that links in a number of static libraries, which may or may not define a number of symbols depending on compilation options. On OS X, we use dlsym(3) with a NULL handle to obtain the symbol addresses. However, on Linux, dlsym(3) always returns NULL.

Consider a trivial program (sources below) that links in a static library containing a function and a variable and tries to print their addresses. We can check that the program contains the symbols:

$ nm -C test | grep "test\(func\|var\)"
0000000000400715 T testFunc
0000000000601050 B testVar

However, when the program is run, neither can be located:

$ ./test
testVar: (nil)
testFunc: (nil)

Is what we are trying to do possible on Linux, using glibc's implementation of dlsym(3)?

 Makefile

(Sorry about the spaces)

LDFLAGS=-L.
LDLIBS=-Wl,--whole-archive -ltest -Wl,--no-whole-archive -ldl

libtest.o: libtest.c libtest.h
    libtest.a: libtest.o
test: test.o libtest.a
clean:
    -rm -f test test.o libtest.o libtest.a

libtest.h

#pragma once
extern void *testVar;
extern int testFunc(int);

libtest.c

#include "libtest.h"
void *testVar;
int testFunc(int x) { return x + 42; }

test.c

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

int main(int argc, char *argv[]) {
  void *handle = dlopen(NULL, 0);
  void *symbol = dlsym(handle, "testVar");
  printf("testVar: %p\n", symbol);
  symbol = dlsym(handle, "testFunc");
  printf("testFunc: %p\n", symbol);
  return 0;
}

Upvotes: 5

Views: 3417

Answers (1)

You should link your program with -rdynamic (or --export-dynamic for ld(1)) so

LDFLAGS += -rdynamic -L.

Then all the symbols are in the dynamic symbol table, the one used by dlsym

BTW, the visibility attribute could be of interest.

Upvotes: 4

Related Questions