1

I'm writing an application fooapp which can use one of several other, existing libraries for some part of its functionality. For the sake of discussion, let's say that its saving the program output. There are formats fa, fb and fc, and suppose there are libraries libfa, libfb and libfc (let's ignore library versions in this question).

Now, if I just compile fooapp with support for all 3 formats, I'll get a library which depends on symbols from libfa, libfb and libfc, expected to be found in three shared libraries. And if the machine on which I deploy does not have all of them, the loader will fail and the app won't run.

Now, I want the same build of my app to also run on machines without libfa, libfb and/or libfc; and when any of three are available, I do want to offer the use of all of them.

I realize I can not-depend on them, then manually search the filesystem for .so's, perform dlopen and dlsym. But - I feel like I would be reinventing the wheel. Is there some better-structured, standardized, idiomatic way to do this?

Notes: For the sake of discussion, and if it helps, suppose my program and the libraries is written in C. (If it doesn't forget about this note.)

1 Answer 1

1

There is no alternative to dlopen et. al. if the shared library of interest, say libfoo.so, is not nominated by a DT_NEEDED entry in the dynamic section of the client program or client shared library, and if it is so nominated then the dynamic linker will unconditionally give a load time error if it cannot find libfoo.so per its search algorithm.

ELF static and dynamic linkers offer you a binary choice between nominating libfoo.so as needed by a client through the options you pass to the static linker for the client (normally and principally -lfoo), or not doing so and making it the client's responsibility to discover libfoo.so, or fail to, using dlopen.

However, this does not oblige the client to "manually search the filesystem for .so's" on which to call dlopen. If the client makes a call of the form:

 dlopen("libfoo.so", <flags>);
 

omitting any absolute or relative path qualification from the library name, then the dynamic linker will search for libfoo.so algorithmically as per man dlopen: it will be found in the same way as if is was needed, if it can be found that way, and otherwise dlopen will return a null handle.


You commented:

But isn't there a way to have this done automatically for me? So that, for example, the first call to a library function using libfa will do the dlopen(), dlsym(), and some magic program self-modification so that next calls will just get the loaded code?

Where is the dynamic linker - carrying out the automatic dlopen, dlsym - to get the information that an undefined external reference in the client might be resolved to a definition in libfa.so, so as to automatically open that library to see if that is so, rather than any other one?

In the ELF file format, that information only comes from a DT_NEEDED entry naming libfa.so in the dynamic section of the client image, and such an entry comes from being written there by the static linker because it has been given -lfa (or an equivalent argument) requesting dynamic linkage of libfa.so.

In the presence of such an entry, what you get already is the automatic finding and opening of libfa.so by the dynamic linker at runtime and automatic patching of the client's undefined references to the definitions matched in libfa.so, by modification of the program in memory, so that calls are thereafter routed to the loaded library's definitions. The static linker options -z now v. -z lazy give you a choice as to whether the patching of the client's dynamic function references will occur as soon as the shared library is loaded (-z now) or be deferred to the time, if any, when such a function is first called (-z lazy, which is the default).

The absence of a DT_NEEDED entry disables this magic not just by convention but because in the absence of such an entry the dynamic linker is ignorant that there is such a library as libfa.so that you permit to be dynamically linked with this client. So if the client wants to make references to definitions in libfa.so without benefit of automation then it must programmatically ask the dynamic linker to find and load libfa.so and use it to define those external dynamic references that the client wants.

If you wanted libfa.so to be automatically found and loaded in the absence of a DT_NEEDED entry for that library in the client then you would require a new kind of dynamic linker (one that would also obselete existing static linkers) that does not confine its automatic directory search for shared libraries to a set prescribed as needed by the client, but instead potentially considers every shared library on the system within reach of its directory search protocol, linking the first library that defines any undefined reference. Nothing stops us technically from having such a dynamic linker but we don't because it would be unserviceably inefficient at getting programs running and we would forfeit our control of the namespace of defined symbols within which a program is dynamically linked.

Sign up to request clarification or add additional context in comments.

2 Comments

But isn't there a way to have this done automatically for me? So that, for example, the first call to a library function using libfa will do the dlopen(), dlsym(), and some magic program self-modification so that next calls will just get the loaded code?
@einpoklum I continued the answer in response to that question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.