I know that there are lots of questions about the use cases of shared vs static libraries, this question is not about that. I am asking about differences in file format stored on disk.
Why question is, what are the differences between the two? Or are they exactly the same, different only in terms of usage?
I am lead to believe that they are not the same, since running 'nm' on a shared library requires the -D flag. Clearly it needs to do something differently. Why?
Are they both ELF files?
Is the only difference that the shared library can contain some paths of dependencies?
A static library, e.g. libfoo.a
is not an executable of any kind.
It is simply an indexed archive in unix ar
format
of other files which happen to be ELF
object files.
A static library is created like any archive:
ar crs libfoo.a objfile0.o objfile1.0...objfileN.o
outputs the new archive (c
) libfoo.a, with those object files inserted (r
)
and index added (s
).
You'll hear of linking libfoo.a
in a program. This doesn't mean that
libfoo.a
itself is linked into or with the program. It means that libfoo.a
is passed to the linker as an archive from which it can extract and link into
the program just those object files within the archive that the program needs.
So the format of a static libary (ar
format) is just an object-file
bundling format for linker input: it could equally well have been some other bundling
format without any effect on the linker's mission, which is to digest a set of
object files and shared libraries and generate a program, or shared library,
from them. ar
format was history's choice.
On the other hand a shared library, e.g. libfoo.so
, is an ELF file
and not any sort of archive.
Don't be tempted to suspect that a static library is a sort of ELF file by
the fact that all the well-known ELF-parsers - objdump
, readelf
, nm
-
will parse a static libary. These tools all know that a static library is
an archive of ELF object files, so they just parse all the object files
in the library as if you had listed them on the commandline.
The use of the -D
option with nm
just instructs the tool to select
only the symbols that are in the dynamic symbol table(s), if any,
of the ELF file(s) that it parses - the symbols visible to the runtime linker
- regardless of whether or not they are parsed from within an archive. It's
the same as objdump -T
and readelf --dyn-syms
. It is not
necessary to use these options to parse the symbols from a shared library. If
you don't do so, then by default you'll just see the full symbol table.
If you run nm -D
on a static library you'll be told no symbols
, for
each object file in the archive - likewise if you ran nm -D
for each of
those object files individually. The reason for that is that an object file
hasn't got a dynamic symbol table: only a shared library or progam has one.
Object file, shared library and program are all variants of the ELF format. If you're interested in ELF variants, those are the variants of interest.
The ELF format itself is a long and thorny technical read and is required background for precisely distinguishing the variants. Intro: An ELF file contains a ELF header structure one of whose fields contains a type-identifier of the file as an object file, shared library, or program. When the file is a program or shared library, it also contains an optional Program header table structure whose fields provide the runtime linker/loader with the parameters it needs to load the file in a process. In terms of ELF structure, the differences between a program and a shared library are slight: it's the detailed content that makes the difference to the behaviour that they elicit from the loader.
For the long and thorny technical read, try Excutable and Linkable Format (ELF)