Oracle® Solaris 11.2 链接程序和库指南

退出打印视图

更新时间: 2014 年 7 月
 
 

观察符号绑定

为了解缺省的符号搜索模型并将其与直接绑定进行比较,我们使用以下组件来生成一个进程。

$ cat main.c
extern int W(), X();

int main() { return (W() + X()); }
$ cat W.c
extern int b();

int a() { return (1); }
int W() { return (a() - b()); }
$ cat w.c
int b() { return (2); }
$ cat X.c
extern int b();

int a() { return (3); }
int X() { return (a() - b()); }
$ cat x.c
int b() { return (4); }
$ cc -o w.so.1 -G -Kpic w.c
$ cc -o W.so.1 -G -Kpic W.c -R. w.so.1
$ cc -o x.so.1 -G -Kpic x.c
$ cc -o X.so.1 -G -Kpic X.c -R. x.so.1
$ cc -o prog1 -R. main.c W.so.1 X.so.1

应用程序的组件按以下顺序装入。

$ ldd prog1
        W.so.1 =>        ./W.so.1
        X.so.1 =>        ./X.so.1
        w.so.1 =>        ./w.so.1
        x.so.1 =>        ./x.so.1

W.so.1X.so.1 文件都定义了一个名为 a() 的函数。w.so.1x.so.1 文件都定义了一个名为 b() 的函数。此外,W.so.1X.so.1 文件都引用了函数 a()b()

通过设置 LD_DEBUG 环境变量,可以观察使用缺省搜索模型及最终绑定的运行时符号搜索。从运行时链接程序诊断信息中,可以发现到函数 a()b() 的绑定。

$ LD_DEBUG=symbols,bindings prog1
....
17375: symbol=a;  lookup in file=prog1  [ ELF ]
17375: symbol=a;  lookup in file=./W.so.1  [ ELF ]
17375: binding file=./W.so.1 to file=./W.so.1: symbol 'a'
....
17375: symbol=b;  lookup in file=prog1  [ ELF ]
17375: symbol=b;  lookup in file=./W.so.1  [ ELF ]
17375: symbol=b;  lookup in file=./X.so.1  [ ELF ]
17375: symbol=b;  lookup in file=./w.so.1  [ ELF ]
17375: binding file=./W.so.1 to file=./w.so.1: symbol 'b'
....
17375: symbol=a;  lookup in file=prog1  [ ELF ]
17375: symbol=a;  lookup in file=./W.so.1  [ ELF ]
17375: binding file=./X.so.1 to file=./W.so.1: symbol 'a'
....
17375: symbol=b;  lookup in file=prog1  [ ELF ]
17375: symbol=b;  lookup in file=./W.so.1  [ ELF ]
17375: symbol=b;  lookup in file=./X.so.1  [ ELF ]
17375: symbol=b;  lookup in file=./w.so.1  [ ELF ]
17375: binding file=./X.so.1 to file=./w.so.1: symbol 'b'

对函数 a()b() 其中之一的每个引用都会导致从应用程序 prog1 开始搜索关联的符号。对 a() 的每个引用都绑定到在 W.so.1 中发现的符号的第一个实例。对 b() 的每个引用都绑定到在 w.so.1 中发现的符号的第一个实例。此示例揭示了 W.so.1w.so.1 中的函数定义如何插入到 X.so.1x.so.1 中的函数定义。使用直接绑定时会发生插入,这是使用直接绑定时需要考虑的一个重要因素。下面的几节中详细介绍了插入。

此示例很简洁,很容易遵循关联的诊断信息。然而,大多数应用程序是基于许多动态组件构造的,要复杂得多。这些组件是从不同的源根基生成的,通常异步提交。

对来自复杂进程的诊断信息进行分析可能比较有难度。分析动态目标文件的接口需求的另一种方法是使用 lari(1) 实用程序。lari 分析进程的绑定信息以及每个目标文件提供的接口定义。该信息使得 lari 能够简明地转换关于进程符号依赖项的受关注信息。在分析伴随着直接绑定发生的插入时,该信息非常有用。

缺省情况下,lari 将转换它认为受关注的信息。该信息源自一个符号定义的多个实例。lariprog1 显示以下信息。

$ lari prog1
[2:2ES]: a(): ./W.so.1
[2:0]: a(): ./X.so.1
[2:2E]: b(): ./w.so.1
[2:0]: b(): ./x.so.1

在此示例中,从 prog1 建立的进程包含两个多次定义的符号:a()b()。输出诊断信息中的初始元素(括在方括号中的那些元素)描述了关联的符号。

第一个十进制值表示关联符号的实例数。a()b() 都存在两个实例。第二个十进制值表示已解析为此符号的绑定数。来自 W.so.1 的符号定义 a() 揭示已建立了到此依赖项的两个绑定。同样,来自 w.so.1 的符号定义 b() 揭示已建立了到此依赖项的两个绑定。绑定数之后的字母用于限定绑定。字母 "E" 表示已从外部 (external) 目标文件建立了绑定。字母 "S" 表示已从同一 (same) 目标文件建立了绑定。

在接下来的几节中,将使用 LD_DEBUGlari 以及从这些组件生成的进程示例来进一步研究直接绑定情况。