JavaScript is required to for searching.
跳过导航链接
退出打印视图
链接程序和库指南     Oracle Solaris 10 1/13 Information Library (简体中文)
search filter icon
search icon

文档信息

前言

第 1 部分使用链接编辑器和运行时链接程序

1.  Oracle Solaris 链接编辑器介绍

2.  链接编辑器

3.  运行时链接程序

共享目标文件依赖项

查找共享目标文件依赖项

运行时链接程序搜索的目录

配置缺省搜索路径

动态字符串标记

重定位处理

重定位符号查找

缺省符号查找

运行时插入

执行重定位的时间

重定位错误

装入其他目标文件

延迟装入动态依赖项

提供 dlopen() 的替代项

初始化和终止例程

初始化和终止顺序

安全性

运行时链接编程接口

装入其他目标文件

重定位处理

符号查找

获取新符号

测试功能

使用插入

调试帮助

调试功能

调试器模块

4.  共享目标文件

第 2 部分快速参考

5.  链接编辑器快速参考

第 3 部分高级主题

6.  直接绑定

7.  生成目标文件以优化系统性能

8.  mapfile

9.  接口和版本控制

10.  使用动态字符串标记建立依赖性

11.  可扩展性机制

第 4 部分ELF 应用程序二进制接口

12.  目标文件格式

13.  程序装入和动态链接

14.  线程局部存储

第 5 部分附录

A.  链接程序和库的更新及新增功能

B.  System V 发行版 4(版本 1)mapfile

索引

调试帮助

Oracle Solaris 运行时链接程序附带有调试库和调试 mdb(1) 模块。使用调试库,可以更详细地跟踪运行时链接过程。使用 mdb(1) 模块,可以进行交互式进程调试。

调试功能

运行时链接程序提供了调试功能,允许您详细地跟踪应用程序的运行时链接及其依赖项情况。使用此功能显示的信息类型应保持不变。不过,信息的确切格式可能随发行版的不同而有所变化。

不了解运行时链接程序的用户可能不熟悉某些调试输出。不过,您可能对其中许多方面不太感兴趣。

可使用环境变量 LD_DEBUG 来启用调试。所有调试输出都使用进程标识符作为前缀。必须使用一个或多个标记来扩充此环境变量,以指示所需调试的类型。

使用 LD_DEBUG=help,可以显示 LD_DEBUG 中可用的标记。

$ LD_DEBUG=help prog

prog 可以是任何动态可执行文件。在将控制权转交给 prog 之前,进程终止并随后显示帮助信息。可执行文件的选择并不重要。

缺省情况下,会将所有调试输出发送到标准错误输出文件 stderr。可以使用 output 标记将调试输出定向到其他文件。例如,可以在名为 rtld-debug.txt 的文件中捕获帮助文本。

$ LD_DEBUG=help,output=rtld-debug.txt prog

此外,还可以通过设置环境变量 LD_DEBUG_OUTPUT 来重定向调试输出。使用 LD_DEBUG_OUTPUT 时,进程标识符作为后缀添加到输出文件名。

如果同时指定 LD_DEBUG_OUTPUToutput 标记,则 LD_DEBUG_OUTPUT 优先。如果同时指定 LD_DEBUG_OUTPUToutput 标记,则 LD_DEBUG_OUTPUT 优先。将 output 标记与调用 fork(2) 的程序结合使用会导致每个进程都将调试输出写入同一文件。调试输出因此会变得混乱且不完整。在这种情况下应使用 LD_DEBUG_OUTPUT,以将每个进程的调试输出定向到唯一的文件。

对于安全的应用程序,不允许进行调试。

其中一个最有用的调试选项是显示运行时进行的符号绑定。以下示例使用很简单的动态可执行文件,该可执行文件依赖于两个局部共享目标文件。

$ cat bar.c
int bar = 10;
$ cc -o bar.so.1 -K pic -G bar.c
 
$ cat foo.c
int foo(int data)
{
        return (data);
}
$ cc -o foo.so.1 -K pic -G foo.c
 
$ cat main.c
extern  int     foo();
extern  int     bar;
 
int main()
{
        return (foo(bar));
}
$ cc -o prog main.c -R/tmp:. foo.so.1 bar.so.1

通过设置 LD_DEBUG=bindings,可以显示运行时符号绑定。

