Generating Weak Filters
Standard filters provide a simple and effective solution to the problem of maintaining runtime compatibility while allowing the underlying system to evolve. However, filters also impose ongoing overhead. Although such a filter provides no functionality, it must be loaded and processed by the system every time the program runs. It is generally recommended that programs discontinue linking against these filters, and leave them for the benefit of old code that hasn't yet been rebuilt.
Eliminating unnecessary filters when building an object is the best
solution when feasible. However, there are cases where this can be
difficult to achieve. In particular, many open source packages have
complicated configuration systems that are intended to work across a
span of operating system versions. On some versions, a library may
deliver necessary content, while on newer ones, they are mere
filters. Rather then grapple with these complexities, the
configuration simply links against everything. On Oracle Solaris,
this frequently happens with libraries such as
libpthread
.
Weak filters, in conjunction with the -z
discard-unused=dependencies
command line option,
offer an automated solution to this problem. Typically, the
link-editor resolves external symbols from libraries by taking the
symbol from the first library on the command line that provides a
symbol definition. In the case of weak filters, such symbols are
ignored if the filtee providing the same filter is
also present on the command line. Resolving such symbols directly to
the filtee allows unused dependency processing to
eliminate the filter. This results in a simpler and more efficient
object, without requiring large changes to the upstream code
base.
The following example uses a filter object named
libprint
, which provides the standard
printf
() from libc
.
$ cat mapfile-libprint-std $mapfile_version 2 FILTER { FILTEE = "libc.so.1"; TYPE = STANDARD; }; SYMBOL_SCOPE { global: printf { TYPE = FUNCTION }; }; $ ld -o libprint.so.1 -G -h libprint.so.1 -Mmapfile-libprint-std $ elfdump libprint.so.1 | egrep 'SONAME|FILTER' [0] SONAME 0x1 libprint.so.1 [1] FILTER 0x4c libc.so.1
An application built against libprint
, requires
that this filter be loaded at runtime even though the
filtee
libc
contains the printf
()
function used at runtime.
$ cc hello.c -o hello -L. -R. libprint.so.1 $ elfdump -d hello | grep NEEDED [0] NEEDED 0x13b libprint.so.1 [1] NEEDED 0x125 libc.so.1 $ ./hello hello, world
The libprint
filter is rebuilt as a weak filter.
The hello world program links to libprint
as
before, but with unused dependency processing enabled. The resulting
program resolves printf
() directly from
libc
. The link-editor is therefore able
to discard the unused libprint
dependency.
$ cat mapfile-libprint-weak $mapfile_version 2 FILTER { FILTEE = "libc.so.1"; TYPE = WEAK; }; SYMBOL_SCOPE { global: printf { TYPE = FUNCTION }; }; $ ld -o libprint.so.1 -G -h libprint.so.1 -Mmapfile-libprint-weak $ elfdump libprint.so.1 | egrep 'SONAME|FILTER' [0] SONAME 0x1 libprint.so.1 [1] FILTER 0x4c libc.so.1 [14] FLAGS_1 0x20000000 [ WEAKFILTER ] $ cc hello.c -o hello -L. -R. libprint.so.1 -z discard-unused=dependencies $ elfdump -d hello | grep NEEDED [0] NEEDED 0x125 libc.so.1 $ ./hello hello, world
In current versions of Oracle Solaris, libraries such as
libpthread
are built as weak filters
instead of standard filters in order to enable the automatic removal
of unnecessary filter dependencies when unused dependency processing
is enabled with the -z
discard-unused=dependencies
option.
Note:
When the-z
discard-unused=dependencies
option is
enabled, and the symbol resolution process determines that a
weak filter symbol from a dependency is needed, the
filtee for that symbol is added to
the end of the link line as an additional dependency. This
allows the link-editor to find the symbol from the
filtee, and to eliminate the weak
filter. Therefore, the runpath for a weak
filter must be sufficient to allow the link-editor to find
the filtee.