With Solaris 10 you can no longer build a static executable.
It's not that ld(1) doesn't allow static linking, or using
archives, it's just that libc.a, the archive
version of libc.so.1, is no longer provided.
This library provides the interfaces between user land and the
kernel, and without this library it is rather hard to create
any form of application.
We've been warning users against static linking for some time
now, and linking against libc.a has been especially
problematic. Every solaris release, or update (even
some patches) has resulted in some application that was built
against libc.a, failing. The problem is
that libc is supposed to isolate an application from the
user/kernel boundary, a boundary which can undergo changes
from release to release.
If an application is built against libc.a, then
any kernel interface it references is extracted from the
archive and becomes a part of the application. Thus, this
application can only run on a kernel that is in-sync with
the kernel interfaces used. Should these interfaces change,
the application is treading on shaky ground.
In addition, implementation details of libc,
such as localization and the name service switch, require
dynamic linking (they dlopen() other
objects). As we antispated libc.a to be used
in a static environment, any dynamic capabilities were
#ifdef'ed out of the code. libc.a
has always been a subset of libc.so.1.
One common failing we have discovered is that many folks built against
libc.a but otherwise used dynamic objects to
supply other interfaces. These applications, termed
partially static, are particularly fragile. The dynamic
objects these partially static applications invoke, commonly
depend on interfaces contained in libc.so.1. However,
at runtime these dynamic objects are bound to the portions of
libc that have been statically linked with the executable,
leaving any other references to be bound to the dynamic
libc.so.1. This combination of inconsistent
interfaces can lead to chaos and ruin.
Because of this potential for distroying any application
binary interface guarantee, the 64-bit version of Solaris
never delivered any 64-bit system archives libraries. We figured
we nip that problem in the bud right away.
But why did we wait until Solaris 10 to stop delivering
32-bit system archives? It turns out the merge of libc
and libthread put the last nail in the coffin.
In earlier releases of Solaris, threaded applications needed
to build against libthread. This library offered
the true thread interfaces that allow you to create and manage
threads. However, to allow library developers to create
libraries that were thread aware (ie. that could be used in a
threading environment and a non-threading environment),
libc also provided all the thread interfaces.
These interfaces were basically no-op stubs. The gyrations
we had to go through to make these two libraries cooperate
was a story in itself.
Now, if you built an application against libc.a
and happened to reference the thread interfaces, you
ended up with the no-op stubs becoming part of the
application. This turned out to be a major problem when
the application moved to another release and became
bound to new dynamic objects.
In Solaris 10, libthread and libc
have been merged. Effectively all applications are
thread capable, but until any new threads are created,
the application remains single threaded.
This model simplifies application and especially library development
because there are no longer three process models to contend with
(threaded, non-threaded, and statically linked). There is now
only one model, one that is thread-capable.
Libraries can be assured they always operate in a thread-capable
application environment. These libraries can take advantage of
threading interfaces and features like thread-local storage that
cannot be provided in a non-thread-capable environment.
The merger of libthread and libc
makes any partially static application doomed to failure,
even if a stripped-down, crippled archive version of
libc.a were made available.
Therefore, to put to rest the consistent failure of
partially static applications from release to release,
we've now made it impossible to make such applications.
Some folks thought of static applications as being
a means of insulating themselves from system changes.
But as I explained above, they were not insulating
themselves from user/kernel interface changes.
Note that there is some flexibility even in a dynamic
linking environment. Although applications are built
to encode the interpretor /usr/lib/ld.so.1,
applications can be built to specify an alternative
% cp /usr/lib/ld.so.1 /local/safe/lib
% cp /usr/lib/libc.so.1 /local/safe/lib
% LD_OPTIONS=-I/local/safe/lib/ld.so.1 \\
cc -o main main.c -R/local/safe/lib ...
Or, you can invoke an alternative interpretor directly:
% /local/safe/lib/ld.so.1 main ...
But, even if you create an environment with an alternate
runtime linker and dynamic libc, it must be
in-sync with the kernel on which it will execute.
Otherwise, this technique is no more robust than using
an archive version of libc.a.
See also this explanation.