5

Scenario:

Executable loads shared object at run time via dlopen.

The shared object references some symbol (a function) that is actually compiled into the main executable.

This works fine if I add -rdynamic to gcc when linking the executable.

-rdynamic exports all non-static symbols of the executable. My shared object only needs a select few.

Question: Is there a way to achieve the effect of -rdynamic, but restricted the the few select symbols that I know are needed by my shared object?

Edit:

At least two people misunderstood the question, so I try to clarify:

This question is about exporting a symbol from the main executable.

This question is not about exporting a symbol from a dynamic library.

Here is a minimal example:

func.h, the common header file

#include <stdio.h>
void func(void);

main.c, the main executable code:

#include <dlfcn.h>
#include "func.h"

// this function is later called by plugin
void func(void) {
  printf("func\n");
}

int main() {
  void * plugin_lib = dlopen("./plugin.so", RTLD_NOW);
  printf("dlopen -> %p, error: %s\n", plugin_lib, dlerror());

  // find and call function "plugin" in plugin.so
  void (*p)(void); // declares p as pointer to function
  p = dlsym(plugin_lib, "plugin");
  p();

  return 0;
}

plugin.c, code for the plugin that is loaded at runtime:

#include "func.h"

void plugin()
{
  printf("plugin\n");
  func();
}

If I compile with

$ gcc -o main main.c -ldl
$ gcc -shared -fPIC -o plugin.so plugin.c

Then plugin.so cannot be loaded, because it references the symbol func, which cannot be resolved:

$ ./main
dlopen -> (nil), error: ./plugin.so: undefined symbol: func
Segmentation fault (core dumped)

I can convince the main executable to export all its global symbols by compiling with -rdynamic:

$ gcc -rdynamic -o main main.c -ldl
$ ./main
dlopen -> 0x75e030, error: (null)
plugin
func

But this fills the dynamic symbol table unnecessarily with all symbols.

(This dynamic symbol table can be inspected with nm -D main.)

The question is, how can I add only "func" to the dynamic symbol table of the main executable, and not everything.

Ludwig Schulze
  • 2,155
  • 1
  • 17
  • 36
  • Possible duplicate of [Explicitly exporting shared library functions in Linux](http://stackoverflow.com/questions/2164827/explicitly-exporting-shared-library-functions-in-linux) – greydet May 10 '16 at 15:18
  • Possible duplicate of [how to call function in executable from my library?](http://stackoverflow.com/questions/6292473/how-to-call-function-in-executable-from-my-library) – ninjalj May 10 '16 at 22:55
  • @ninjalj Nice find! That question itself is not my question. But it has an answer http://stackoverflow.com/posts/6298434/revisions that also anwers my question. – Ludwig Schulze May 10 '16 at 23:14
  • @LudwigSchulze: I have shown an explicit example of how to do this [in this answer](http://stackoverflow.com/a/36807145/1475978). The original question there is pretty much exactly the same situation as you have here. – Nominal Animal May 11 '16 at 18:36

3 Answers3

1

You could do it with the visibility attribute of GCC.

Declare the function you need to export with __attribute__ ((visibility ("default"))) flag. Then compile your whole library passing -fvisibility=hidden argument to GCC.

For full explanation on this, refer to the following GCC documentation page.

greydet
  • 5,509
  • 3
  • 31
  • 51
1

Unfortunately it's harder to achieve this for executables. You need to generate a list of symbols that you want to export and then add -Wl,--dynamic-list=symfile.txt to LDFLAGS.

Here's example of how it's done in Clang (and here's the script they use to generate the symbols file).

yugr
  • 19,769
  • 3
  • 51
  • 96
  • Yes, -Wl,--dynamic-list= is the way to do it. See https://stackoverflow.com/posts/6298434/revisions for an answer that gives an example symbol file. – Ludwig Schulze Dec 28 '17 at 18:04
0

greydet's answer is perfectly applicable for executables; after all, it's all just ELFs

The -Wl,--dynamic-list= solution is available even in ancient versions of GCC, so it is more compatible. Nowadays, there is no reason not to use -fvisibility= to achieve the same.

(source: https://flameeyes.blog/2011/01/20/hide-those-symbols and https://www.gnu.org/software/gnulib/manual/html_node/Exported-Symbols-of-Shared-Libraries.html)

// main.c

int fsym(void) { return 42; }

__attribute__((visibility("default"))) int gsym(void) { return 24; }

int main(void) { return 0; }

Compile this with gcc -fvisibility=hidden -rdynamic main.c and examine the symbols with nm --dynamic a.out

% gcc -fvisibility=hidden -rdynamic main.c
% nm --dynamic a.out | grep sym                    
0000000000401111 T gsym

Notice that fsym is not exported, while gsym is.

user7610
  • 25,267
  • 15
  • 124
  • 150