$ LD_DEBUG=bindings prog
11753: .......
11753: binding file=prog to file=./bar.so.1: symbol bar
11753: .......
11753: transferring control: prog
11753: .......
11753: binding file=prog to file=./foo.so.1: symbol foo
11753: .......

即时重定位需要的符号 bar 是在应用程序获得控制权之前绑定的。然而,符号 foo 是延迟重定位所需的,将在应用程序获得第一次调用函数的控制权之后绑定。此重定位说明了延迟绑定的缺省模式。如果设置了环境变量 LD_BIND_NOW,则所有符号绑定都会在应用程序获取控制权之前进行。

通过设置 LD_DEBUG=bindings,detail,可提供有关实际绑定位置的实际地址和相对地址的其他信息。

可以使用 LD_DEBUG 来显示使用的各个搜索路径。例如,通过设置 LD_DEBUG=libs,可以显示用于查找所有依赖项的搜索路径机制。

$ LD_DEBUG=libs prog
11775:
11775: find object=foo.so.1; searching
11775:  search path=/tmp:.  (RUNPATH/RPATH from file prog)
11775:  trying path=/tmp/foo.so.1
11775:  trying path=./foo.so.1
11775:
11775: find object=bar.so.1; searching
11775:  search path=/tmp:.  (RUNPATH/RPATH from file prog)
11775:  trying path=/tmp/bar.so.1
11775:  trying path=./bar.so.1
11775: .......

应用程序 prog 中记录的运行路径将影响两个依赖项 foo.so.1bar.so.1 的搜索。

同样,可通过设置 LD_DEBUG=symbols 来显示每个符号查找的搜索路径。组合使用 symbolsbindings 可生成符号重定位进程的完整信息。

$ LD_DEBUG=bindings,symbols prog
11782: .......
11782: symbol=bar;  lookup in file=./foo.so.1  [ ELF ]
11782: symbol=bar;  lookup in file=./bar.so.1  [ ELF ]
11782: binding file=prog to file=./bar.so.1: symbol bar
11782: .......
11782: transferring control: prog
11782: .......
11782: symbol=foo;  lookup in file=prog  [ ELF ]
11782: symbol=foo;  lookup in file=./foo.so.1  [ ELF ]
11782: binding file=prog to file=./foo.so.1: symbol foo
11782: .......

在前面的示例中,未在应用程序 prog 中搜索符号 bar。省略数据引用查找是因为在处理复制重定位时使用了优化。有关此重定位类型的更多详细信息,请参见复制重定位

调试器模块

调试器模块提供了一组可在 mdb(1) 下装入的 dcmdswalkers。此模块可用于检查运行时链接程序的各种内部数据结构。许多调试信息都要求您熟悉运行时链接程序的内部构造。并且该信息会随发行版的不同而有所变化。但是,这些数据结构中的某些元素显示了动态链接进程的基本组件,有助于进行一般调试。

以下示例显示了一些将 mdb(1) 与调试器模块一起使用的简单方案。

$ cat main.c
#include  <dlfnc.h>

int main()
{
        void *handle;
        void (*fptr)();

        if ((handle = dlopen("foo.so.1", RTLD_LAZY)) == NULL)
                return (1);

        if ((fptr = (void (*)())dlsym(handle, "foo")) == NULL)
                return (1);

        (*fptr)();
        return (0);
}
$ cc -o main main.c -R.

如果 mdb(1) 尚未自动装入调试器模块 ld.so,则显式装入该模块。之后可以检查调试器模块的功能。

$ mdb main
> ::load ld.so
> ::dmods -l ld.so

ld.so
-----------------------------------------------------------------
  dcmd Bind                 - Display a Binding descriptor
  dcmd Callers              - Display Rt_map CALLERS binding descriptors
  dcmd Depends              - Display Rt_map DEPENDS binding descriptors
  dcmd ElfDyn               - Display Elf_Dyn entry
  dcmd ElfEhdr              - Display Elf_Ehdr entry
  dcmd ElfPhdr              - Display Elf_Phdr entry
  dcmd Groups               - Display Rt_map GROUPS group handles
  dcmd GrpDesc              - Display a Group Descriptor
  dcmd GrpHdl               - Display a Group Handle
  dcmd Handles              - Display Rt_map HANDLES group descriptors
  ....
> ::bp main
> :r

