How to create a shared object that is statically linked to pthreads and libstdc ++ on Linux / gcc?

How to create a shared object that is statically linked to pthreads and libstdc ++ on Linux / gcc?

+4
source share
3 answers

Before proceeding to answer your question, as described, I will notice that in the end it is not entirely clear what you are trying to achieve, and probably the best solution to your problem.

However, there are two main problems with trying to do what you described:

  • One of them is that you need to decompose libpthread and libstdc++ into the files of the objects with which they are made. This is because the ELF binaries (used on Linux) have two levels of the “runtime” library loading - even when the static executable file is loaded, the loader must load the statically linked libraries in the executable binary file and display the correct memory addresses. This is done before the general link of libraries that are dynamically loaded (shared objects) and displayed in shared memory. Thus, a shared object cannot be statically linked to libraries such as at the time the object was loaded; all static linked libraries have already been loaded. This is one difference between linking to a static library and a simple object file - a static library does not just stick together, like any object file, into an executable file, but it still contains separate tables that are mentioned during loading. (I believe this runs counter to the much simpler static libraries in MS-DOS and the classic Windows .LIB , but maybe more than I remember).

    Of course, you do not need to decompose libpthread and libstdc++ , you can just use the object files created when they were created. Collecting them can be a little tricky (looking for objects that are referenced by the final Makefile rule of these libraries). And you will need to use ld directly, not gcc / g++ for reference, so as not to mess with dynamic versions.

  • The second problem is indirect. If you do this, you will definitely get the shared / dynamic library that you want to create. However, this will not be very useful, because as soon as you try to link a regular executable file that uses these libpthread / libstdc++ (the last of which is any C ++ program) with this shared object, it will fail with character conflicts - characters of the static libpthread / libstdc++ objects that you linked your shared object to will encounter characters from the standard libpthread / libstdc++ used by this executable, regardless of whether it is dynamically or statically linked to standard libraries.

    You could, of course, try either to hide all the symbols in the static objects from libstdc++ / libpthread used by your shared library, make them private, or rename them automatically in some way, so that there will be no conflict. However, even if you get this to work, you will find some unwanted results at runtime, since both libstdc++ / libpthread save quite a bit of state in global variables and structures that you will now have a duplicate and each one does not know the other. This will lead to inconsistencies between this global data and the underlying state of the operating system, such as file descriptors and memory limits (and possibly some values ​​from the standard C library, such as errno for libstdc++ , and signal handlers and timers for libpthread .

To avoid an overly broad interpretation, I will add a remark: at times there may be reasonable grounds for static linking against even such basic libraries as libstdc++ and even libc , and even if it becomes a bit more complicated with the latest systems and versions of these libraries (due to a small link with the bootloader and special intermediary tricks), this is definitely possible - I have done this several times and know other cases in which it is still done. However, in this case, you need to link the entire executable statically. Static linking with standard libraries in combination with dynamic linking with other objects is usually not possible.


Edit: One of the issues that I forgot to mention but is very important is C ++. C ++, unfortunately, was not well designed for the classical model of binding and loading objects (used on Unix and other systems). This makes C ++ shared libraries not very portable, as it should be, because many things, such as type information and templates, are not shared between objects (often taken along with a lot of actual library code at compile time from the headers) . libstdc++ for this reason is closely related to GCC, and code compiled with one version of g++ will only work with libstdc++ with this (or very similar) version of g++ . Since you will probably notice that you will ever try to create a program with GCC 4 with any non-trivial library on your system that was built using GCC 3, it is not just libstdc++ . If your reason for this is to make sure your shared object is always associated with the specific versions of libstdc++ and libpthread with which it was created, this will not help, because a program using another / incompatible libstdc++ will also be built with an incompatible compiler C ++ or g++ version and thus will not be able to communicate with your shared object in any way, except the actual libstdc++ conflicts.

If you are wondering, “Why wasn’t it easier?”, The general reflection is worth considering: for C ++ it’s good to work with dynamic / shared libraries (which means compatibility between compilers and the possibility of replacing the dynamic library with another version with a compatible interface without rebuilding everything that uses it) requires not only standardization of the compiler, but also the level of the bootloader of the operating system, the structure and interface of files of objects and libraries, and the work of the linker should be significantly expanded besides the relatively simple classical Unix used in common operating systems (Microsoft Windows, Mach-based systems and NeXTStep siblings such as Mac OS, VMS siblings, and some mainframe systems are also included) for self-tuning code today. The linker and the dynamic loader would need to know about things such as templates and typing, to some extent have the functionality of a small compiler , in order to actually adapt the library code to the type given to it - and (personal subjective observation here) it seems that the intermediate intermediate code at a higher level (together with higher-level languages ​​and compilation "just in time") they catch the earth faster and are likely to be standardized earlier than such extensions for their own object formats and layouts shchikov.

+8
source

You mentioned in a separate comment that you are trying to port the C ++ library to an embedded device. (I am adding a new answer here instead of editing my original answer here because I think other StackOverflow users interested in this original question may still be interested in this answer in its context)

  • Obviously, depending on how the embedded system is trimmed (I don't have many Linux built-in features, so I'm not sure which is most likely), you can of course just install the generic libstdc++ on it and dynamically link everything like you would otherwise.

  • If dynamic linking to libstdc++ not suitable for you or does not work on your system (there are many different levels of embedded systems that are impossible to know), and you need to link static libstdc++ , then, as I said, your only real option is static linking of the executable file using the library with it and libstdc++ . You mentioned porting the library to an embedded device, but if it is intended to be used in some code, you write or create a device, and you don't mind static libstdc++ , and then set everything statically (except, possibly, libc ), probably OK.

  • If the size of libstdc++ is a problem and you find that your library actually uses only a small part of its interfaces, I suggest that you first try to determine the actual space that you would save by linking only those parts that you need. It can be significant or not, I have never looked so deep into libstdc++ , and I suspect it has a lot of internal dependencies, so although you probably do not need some interfaces, you may or may not still depend on much of it internal organs - I do not know and do not try, but it may surprise you. You can get the idea by simply linking the binary library with its static assembly and libstdc++ (without forgetting, for example, breaking the binary code), and compare the size of the resulting executable, which with the total size ( strip ped), the executable is dynamically linked with the full ( strip ped ) shared library objects and libstdc++ .

    If you find that the size difference is significant, but do not want to statically link everything, you try to reduce the size of libstdc++ by rebuilding it without some parts that you know you don’t need (there are settings, time parameters for some of its parts, and You can also try to remove some independent objects during the final creation of libstdc++.so . There are some tools for optimizing the size of libraries - search the Internet (I remember one of the companies named MontaVista , but don’t see it on my website now, there are others).

Besides the simple above, some ideas and suggestions to think about:

You mentioned that you are using uClibc , which I never played with myself (my experience with embedded programming is much more primitive, this mainly concerns assembly programming for the embedded processor and cross-compilation with minimal built-in libraries). I assume that you have checked this, and I know that uClibc designed for a simple but fairly complete standard C library, but remember that C ++ code is hardly independent of the C library, while g++ and libstdc++ depend on rather delicate things (I remember problems with libc on some proprietary versions of Unix), so I wouldn’t assume that g++ or GNU libstdc++ works with uClibc without trying - I don’t remember seeing this on uClibc pages.

In addition, if it is an embedded system, think about its performance, processing power, total, and time / simplicity / reliability requirements. Consider the complexity and consider whether using C ++ and threads is appropriate in your embedded system, and if nothing in the system uses them, is it worth using for this library. It may be without knowing the library or system that I cannot say (again, embedded systems currently have such wide ranges).

And in this case also, just a quick link, I came across a search for uClibc - if you are working on an embedded system using uClibc and want to use C ++ code on it - look at uClibc++ . I don’t know how many of the standard C ++ materials you need, and it already supports, and it seems to be a permanent project, so it’s not clear if it’s sufficient in a condition sufficient for you, but assuming your work is nonetheless , this could be a good alternative to GCC libstdc++ for your inline work.

+1
source

I think this guy explains why this doesn't make sense. C ++ is code that uses your shared object, but another libstdC ++ will link in order, but will not work.

0
source

All Articles