Reputation: 2325
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.
Upvotes: 6
Views: 1783
Reputation: 28879
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.
Upvotes: 0
Reputation: 21955
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).
Upvotes: 1
Reputation: 5539
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.
Upvotes: 1