进程中的每个动态目标文件都表示为链接映射 Rt_map,该映射在链接映射列表中对其进行维护。可使用 Rt_maps 显示进程的所有链接映射。

> ::Rt_maps
Link-map lists (dynlm_list): 0xffbfe0d0
----------------------------------------------
  Lm_list: 0xff3f6f60  (LM_ID_BASE)
  ----------------------------------------------
    lmco        rtmap       ADDR()     NAME()
    ----------------------------------------------
    [0xc]       0xff3f0fdc 0x00010000 main
    [0xc]       0xff3f1394 0xff280000 /lib/libc.so.1
  ----------------------------------------------
  Lm_list: 0xff3f6f88  (LM_ID_LDSO)
  ----------------------------------------------
    [0xc]       0xff3f0c78 0xff3b0000 /lib/ld.so.1

可使用 Rt_map 显示单个链接映射。

> 0xff3f9040::Rt_map
Rt_map located at: 0xff3f9040
     NAME: main
 PATHNAME: /export/home/user/main
     ADDR: 0x00010000         DYN: 0x000207bc
     NEXT: 0xff3f9460        PREV: 0x00000000
      FCT: 0xff3f6f18    TLSMODID:          0
     INIT: 0x00010710        FINI: 0x0001071c
   GROUPS: 0x00000000     HANDLES: 0x00000000
  DEPENDS: 0xff3f96e8     CALLERS: 0x00000000
    .....

可使用 ElfDyn dcmd 显示目标文件的 .dynamic 节。以下示例显示了前 4 项。

> 0x000207bc,4::ElfDyn
Elf_Dyn located at: 0x207bc
    0x207bc  NEEDED       0x0000010f
Elf_Dyn located at: 0x207c4
    0x207c4  NEEDED       0x00000124
Elf_Dyn located at: 0x207cc
    0x207cc  INIT         0x00010710
Elf_Dyn located at: 0x207d4
    0x207d4  FINI         0x0001071c

mdb(1) 在设置推迟断点时也很有用。在此示例中,函数 foo() 中的断点可能会很有用。但是,在对 foo.so.1 执行 dlopen(3C) 之前,调试器不知道此符号。推迟断点会指示调试器在装入动态目标文件时设置实际断点。

> ::bp foo.so.1`foo
> :c
> mdb: You've got symbols!
> mdb: stop at foo.so.1`foo
mdb: target stopped at:
foo.so.1`foo:   save      %sp, -0x68, %sp

此时,已经装入了新目标文件:

> *ld.so`lml_main::Rt_maps
lmco    rtmap       ADDR()     NAME()
----------------------------------------------
[0xc]   0xff3f0fdc 0x00010000 main
[0xc]   0xff3f1394 0xff280000 /lib/libc.so.1
[0xc]   0xff3f9ca4 0xff380000 ./foo.so.1
[0xc]   0xff37006c 0xff260000 ./bar.so.1

foo.so.1 的链接映射显示了 dlopen(3C) 返回的句柄。可使用 Handles 来扩展此结构。

> 0xff3f9ca4::Handles -v
HANDLES for ./foo.so.1
----------------------------------------------
  HANDLE: 0xff3f9f60 Alist[used 1: total 1]
    ----------------------------------------------
    Group Handle located at: 0xff3f9f28
    ----------------------------------------------
        owner:               ./foo.so.1
        flags: 0x00000000    [ 0 ]
       refcnt:          1    depends: 0xff3f9fa0 Alist[used 2: total 4]
        ----------------------------------------------
        Group Descriptor located at: 0xff3f9fac
           depend: 0xff3f9ca4    ./foo.so.1
            flags: 0x00000003    [ AVAIL-TO-DLSYM,ADD-DEPENDENCIES ]
        ----------------------------------------------
        Group Descriptor located at: 0xff3f9fd8
           depend: 0xff37006c    ./bar.so.1
            flags: 0x00000003    [ AVAIL-TO-DLSYM,ADD-DEPENDENCIES ]

句柄的依赖项由一组链接映射组成,这些链接映射表示可满足 dlsym(3C) 请求的句柄的目标文件。在此情况下,依赖项为 foo.so.1bar.so.1


注 - 前面的示例提供了调试器模块功能的基本指南,但确切的命令、用法和输出可能会随发行版的不同而有所变化。有关系统中可用的确切功能,请参阅 mdb(1) 用法和帮助信息。