What Does -Fpic Mean When Building a Shared Library

Difference between static and shared libraries?

Shared libraries are .so (or in Windows .dll, or in OS X .dylib) files. All the code relating to the library is in this file, and it is referenced by programs using it at run-time. A program using a shared library only makes reference to the code that it uses in the shared library.

Static libraries are .a (or in Windows .lib) files. All the code relating to the library is in this file, and it is directly linked into the program at compile time. A program using a static library takes copies of the code that it uses from the static library and makes it part of the program. [Windows also has .lib files which are used to reference .dll files, but they act the same way as the first one].

There are advantages and disadvantages in each method:

  • Shared libraries reduce the amount of code that is duplicated in each program that makes use of the library, keeping the binaries small. It also allows you to replace the shared object with one that is functionally equivalent, but may have added performance benefits without needing to recompile the program that makes use of it. Shared libraries will, however have a small additional cost for the execution of the functions as well as a run-time loading cost as all the symbols in the library need to be connected to the things they use. Additionally, shared libraries can be loaded into an application at run-time, which is the general mechanism for implementing binary plug-in systems.

  • Static libraries increase the overall size of the binary, but it means that you don't need to carry along a copy of the library that is being used. As the code is connected at compile time there are not any additional run-time loading costs. The code is simply there.

Personally, I prefer shared libraries, but use static libraries when needing to ensure that the binary does not have many external dependencies that may be difficult to meet, such as specific versions of the C++ standard library or specific versions of the Boost C++ library.

On linking of shared libraries, are they really final, and if so, why?

Once you have a shared library libfoo.so the only ways you can use it
in the linkage of anything else are:-

Link a program that dynamically depends on it, e.g.

$ gcc -o prog bar.o ... -lfoo

Or, link another shared library that dynamically depends on it, e.g.

$ gcc -shared -o libbar.so bar.o ... -lfoo

In either case the product of the linkage, prog or libbar.so
acquires a dynamic dependency on libfoo.so. This means that prog|libfoo.so
has information inscribed in it by the linker that instructs the
OS loader, at runtime, to find libfoo.so, load it into the
address space of the current process and bind the program's references to libfoo's exported symbols to
the addresses of their definitions.

So libfoo.so must continue to exist as well as prog|libbar.so.
It is not possible to link libfoo.so with prog|libbar.so in
such a way that libfoo.so is physically merged into prog|libbar.so
and is no longer a runtime dependency.

It doesn't matter whether or not you have the source code of the
other linkage input files - bar.o ... - that depend on libfoo.so. The
only kind of linkage you can do with a shared library is dynamic linkage.

This is in complete contrast with the linkage of a static library

You wonder about the statement in this this answer where it says:

If you have access to either source or object files for both libraries, it is straightforward to compile/link a combined SO from them.

The author is just observing that if I have source files

foo_a.c foo_b.c... bar_a.c bar_b.c

which I compile to the corresponding object files:

foo_a.o foo_b.o... bar_a.o bar_b.o...

or if I simply have those object files. Then as well as - or instead of - linking them into two shared libraries:

$ gcc -shared -o libfoo.so foo_a.o foo_b.o...
$ gcc -shared -o libbar.so bar_a.o bar_b.o...

I could link them into one:

$ gcc -shared -o libfoobar.so foo_a.o foo_b.o... bar_a.o bar_b.o...

which would have no dependency on libfoo.so or libbar.so even if they exist.

And although that could be straightforward it could also be false. If there is
any symbol name that is globally defined in any of foo_a.o foo_b.o... and
also globally defined in any of bar_a.o bar_b.o... then it will not matter
to the linkage of either libfoo.so or libbar.so (and it need not be dynamically
exported by either of them). But the linkage of libfoobar.so will fail for
multiple definition of name.

If we build a shared library libbar.so that depends on libfoo.so and has
itself been linked with libfoo.so:

$ gcc -shared -o libbar.so bar.o ... -lfoo

and we then want to link a program with libbar.so, we can do that in such a way
that we don't need to mention its dependency libfoo.so:

$ gcc -o prog main.o ... -lbar -Wl,-rpath=<path/to/libfoo.so>

See this answer to follow that up. But
this doesn't change the fact that libbar.so has a runtime dependency on libfoo.so.

If that's not possible, what is technically preventing it?

What technically prevents linking a shared library with some program
or shared library targ in a way that physically merges it into targ is that a
shared library (like a program) is not the sort of thing that a linker knows
how to physically merge into its output file.

Input files that the linker can physically merge into targ need to
have structural properties that guide the linker in doing that merging. That is the structure of object files.
They consist of named input sections of object code or data that are tagged with various attributes.
Roughly speaking, the linker cuts up the object files into their sections and distributes them into
output sections of the output file according to their attributes, and makes
binary modifications to the merged result to resolve static symbol references
or enable the OS loader to resolve dynamic ones at runtime.

This is not a reversible process. The linker can't consume a program or
shared library and reconstruct the object files from which it was made to
merge them again into something else.

But that's really beside the point. When input files are physically
merged into targ, that is called static linkage.
When input files are just externally referenced in targ to
make the OS loader map them into a process it has launched for targ,
that is called dynamic linkage. Technical development has given us
a file-format solution to each of these needs: object files for static linkage, shared libraries
for dynamic linkage. Neither can be used for the purpose of the other.

Building Shared Library from static Library *.a file

It's totally correct but you seem to be confused about concepts. Your static library is not included in your shared library as you seem to expect. Your static library is just linked to the shared library. In the end, your program needs an .so file and an .a to function properly, not just one big .so that holds everything.

static and shared library and their cross linking

when I have an executable that links to a static lib, the executable copies full contents of the functions/resources it needs into itself, so when it runs, it no longer needs the static lib

Correct.

If the executable links to a shared lib, then it only create place holder for all the contents it needs, so when it runs, it needs the shared lib in the path

It needs access to the shared library, certainly. The rules by which the shared library is found varies by platform.

when I build a static library A that links to a shared lib B, and then build an executable C that links to A for functions that are originally from B. As a result, when I run C, I don't A to be presented because all needed contents are already in C, but B is still needed.

Correct

when I build a shared library A that links to a static lib B, and then build an executable C that links to A for functions that are originally from B. As a result, when I run C, I only need A but not B as all the contents needed is already in A

Correct

Essentially, when you link against a static library, you never need it at runtime, and when you link against a shared library, you do.

Share single copy of structure/data defined in shared library to different objects defined in multiple shared libraries

class __attribute__ ((visibility ("default")) SharedObject

Defining the class as above solved the issue. It seems like without this, symbol is not exported and not available for dynamic linker.

Why string shown up in Shared Library file like .so file in Linux?

-fvisibility=hidden only affects the linker visibility, i.e. whether symbols are visible when a linker tries to link against your file. It does not specify any active obfuscation.

Your strings are still placed inside a data section and need to be loaded into the memory space of the process when your library is loaded, so they will still need to be visible when inspecting the file. If you need them to be obfuscated, you will need to obfuscate them yourself and decode them at runtime (knowing that a sufficiently determined attacker can still reverse engineer or debug your library).



Related Topics



Leave a reply



Submit