-rdynamic for select symbols only?
Asked Answered
M

3

6

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.

Mcdevitt answered 10/5, 2016 at 15:3 Comment(4)
Possible duplicate of Explicitly exporting shared library functions in LinuxAxis
Possible duplicate of how to call function in executable from my library?Cabot
@Cabot Nice find! That question itself is not my question. But it has an answer stackoverflow.com/posts/6298434/revisions that also anwers my question.Mcdevitt
@LudwigSchulze: I have shown an explicit example of how to do this in this answer. The original question there is pretty much exactly the same situation as you have here.Stegman
A
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.

Axis answered 10/5, 2016 at 15:17 Comment(1)
Thank you, but No. My question is about exporting symbols from the main executable, not from a library.Mcdevitt
E
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).

Equilibrate answered 29/11, 2017 at 16:29 Comment(1)
Yes, -Wl,--dynamic-list=<text file with list of symbols> is the way to do it. See stackoverflow.com/posts/6298434/revisions for an answer that gives an example symbol file.Mcdevitt
G
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.

Gantlet answered 12/7, 2023 at 14:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.