4

I am working on code that creates 'models'. A model is created from an XML file and part of its representation is, generated on the fly, C code. This C code is compiled, on the fly, into a shared library that is dynamically loaded (using POCO shared lib class). The shared library mainly contains small functions, and part of a models creation is to populate function pointers to these functions. All this works fine. However, creating several models, at the same time, causes problems.

I believe it has to do with how the dynamic loading works on Linux, and the fact that each shared library contain functions with identical names. Does PIC cause this? The problems manifest itself in no sense data being retrieved from shared libraries functions.

So question is, how to load multiple (thousands) shared libraries, containing identical function names, on linux?

The above works fine on windows, where it seems that dynamically loaded libraries data/functions are kept perfectly isolated from each other.

Totte Karlsson
  • 1,261
  • 1
  • 20
  • 55

2 Answers2

3

First, you can dlopen many hundreds of thousands of shared objects. My manydl.c demonstrate that.

Then, you can also generate C code, compile it, and dlopen the shared object, all this from the same process. My (obsolete in 2017) MELT plugin (for GCC, MELT provides a high level language to extend GCC) does that (and so does my manydl.c example).

However, I don't think you should keep identical (defined) function names in them. I suggest avoiding that. You could

  1. generate unique names (since the C code is generated, this is the best, most portable, and simplest solution)

  2. compile with some -D flags to #define these names to unique names, so the source code could apparently contain duplicate names; that is if your generated code defines the foo function pass a -Dfoo=foo_123 (with foo_123 being globally unique) to the gcc command compiling it. (Of course you then dlsym for "foo_123").

  3. add visibility("hidden") function attributes in your generated code. You could also pass -fvisibility=hidden option to gcc.

  4. have only static functions (then, the name don't matter much so can be duplicate), and have a constructor function which somehow binds the functions (e.g. store their pointer somewhere, e.g. in some global table).

  5. you might consider passing RTLD_LOCAL to dlopen(3). I'm not sure it is a good idea (and POCO probably don't know how to do that).

PS. I don't think it is related to position independent code (which is preferable, but not absolutely required, in shared objects; without -fPIC the dlopen would have to do a lot of inefficient relocations). It is related to Linux shared object linking & loading. Read Levine's Linkers & Loaders book for details.

See also this question, and read Drepper's paper on How to Write Shared Libraries.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • Thanks for the suggestions. Giving the functions unique names was my first thought, but it would require a lot of rewriting in the API. However the real answer to this question was much simpler, fortunately there is a linker flag that controls how symbols are resolved, RTLD_GLOBAL and RTLD_LOCAL. Default is RTLD_GLOBAL. Setting the loader flag to RTLD_LOCAL fixed the problem! – Totte Karlsson Feb 28 '13 at 20:43
  • I did mention `RTLD_LOCAL` but I don't believe it is the good approach. I don't understand why generating unique names change the API (the name is mostly useful to `dlsym`), unless one generated shared object has functions directly called from another generated shared object. – Basile Starynkevitch Feb 28 '13 at 20:49
  • Why do you think RTLD_LOCAL is a not a good approach? The shared libraries do not contain any objects, but straightforward C functions. However, these functions are made part of the internal model class, meaning that changing their names would result in a considerable internal changes. Setting the linker flag circumvent all that. – Totte Karlsson Feb 28 '13 at 22:03
3

Poco SharedLibrary open function accepts linker flags. Default is Poco::SharedLibrary::SHLIB_GLOBAL, corresponding to dlopens RTLD_GLOBAL and Poco::SharedLibrary::SHLIB_LOCAL, corresponding to RTLD_LOCAL. See http://linux.die.net/man/3/dlopen for more info.

Passing the Poco::SharedLibrary::SHLIB_LOCAL flag fixed the problem.

Totte Karlsson
  • 1,261
  • 1
  • 20
  • 55