Selective static linking of library functions in a shared library

I want to create a shared library that uses functions from a third-party static library. For example, foo and bar from libfoobar.a . I know that my main application also uses foo and will export this symbol. So I just want to bind in bar to keep the code size and leave "foo" unresolved (as will be provided by the main application). If I include libfoobar.a , the ld linker will include both functions in my shared library. If I do not enable libfoobar.a , my library will not have access to the bar function, because the program itself does not bind to bar . Questions:

  • Is there a way to tell ld to allow only certain characters when creating a shared library?
  • Include libfoobar.a in the shared library?
  • Extract the file containing the bar function from libfoobar.a and point it to the linker line?
  • Don’t worry about this, the runtime loader will use bar from your application so that a copy of bar in the shared library is not loaded?
+7
linux shared-libraries ld static-linking
source share
3 answers

The following points try to answer my questions:

  • ld does not seem to allow you to omit the link to specific characters from the static library. Using --just-symbols or --undefined (or the EXTERN linker script command) will not prevent ld from joining the characters.
  • To convert the static library libfoobar.a to the general one, libfoobar.so.1.0 and export all visible characters. You can also use --version-script and other methods to export only a subset of characters.

    ld -shared -soname libfoobar.so.1 -o libfoobar.so.1.0 --whole-archive libfoobar.a --no-whole-archive

  • It is better to remove archive members from a copy of your static library than to extract them, because there may be internal dependencies that you have to manage. For example, if you export all the symbols, you can generate a map file from the main executable. Then you can grep for all members of the archive so that the executable file is pulled from the copy of the static library and removed from the copy. Therefore, when your DSO is linked in a static library, it will leave the same characters unresolved.

  • You can specify your main executable as a shared library for your DSO if you compile the executable with the --pie option. Your DSO will first contact your executable if it precedes the static library in the link command. The caveat is that the main executable must be accessible via LD_LIBRARY_PATH or -rpath . Also, using strace shows that since the executable is a dependency of your library, it loads again when your DSO loads.

    ld -shared -rpath '$ORIGIN' -L. -lc -ldl -o DSO.so DSO.o app libfoobar.a

  • The dynamic linker first uses the executable version of foo unless you call dlopen () with the RTLD_DEEPBIND flag. Using strace shows that all DSO is a file mapped to mmap2 () in memory. However, Wikipedia claims that for mmap, "Actual disk reads are done in a" lazy "way, after accessing a specific location." If so, the duplicate foo will not be loaded. Note that overriding only happens if your DSO has exported the foo function. Otherwise, the foo function statically associated with your DSO will be used whenever your DSO calls foo.

In conclusion, if mmap () uses lazy reading, then the best solution is to bind your DSO in normal mode and let the dynamic linker and linux take care of the rest.

+4
source share

I'm not the biggest expert in shared libraries, so I'm probably wrong!

If I can guess what you are trying to do, just connect your shared lib with libc.so. You do not need an extra copy of sscanf built into your library.

I answered your questions before I understood what you came to, in case you are interested in the answers.

Is there a way to tell ld to allow only certain characters when creating a shared library?

only in extern, and not in static, functions and variables are included in the symbol table of the shared library.

When you create your shared library, any characters not found in the objects on the linker command line remain unresolved. If the linker complains about this, you probably need to link your shared library to the shared libc. You can have shared libraries that depend on other shared libraries, and ld.so can work with dependency chains.

If I had more reputation, I would ask this as a comment: Do you have a customized version of sprintf / sscanf, or would it be nice if your shared library used the implementation in -lc? If -lc ​​is ok, then my answer probably solves your problem. If not, then you need to create your shared library from objects that have only the functions you need. those. do not associate it with /usr/lib/libc.a.

Maybe I am embarrassed by your

libc.a (not really the "real" libc) line. /usr/lib/libc.a is really glibc (on linux). This is a statically linked copy of the same code in libc.so. If you are not talking about your own libc.a (which I thought about first) ...

Include libc.a in the shared library? You probably can, but not like that, because it probably doesn't compile as position-independent code, so many ld.so moves will be required at runtime.

Extract sscanf from libc.a and indicate what's on the linker line?

Maybe. ar t / usr / lib / libc.a to display content. (ar args are like tar. tar was ar for tapes .... The old Unix school is here.) This is probably not that simple, because sscanf is probably dependent on the characters in other .o files in .a.

+1
source share

Answering your revised clearer question.

Keep in mind that usually the point of a shared lib is that several programs can communicate with it. Therefore, your optimization of using the main symbol of the program for the required function will work only if the main program always provides this symbol (through a static library or otherwise). This is usually not what people want to do.

If this is just a couple of small features, perhaps you should allow it. You will probably get two copies of the code for the functions, one in your shlib and one in the main program. If they are small (or at least not huge), or are not called often, and are not performance critical, then defeating the size of the two-copy code / I-cache is not something to worry about. (translation: I don’t know how to avoid this from my head, so I probably won’t find the time to look at it and make the Makefile more complicated to avoid it.)

See my other answer for some comments on how to mess with ar to extract material from a static library. summary: perhaps not trivial as you don't know the dependencies between the various .o files in .a.

You may be able to do what you are hoping for if your shared library exports the characters that it inserts from the static library. Then, when you link the main application, place your shared library in front of the static lib at the linker command line. ld will find "foo" in your shlib and use this copy (if this re-export trick is possible), but for "bar" it will have to include a copy from the static library.

ld --export-dynamic may be what you need to export all characters to a dynamic symbol table. Try this. Look for "exports" on the docs / man page. "export" is the jargon for creating the symbol visible in the library. --export-all-symbols is located in the i386 PE (Windows DLL) section, otherwise it would probably do the trick.

+1
source share

All Articles