Linker and Libraries Guide

Preventing a Symbol from being Directly Bound to

Direct bindings can be overridden with explicit interposition. See Defining Explicit Interposition. However, cases can exist where you do not have control over establishing explicit interposition.

For example, you might deliver a family of shared objects that you would like to use direct bindings. Customers are known to be interposing on symbols that are provided by shared objects of this family. If these customers have not explicitly defined their interpositioning requirements, their interpositioning can be compromised by a re-delivery of shared objects that employ direct bindings.

Shared objects can also be designed that provide a number of default interfaces, with an expectation that users provide their own interposing routines.

To prevent disrupting existing applications, shared objects can be delivered that explicitly prevent directly binding to one or more of their interfaces.

Directly binding to a dynamic object can be prevented using one of the following options.

An interface that is labelled as nodirect, can not be directly bound to from an external object. In addition, an interface that is labelled as nodirect, can not be directly bound to from within the same object.

The following sections describe the use of each of the direct binding prevention mechanisms.

Using the -B nodirect Option

The -B nodirect option provides the simplest mechanism of preventing direct binding from any dynamic object. This option prevents direct binding from any other object, and from within the object being built.

The following components are used to build three shared objects, A.so.1, O.so.1 and X.so.1. The -B nodirect option is used to prevent A.so.1 from directly binding to O.so.1. However, O.so.1 can continue to establish direct bindings to X.so.1 using the -z direct option.


$ cat a.c
extern int o(), p(), x(), y();

int a() { return (o() + p() - x() - y()); }

$ cat o.c
extern int x(), y();

int o() { return (x()); }
int p() { return (y()); }

$ cat x.c
int x() { return (1); }
int y() { return (2); }

$ cc -o X.so.1 -G -Kpic x.c
$ cc -o O.so.1 -G -Kpic o.c -Bnodirect -zdirect -R. X.so.1
$ cc -o A.so.1 -G -Kpic a.c -Bdirect -R. O.so.1 X.so.1

The symbol information for A.so.1 and O.so.1 can be viewed with elfdump(1).


$ elfdump -y A.so.1
    [1]  DBL     [3] X.so.1            x
    [5]  DBL     [3] X.so.1            y
    [6]  DL      [1] O.so.1            o
    [9]  DL      [1] O.so.1            p
$ elfdump -y O.so.1
    [3]  DB      [0] X.so.1            x
    [4]  DB      [0] X.so.1            y
    [6]  N                             o
    [7]  N                             p

The letter “N” indicates that no direct bindings be allowed to the functions o() and p(). Even though A.so.1 has requested direct bindings by using the -B direct option, direct bindings have not be established to the functions o() and p(). O.so.1 can still request direct bindings to its dependency X.so.1 using the -z direct option.

The Oracle Solaris library libproc.so.1 is built with the -B nodirect option. Users of this library are expected to provide their own call back interfaces for many of the libproc functions. References to the libproc functions from any dependencies of libproc should bind to any user definitions when such definitions exist.

Using the NODIRECT mapfile Keyword

The NODIRECT mapfile keyword provides a means of preventing a direct binding to individual symbols. This keyword allows for more fine grained control over preventing direct binding than the -B nodirect option.

From the components used in the previous example, O.so.2 can be built to prevent direct binding to the function o().


$ cat mapfile
$mapfile_version 2
SYMBOL_SCOPE {
        global:
                o       { FLAGS = NODIRECT };
};
$ cc -o O.so.2 -G -Kpic o.c -Mmapfile -zdirect -R. X.so.1
$ cc -o A.so.2 -G -Kpic a.c -Bdirect -R. O.so.2 X.so.1

The symbol information for A.so.2 and O.so.2 can be viewed with elfdump(1).


$ elfdump -y A.so.2
    [1]  DBL     [3] X.so.1            x
    [5]  DBL     [3] X.so.1            y
    [6]  DL      [1] O.so.1            o
    [9]  DBL     [1] O.so.1            p
$ elfdump -y O.so.1
    [3]  DB      [0] X.so.1            x
    [4]  DB      [0] X.so.1            y
    [6]  N                             o
    [7]  D           <self>            p

O.so.1 only declares that the function o() can not be directly bound to. Therefore, A.so.2 is able to directly bind to the function p() in O.so.1.

Several individual interfaces within the Oracle Solaris libraries have been defined to not allow direct binding. One example is the data item errno. This data item is defined in libc.so.1. This data item can be referenced by including the header file stdio.h. However, many applications were commonly taught to defined their own errno. These applications would be compromised if a family of system libraries were delivered which directly bound to the errno that is defined in libc.so.1.

Another family of interfaces that have been defined to prevent direct binding to, are the malloc(3C) family. The malloc() family are another set of interfaces that are frequently implemented within user applications. These user implementations are intended to interpose upon any system definitions.


Note –

Various system interposing libraries are provided with the Oracle Solaris OS that provide alternative malloc() implementations. In addition, each implementation expects to be the only implementation used within a process. All of the malloc() interposing libraries have been built with the -z interpose option. This option is not really necessary as the malloc() family within libc.so.1 have been labelled to prevent any direct binding

However, the interposing libraries have been built with -z interpose to set a precedent for building interposers. This explicit interposition has no adverse interaction with the direct binding prevention definitions established within libc.so.1.


Symbols that are assigned the STV_SINGLETON visibility can not be directly bound to. See Table 7–20. These symbols can be assigned by the compilation system to an implementation that might become multiply instantiated in a number of objects within a process. All references to a singleton symbol are bound to the first occurrence of a singleton symbol within a process.