可以使用显式插入来覆盖直接绑定。请参见定义显式插入。不过,可能会存在您无法控制显式插入的建立的情况。
例如,您可能交付了您希望使用直接绑定的一系列共享目标文件。用户知道要在该系列的共享目标文件提供的符号上进行插入。如果这些用户没有显式定义他们的插入要求,则重新交付使用直接绑定的共享目标文件可能会破坏它们的插入。
共享目标文件也可设计提供许多缺省接口,并期望用户提供自己的插入例程。
为防止破坏现有的应用程序,可以交付显式阻止直接绑定到一个或多个应用程序接口的共享目标文件。
可以使用下列选项之一阻止直接绑定到动态目标文件。
使用 -B nodirect 选项。此选项阻止直接绑定到由要生成的目标文件提供的任何接口。
使用 NODIRECT mapfile 关键字。使用此关键字可阻止直接绑定到各个符号。SYMBOL_SCOPE / SYMBOL_VERSION 指令中描述了此关键字。
不能从外部目标文件直接绑定到标签为 nodirect 的接口。此外,也不能从同一目标文件内直接绑定到标签为 nodirect 的接口。
以下几节介绍了每种直接绑定阻止机制的使用方法。
-B nodirect 选项提供了最简单的机制,它阻止从任何动态目标文件进行直接绑定。此选项阻止从任何其他目标文件进行直接绑定,并阻止从要生成的目标文件内进行直接绑定。
以下组件用于生成三个共享目标文件:A.so.1、O.so.1 和 X.so.1。-B nodirect 选项用于阻止 A.so.1 直接绑定到 O.so.1。不过,O.so.1 可以使用 -z direct 选项继续建立到 X.so.1 的直接绑定。
$ 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
可以使用 elfdump(1) 来查看 A.so.1 和 O.so.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
字母 "N" 表示不允许直接绑定到函数 o() 和 p()。尽管 A.so.1 已使用 -B direct 选项来请求直接绑定,但是没有建立到函数 o() 和 p() 的直接绑定。O.so.1 仍然可以使用 -z direct 选项来请求到其依赖项 X.so.1 的直接绑定。
Oracle Solaris 库 libproc.so.1 是使用 -B nodirect 选项生成的。该库的用户应该为许多 libproc 函数提供他们自己的回调接口。从 libproc 的任何依赖项对 libproc 函数的引用都应当绑定到任何用户定义(如果存在这样的定义)。
NODIRECT mapfile 关键字提供了一种阻止直接绑定到各个符号的方法。在阻止直接绑定方面,该关键字提供了比 -B nodirect 选项更细粒度的控制。
从之前示例使用的组件中,可以将 O.so.2 生成为阻止直接绑定到函数 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
可以使用 elfdump(1) 来查看 A.so.2 和 O.so.2 的符号信息。
$ 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 只声明了不能直接绑定到函数 o()。因此,A.so.2 能够直接绑定到 O.so.1 中的函数 p()。
Oracle Solaris 库内的各个接口已被定义为不允许直接绑定。其中之一是数据项 errno。该数据项是在 libc.so.1 中定义的。可以通过包含头文件 stdio.h 来引用该数据项。但是,通常会指示许多应用程序定义其自己的 errno。如果交付了直接绑定到 libc.so.1 中定义的 errno 的一系列系统库,则这些应用程序会被损害。
已定义为阻止绑定到的另一个接口系列是 malloc(3C) 系列。malloc() 系列是用户应用程序内经常会实现的另一组接口。这些用户实现的目的是在任何系统定义上进行插入。
注 - 随 Oracle Solaris OS 提供了各种系统插入库,这些库提供了替代的 malloc() 实现。此外,每个实现都期望成为在一个进程内使用的唯一实现。所有 malloc() 插入库都是使用 -z interpose 选项生成的。该选项实际上不是必需的,因为 libc.so.1 内的 malloc() 系列已标记为阻止任何直接绑定。
不过,仍然使用了 -z interpose 选项生成这些插入库是为了给插入项的生成设定一个惯例。该显式插入与在 libc.so.1 中建立的直接绑定阻止定义之间没有任何不利的相互影响。
不能直接绑定到指定了 STV_SINGLETON 可见性的符号。请参见表 7-20。编译系统可将这些符号指定给一个实现,该实现可能会在进程内的多个目标文件中多次实例化。所有的单件符号引用都绑定到进程中第一次出现的单件符号。