Generating Standard Filters
To generate a standard filter, you first define a
filtee on which the filtering is applied.
The following example builds a filtee
filtee.so.1
, suppling the symbols
foo
and bar
.
$ cat filtee.c char *bar = "defined in filtee"; char *foo() { return("defined in filtee"); } $ cc -o filtee.so.1 -G -K pic filtee.c
Standard filters can be defined at the object level, or for individual
symbols. To declare all of the interfaces offered by a shared object
to be filters, use the link-editor's mapfile
FILTER
directive, or -F
command
line option. To declare individual interfaces of a shared object to
be filters, use a link-editor mapfile
and the
FILTER
symbol attribute.
In the following example, the shared object
filter.so.1
is defined to be a filter.
filter.so.1
offers the symbols
foo
and bar
, and is a
filter on the filtee
filtee.so.1
. In this example, the environment
variable LD_OPTIONS
is used to circumvent the
compiler driver from interpreting the -F
option.
$ cat filter.c #include <stdio.h> char *bar = NULL; char *foo() { return (NULL); } $ LD_OPTIONS='-F filtee.so.1' \ cc -o filter.so.1 -G -K pic -h filter.so.1 -R. filter.c $ elfdump -d filter.so.1 | egrep "SONAME|FILTER" [2] SONAME 0xee filter.so.1 [3] FILTER 0xfb filtee.so.1
A mapfile
can be used instead of the
-F
command line option.
$ cat mapfile $mapfile_version 2 FILTER { FILTEE = filtee.so.1; TYPE = STANDARD; }; $ cc -o filter.so.1 -G -K pic -h filter.so.1 -M mapfile -R. filter.c $ elfdump -d filter.so.1 | egrep "SONAME|FILTER" [2] SONAME 0xee filter.so.1 [3] FILTER 0xfb filtee.so.1
The link-editor can reference the standard filter
filter.so.1
as a dependency when
creating a dynamic object. The link-editor uses
information from the symbol table of the filter to satisfy any
symbol resolution. However, at runtime, any reference to the symbols
of the filter result in the additional loading of the
filtee
filtee.so.1
. The runtime linker uses the
filtee to resolve any symbols defined by
filter.so.1
. If the
filtee is not found, or a filter symbol is
not found in the filtee, the filter is skipped for
this symbol lookup.
For example, the following dynamic executable
prog
, references the symbols
foo
and bar
, which are
resolved during link-edit from the filter
filter.so.1
. The execution of
prog
results in foo
and bar
being obtained from the
filtee
filtee.so.1
, not from the
filter filter.so.1
.
$ cat main.c extern char *bar, *foo(); void main() { (void) printf("foo is %s: bar is %s\n", foo(), bar); } $ cc -o prog main.c -R. filter.so.1 $ prog foo is defined in filtee: bar is defined in filtee
In the following example, the shared object
filter.so.2
defines one of its
interfaces, foo
, to be a filter on the
filtee
filtee.so.1
.
Note:
As no source code is supplied forfoo
(), the
mapfile
FUNCTION
symbol attribute is used to
ensure a symbol table entry for foo
is
created.
$ cat filter.c char *bar = "defined in filter"; $ cat mapfile $mapfile_version 2 SYMBOL_SCOPE { global: foo { TYPE=FUNCTION; FILTER=filtee.so.1 }; }; $ cc -o filter.so.2 -G -K pic -h filter.so.2 -M mapfile -R. filter.c $ elfdump -d filter.so.2 | egrep "SONAME|FILTER" [2] SONAME 0xd8 filter.so.2 [3] SUNW_FILTER 0xfb filtee.so.1 $ elfdump -y filter.so.2 | egrep "foo|bar" [1] [ FILTER ] [3] filtee.so.1 foo [10] [ DEPEND ] <self> bar
At runtime, any reference to the symbol foo
of the
filter, results in the additional loading of the
filtee
filtee.so.1
. The runtime linker uses the
filtee to resolve only the symbol
foo
defined by
filter.so.2
. Reference to the symbol
bar
always uses the symbol from
filter.so.2
, as no
filtee processing is defined for this
symbol.
For example, the following dynamic executable
prog
, references the symbols
foo
and bar
, which are
resolved during link-edit from the filter
filter.so.2
. The execution of
prog
results in foo
being obtained from the filtee
filtee.so.1
, and bar
being
obtained from the filter filter.so.2
.
$ cc -o prog main.c -R. filter.so.2 $ prog foo is defined in filtee: bar is defined in filter
In these examples, the filtee
filtee.so.1
is uniquely associated to the
filter. The filtee is not available to satisfy
symbol lookup from any other objects that might be loaded as a
consequence of executing prog
.
Standard filters provide a convenient mechanism for defining a subset interface of an existing shared object. Standard filters provide for the creation of an interface group spanning a number of existing shared objects. Standard filters also provide a means of redirecting an interface to its implementation. Several standard filters are used in the Oracle Solaris OS.
The /lib/libxnet.so.1
filter uses multiple
filtees. This library provides socket and
XTI interfaces from
/lib/libsocket.so.1
,
/lib/libnsl.so.1
, and
/lib/libc.so.1
.
libc.so.1
defines interface filters to the
runtime linker. These interfaces provide an abstraction between the
symbols referenced in a compilation environment from
libc.so.1
, and the actual
implementation binding produced within the runtime environment to
ld.so.1
(1).
libnsl.so.1
defines the standard filter
gethostname
(3C) against
libc.so.1
. Historically, both
libnsl.so.1
and
libc.so.1
have provided the same
implementation for this symbol. By establishing
libnsl.so.1
as a filter, only one
implementation of gethostname
() need exist. As
libnsl.so.1
continues to export
gethostname
(), the interface of this
library continues to remain compatible with previous
releases.
Because the code in a standard filter is never referenced at runtime,
adding content to any functions defined as filters is redundant. Any
filter code might require relocation, which would result in an
unnecessary overhead when processing the filter at runtime.
Functions are best defined as empty routines, or directly from a
mapfile
. See SYMBOL_SCOPE and SYMBOL_VERSION Directives.
When generating data symbols within a filter, always associate the
data with a section. This association can be produced by defining
the symbol within a relocatable object file. This association can
also be produced by defining the symbol within a
mapfile
together with a
size
declaration and
no
value
declaration. See SYMBOL_SCOPE and SYMBOL_VERSION Directives. The resulting data definition ensures
that references from a dynamic executable are established
correctly.
Some of the more complex symbol resolutions carried out by the link-editor require knowledge of a symbol's attributes, including the symbol's size. Therefore, you should generate the symbols in the filter so that their attributes match the attributes of the symbols in the filtee. Maintaining attribute consistency ensures that the link-editing process analyzes the filter in a manner that is compatible with the symbol definitions used at runtime. See Symbol Resolution.
Note:
The link-editor uses the ELF class of the first relocatable file that is processed to govern the class of object that is created. Use the link-editor's-64
option to create a
64-bit filter solely from a
mapfile
.