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

文档信息

前言

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

1.  Oracle Solaris 链接编辑器介绍

2.  链接编辑器

3.  运行时链接程序

4.  共享目标文件

5.  接口和版本控制

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

第 2 部分快速参考

7.  链接编辑器快速参考

8.  版本控制快速参考

第 3 部分高级主题

9.  直接绑定

10.  Mapfile

Mapfile 结构和语法

Mapfile 版本

条件输入

指令语法

Mapfile 指令

CAPABILITY 指令

HW 属性

HW_1 / HW_2 属性

MACHINE 属性

PLATFORM 属性

SF 属性

SF_1 属性

DEPEND_VERSIONS 指令

ALLOW 属性

REQUIRE 属性

HDR_NOALLOC 指令

PHDR_ADD_NULL 指令

LOAD_SEGMENT / NOTE_SEGMENT / NULL_SEGMENT 指令

ALIGN 属性(仅限 LOAD_SEGMENT)

ASSIGN_SECTION 属性

DISABLE 属性

FLAGS 属性(仅限 LOAD_SEGMENT)

IS_ORDER 属性

MAX_SIZE 属性(仅限 LOAD_SEGMENT)

NOHDR 属性(仅限 LOAD_SEGMENT)

OS_ORDER 属性

PADDR 属性(仅限 LOAD_SEGMENT)

ROUND 属性(仅限 LOAD_SEGMENT)

SIZE_SYMBOL 属性(仅限 LOAD_SEGMENT)

VADDR(仅限 LOAD_SEGMENT)

SEGMENT_ORDER 指令

STACK 指令

STUB_OBJECT 指令

SYMBOL_SCOPE / SYMBOL_VERSION 指令

ASSERT 属性

AUXILIARY 属性

FILTER 属性

FLAGS 属性

SIZE 属性

TYPE 属性

VALUE 属性

预定义段

映射示例

示例:节到段的分配

示例:预定义节的修改

链接编辑器内部:节和段的处理

节到段的分配

预定义段和入口条件的 Mapfile 指令

11.  可扩展性机制

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

12.  目标文件格式

13.  程序装入和动态链接

14.  线程局部存储

第 5 部分附录

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

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

索引

Mapfile 指令

链接编辑器接受以下指令。

表 10-6 Mapfile 指令

指令
目的
CAPABILITY
硬件、软件、计算机和平台功能
DEPEND_VERSIONS
指定可共享目标文件依赖项的允许版本
HDR_NOALLOC
ELF 头和程序头不可分配
LOAD_SEGMENT
创建新的可装入段,或者修改现有装入段
NOTE_SEGMENT
创建注释段,或者修改现有注释段
NULL_SEGMENT
创建空段,或者修改现有空段
PHDR_ADD_NULL
添加空程序头项
SEGMENT_ORDER
指定输出目标文件和程序头数组中的段顺序
STACK
进程栈属性
STUB_OBJECT
指定该目标文件可生成为桩目标文件
SYMBOL_SCOPE
设置未命名全局版本中的符号属性和作用域
SYMBOL_VERSION
设置显式命名版本中的符号属性和作用域

后面的各个小节显示了每个支持的 mapfile 指令的特定语法。

CAPABILITY 指令

通常在编译时会在目标文件中记录可重定位目标文件的硬件、软件、计算机和平台功能。链接编辑器结合所有输入可重定位目标文件的功能来创建输出文件的最终功能节。可以在 mapfile 中定义功能以扩充或完全取代由输入可重定位目标文件提供的功能。

        CAPABILITY [capid] {
                HW  = [hwcap_flag...];
                HW += [hwcap_flag...];
                HW -= [hwcap_flag...];
 
                HW_1  = [value...];
                HW_1 += [value...];
                HW_1 -= [value...];
 
                HW_2  = [value...];
                HW_2 += [value...];
                HW_2 -= [value...];
 
                MACHINE  = [machine_name...];
                MACHINE += [machine_name...];
                MACHINE -= [machine_name...];
 
                PLATFORM  = [platform_name...];
                PLATFORM += [platform_name...];
                PLATFORM -= [platform_name...];
 
                SF  = [sfcap_flag...];
                SF += [sfcap_flag...];
                SF -= [sfcap_flag...];
 
                SF_1  = [value...];
                SF_1 += [value...];
                SF_1 -= [value...];
        };    

如果存在可选的 capid 名称,则它可以为目标文件功能提供一个符号名称,从而在输出目标文件中获得一个 CA_SUNW_ID 功能项。如果发现多个 CAPABILITY 指令,则会使用最后一个指令提供的 capid

可以使用空 CAPABILITY 指令为目标文件功能指定一个 capid 而不指定任何功能值。

        CAPABILITY capid;

对于每种功能类型,链接编辑器会维护一个当前值 (value) 和一组要排除的值 (exclude)。对于硬件和软件功能,这些值是位掩码。对于计算机和平台功能,它们是名称列表。在处理 mapfile 之前,必须清除所有功能的 valueexclude 值。赋值运算符的工作方式如下。

输入目标文件在读取 mapfile 后进行处理。输入目标文件指定的功能值将与来自 mapfile 的值合并,除非使用 "=" 运算符,在这种情况下,在输入目标文件中遇到时将忽略该功能。因此,"=" 运算符将覆盖输入目标文件,而 "+=" 运算符则用于扩充它们。

在将所获得的功能值写入到输出目标文件之前,链接编辑器会减去使用 "-=" 运算符指定的任何功能值。

要从输出目标文件中完全排除某个给定功能,使用 "=" 运算符和一个空值列表已足够。例如,以下示例将抑制输入目标文件提供的任何硬件功能:

        $mapfile_version 2
        CAPABILITY {
                HW = ;
        };

在 ELF 目标文件中,硬件和软件功能表示为目标文件功能节中的一个或多个位掩码中的位赋值。HWSF mapfile 属性提供了这一实现的更抽象的视图,即接受一个空格分隔的符号功能名称列表,链接编辑器会将其转换为相应掩码和位。带有编号的属性(HW_1HW_2SF_1)旨在允许对底层功能位掩码进行直接数字访问。它们可用于指定尚未正式定义的功能位。如有可能,则建议使用 HWSF 属性。

HW 属性

硬件功能指定为一个空格分隔的符号功能名称列表。对于 SPARC 平台,硬件功能定义为 <sys/auxv_SPARC.h> 中的 AV_ 值。对于 x86 平台,硬件功能定义为 <sys/auxv_386.h> 中的 AV_ 值。Mapfile 使用相同的名称,但不带 AV_ 前缀。例如,x86 AV_SSE 硬件功能在 mapfile 中称为 SSE。该列表可以包含为 CA_SUNW_HW_ 功能掩码定义的任意功能名称。

HW_1 / HW_2 属性

HW_1HW_2 属性允许将 CA_SUNW_HW_1CA_SUNW_HW_2 功能掩码直接指定为数字值,或者指定为与该掩码相对应的符号硬件功能名称。

MACHINE 属性

MACHINE 属性指定目标文件可在其中执行的系统的计算机硬件名称。可通过实用程序 uname(1)-m 选项显示系统的计算机硬件名称。一个 CAPABILITY 指令可以指定多个计算机名称。每个名称将在输出目标文件中获得一个 CA_SUNW_MACH 功能项。

PLATFORM 属性

PLATFORM 属性指定目标文件可在其中执行的系统的平台名称。可通过实用程序 uname(1)-i 选项显示系统的平台名称。一个 CAPABILITY 指令可以指定多个平台名称。每个名称将在输出目标文件中获得一个 CA_SUNW_PLAT 功能项。

SF 属性

软件功能指定为一个空格分隔的符号功能名称列表。软件功能定义为 <sys/elf.h> 中的 SF1_SUNW_ 值。Mapfile 使用相同的名称,但不带 SF1_SUNW_ 前缀。例如,SF1_SUNW_ADDR32 软件功能在 mapfile 中称为 ADDR32。该列表可以包含为 CA_SUNW_SF_1 定义的任意功能名称。

SF_1 属性

SF_1 属性允许将 CA_SUNW_SF_1 功能掩码直接指定为数字值,或者指定为与该掩码相对应的符号软件功能名称。

DEPEND_VERSIONS 指令

链接可共享目标文件时,来自由目标文件导出的所有版本的符号通常可供链接编辑器使用。DEPEND_VERSIONS 指令用于将访问只限定于指定的版本。限制版本访问可用于确保给定输出目标文件不会使用在系统的较早版本上可能不可用的较新功能。

DEPEND_VERSIONS 指令的语法如下。

        DEPEND_VERSIONS objname {
                ALLOW = version_name;
                REQUIRE = version_name;
                ...
        };

objname 是可共享目标文件的名称,在命令行中指定。在使用 -l 命令行选项指定目标文件的一般情况下,这将是带有 lib 前缀的指定名称。例如,libc 通常在命令行中引用为 -lc,因此在 DEPEND_VERSIONS 指令中指定为 libc.so

ALLOW 属性

ALLOW 属性指定所指定的版本以及该版本所继承的版本可供链接编辑器用来在输出目标文件中解析符号。链接编辑器会向输出目标文件要求中添加一个针对包含此版本的继承链中使用的最高版本的要求。

REQUIRE 属性

REQUIRE 将指定版本添加到输出目标文件要求中,而不管该版本是否是满足链接操作所实际需要的。

HDR_NOALLOC 指令

每个 ELF 目标文件在文件的偏移 0 处都有一个 ELF 头。可执行和可共享目标文件还包含通过 ELF 头访问的程序头。链接编辑器通常会将这些项目安排为包含在第一个可装入段中。因此,这些头中所含的信息会显示在映射的映像中,并通常由运行时链接程序使用。HDR_NOALLOC 指令会防止这种情况。

        HDR_NOALLOC;

指定 HDR_NOALLOC 时,ELF 头和程序头数组仍显示在所获得的输出目标文件的开始处,但不包含在一个可装入段中,并且映像的虚拟地址计算始于第一个段的第一节,而非基于 ELF 头。

PHDR_ADD_NULL 指令

PHDR_ADD_NULL 指令会导致链接编辑器在程序头数组末尾添加指定数量的类型为 PT_NULL 的附加程序头项。额外的 PT_NULL 项可供后期处理实用程序使用。

        PHDR_ADD_NULL = value;

value 必须是正整数值,并给出要创建的额外 PT_NULL 项数。所获得的程序头项的所有字段将设置为 0。

LOAD_SEGMENT / NOTE_SEGMENT / NULL_SEGMENT 指令

段是输出目标文件的一个连续部分,其中包含节。mapfile 段指令允许指定三种不同的段类型。

段指令用于在输出文件中创建新段,或更改现有段的属性值。现有段是之前定义的段,或者是预定义段中所讨论的内置段。每个新段将添加到目标文件中相同类型的最后一个此类段之后。先添加可装入段,然后是注释段,最后添加空段。与这些段相关联的任何程序头将按照与段本身相同的相对顺序放在程序头数组中。通过为可装入段设置显式地址或者使用 SEGMENT_ORDER 指令可以更改这一缺省放置方式。

如果 segment_name 是一个预先存在的段,则所指定的属性将修改现有段。否则,将创建一个新段并为新段应用指定属性。链接编辑器会为未明确提供的属性填入缺省值。


注 - 选择段名称时,请注意链接编辑器的未来版本可能会添加新的预定义段。如果您的段指令中使用的名称与此新名称相匹配,则新的预定义段会将 mapfile 的含义从创建新段更改为修改现有段。防止这种情况的最好方式是避免为段使用通用名称,并为您的所有段名称指定一个唯一的前缀,例如公司/项目标识符,甚至程序的名称。例如,名为 hello_world 的程序可以使用段名称 hello_world_data_segment


所有这三个段指令共享一组通用的核心属性。段的声明如下,可用 LOAD_SEGMENTNOTE_SEGMENTNULL_SEGMENT 其中之一取代 directive

        directive segment_name {
                ASSIGN_SECTION [assign_name];
                ASSIGN_SECTION [assign_name] {
                        FILE_BASENAME = file_basename;
                        FILE_OBJNAME = objname;
                        FILE_PATH = file_path;
                        FLAGS = section_flags;
                        IS_NAME = section_name;
                        TYPE = section_type;
                };

                DISABLE;

                IS_ORDER  = assign_name...;
                IS_ORDER += assign_name...;

                OS_ORDER  = section_name...;
                OS_ORDER += section_name...;
};

LOAD_SEGMENT 指令接受一组特定于可装入段的附加属性。这些附加属性的语法如下。

        LOAD_SEGMENT segment_name {
                ALIGN = value;

                FLAGS  = segment_flags;
                FLAGS += segment_flags;
                FLAGS -= segment_flags;

                MAX_SIZE = value;

                NOHDR;

                PADDR = value;
                ROUND = value;

                SIZE_SYMBOL  = symbol_name...;
                SIZE_SYMBOL += symbol_name...;

                VADDR = value;
};

其中的任何段指令都可指定为空指令。当空段指令创建新段时,将为所有段属性设置缺省值。空段的声明如下。

        LOAD_SEGMENT segment_name;

        NOTE_SEGMENT segment_name;

        NULL_SEGMENT segment_name;

下面将说明一个或多个段指令所接受的所有属性。

ALIGN 属性(仅限 LOAD_SEGMENT)

ALIGN 属性用于指定可装入段的对齐方式。所指定的值设置在对应于该段的程序头的 p_align 字段中。段对齐用于计算段开头的虚拟地址。

指定的对齐方式必须是 2 的幂。缺省情况下,链接编辑器将段的对齐方式设置为内置缺省值。此缺省值随 CPU 的不同而不同,甚至也可能随软件修订版的不同而不同。

ALIGN 属性与 PADDRVADDR 属性相互排斥,不能与其一起使用。当指定了 PADDRVADDR 时,对应程序头的 p_align 字段将设置为缺省值。

ASSIGN_SECTION 属性

ASSIGN_SECTION 指定一个节属性组合,例如节名称、类型和标志,它们共同确定将某个节分配给某个给定段。每个此类属性集合称为一个入口条件。当节属性与入口条件的那些属性精确匹配时,该节即匹配。未指定任何属性的 ASSIGN_SECTION 将匹配与条件进行比较的任何节。

针对某个给定段允许使用多个 ASSIGN_SECTION 属性。每个 ASSIGN_SECTION 属性都独立于其他属性。如果某节与其中任何一个与段关联的 ASSIGN_SECTION 定义相匹配,则将该节指定给该段。除非段具有至少一个 ASSIGN_SECTION 属性,否则链接编辑器不会将节指定给段。

链接编辑器使用一个内部入口条件列表将节指定给段。在 mapfile 中遇到的每个 ASSIGN_SECTION 声明都按照所遇到的顺序放在此列表中。预定义段中所讨论的内置段的入口条件将紧接最后一个 mapfile 定义的项放在此列表中。

可以为入口条件指定一个可选名称 (assign_name)。该名称可与 IS_ORDER 属性一起使用,以指定输入节在输出节中的放置顺序。

为放置输入节,链接编辑器从入口条件列表的开头开始,将节的属性依次与每个入口条件进行比较。节将指定给与节属性精确匹配的第一个入口条件所关联的段。如果没有匹配,该节将放置在文件的最后,所有非可分配节通常都是如此。

ASSIGN_SECTION 接受以下各项。

表 10-7 节 FLAGS 值

标志值
含义
ALLOC
节是可分配的
WRITE
节是可写的
EXECUTE
节是可执行的
AMD64_LARGE
节可以大于 2 GB

DISABLE 属性

DISABLE 属性会导致链接编辑器忽略段。不会将任何节指定给禁用的段。当由以下段指令引用时,将自动重新启用段。因此,空引用即足以重新启用禁用的段。

segment segment_name;

FLAGS 属性(仅限 LOAD_SEGMENT)

FLAGS 属性将段权限指定为表 10-3 中所示权限的空格分隔列表。缺省情况下,用户定义的段将获得 READWRITEEXECUTE 权限。预定义段中所描述的预定义段的缺省标志由链接编辑器提供,在某些情况下可能与平台相关。

该属性允许采用三种形式。

        FLAGS  = segment_flags...;
        FLAGS += segment_flags...;
        FLAGS -= segment_flags...;

简单的 "=" 赋值运算符将当前标志替换为新集合,"+=" 形式将新标志添加到现有集合中,而 "-=" 形式将指定标志从现有集合中删除。

IS_ORDER 属性

链接编辑器通常按照遇到输出节的顺序将其放入段中。类似地,构成输出节的输入节也按照遇到它们的顺序进行放置。IS_ORDER 属性可用于改变输入节的这种缺省放置方式。IS_ORDER 指定入口条件名称 (assign_name) 的空格分隔列表。通过其中一个入口条件匹配的节将放置在输出节的开头,并按 IS_ORDER 指定的顺序排序。通过未在 IS_ORDER 列表中的入口条件匹配的节将按照遇到它们的顺序放置在已排序节之后。

使用 "=" 形式的赋值时,将放弃给定段的 IS_ORDER 的先前值并替换为新列表。"+=" 形式的 IS_ORDER 将新列表串联到现有列表的最后。

IS_ORDER 属性与编译器的 -xF 选项一起使用时会更有用。使用 -xF 选项编译文件时,将该文件中的每个函数都放置在与 text 节具有相同属性的单独节中。这些节称为 .text%function_name

例如,使用 -xF 选项编译包含 main()foo()bar() 这三个函数的文件时,会生成一个可重定位的目标文件,并会将三个函数的文本放置在名为 .text%main.text%foo.text%bar 的节中。当链接编辑器将这些节放入输出中时,将删除 %% 之后的任何内容。因此,所有这三个函数都将放在 .text 输出节中。IS_ORDER 属性可用于强制将它们以相对于彼此的特定顺序放在 .text 输出节中。

请考虑以下用户定义的 mapfile

        $mapfile_version 2
                LOAD_SEGMENT text {
                ASSIGN_SECTION text_bar  { IS_NAME = .text%bar };
                ASSIGN_SECTION text_main { IS_NAME = .text%main };
                ASSIGN_SECTION text_foo  { IS_NAME = .text%foo };
                IS_ORDER = text_foo text_bar text_main;
        };

不管这三个函数在源代码中的顺序或者链接编辑器遇到它们的顺序如何,它们在输出目标文件文本段中的顺序都将是 foo()bar()main()

MAX_SIZE 属性(仅限 LOAD_SEGMENT)

缺省情况下,链接编辑器允许段增大到段内容所需要的大小。MAX_SIZE 属性可用于指定段的最大大小。如果设置了 MAX_SIZE,链接编辑器会在段增长超出指定大小时生成错误。

NOHDR 属性(仅限 LOAD_SEGMENT)

如果设置了 NOHDR 属性的段成为输出目标文件中的第一个可装入段,则 ELF 头和程序头将不会包含在该段中。

NOHDR 属性与顶级 HDR_NOALLOC 指令的区别在于 HDR_NOALLOC 是一个基于段的值,仅当段成为第一个可装入段时才有效。该功能主要用于为早期的 mapfile 提供功能奇偶校验。有关更多详细信息,请参见附录 B

建议优先使用 HDR_NOALLOC 指令,而不是段 NOHDR 属性。

OS_ORDER 属性

链接编辑器通常按照遇到输出节的顺序将其放入段中。OS_ORDER 属性可用于改变输出节的这种缺省放置方式。OS_ORDER 指定输出节名称 (section_name) 的空格分隔列表。列出的节放在段的开头,并按照 OS_ORDER 指定的顺序排序。未在 OS_ORDER 中列出的节将按照遇到它们的顺序放在已排序节之后。

使用 "=" 形式的赋值时,将放弃给定段的 OS_ORDER 的先前值并替换为新列表。"+=" 形式的 OS_ORDER 将新列表串联到现有列表的最后。

PADDR 属性(仅限 LOAD_SEGMENT)

PADDR 属性用于为段指定一个显式物理地址。所指定的值设置在对应于该段的程序头的 p_addr 字段中。缺省情况下,链接编辑器将段的物理地址设置为 0,因为此字段对于用户模式目标文件没有意义,它主要用于非用户级目标文件,如操作系统内核。

ROUND 属性(仅限 LOAD_SEGMENT)

ROUND 属性用于指定段的大小应向上舍入为给定值。指定的舍入值必须是 2 的幂。缺省情况下,链接编辑器将段的舍入系数设置为 1,即不对段大小向上舍入。

SIZE_SYMBOL 属性(仅限 LOAD_SEGMENT)

SIZE_SYMBOL 属性定义要由链接编辑器创建的节大小符号名称的空格分隔列表。大小符号是全局绝对符号,以字节为单位表示段的大小。可以在目标文件中引用这些符号。为访问代码中的符号,应确保 symbol_name 是该语言中的合法标识符。建议采用 C 编程语言的符号命名规则,因为这种符号可能能够由任何其他语言访问。

可以使用 "=" 形式的赋值建立初始值,并且针对每个链接编辑器会话只能使用一次。"+=" 形式的 SIZE_SYMBOL 将新列表串联到现有列表的最后,并可根据需要使用任意次。

VADDR(仅限 LOAD_SEGMENT)

VADDR 属性用于为段指定一个显式虚拟地址。所指定的值设置在对应于该段的程序头的 p_vaddr 字段中。缺省情况下,链接编辑器会在创建输出文件时将虚拟地址指定给段。

SEGMENT_ORDER 指令

SEGMENT_ORDER 指令用于为输出目标文件中的段指定非缺省顺序。

SEGMENT_ORDER 接受段名称的空格分隔列表。

        SEGMENT_ORDER  = segment_name...;
        SEGMENT_ORDER += segment_name...;

使用 "=" 形式的赋值时,将放弃之前的段顺序列表并替换为新列表。"+=" 形式的赋值将新列表串联到现有列表的最后。

缺省情况下,链接编辑器按以下方式确定段顺序。

  1. 具有通过 LOAD_SEGMENT 指令的 VADDR 属性设置的显式地址的可装入段,按地址排序。

  2. 使用 SEGMENT_ORDER 指令排序的段,按指定顺序排序。

  3. 没有显式地址且未在 SEGMENT_ORDER 列表中列出的可装入段。

  4. 没有显式地址且未在 SEGMENT_ORDER 列表中列出的注释段。

  5. 没有显式地址且未在 SEGMENT_ORDER 列表中列出的空段。


注 - ELF 具有一些格式正确的目标文件所必须遵循的隐式约定。

可以使用 Mapfile 创建不遵循这些要求的目标文件。但应避免如此操作,因为运行这种目标文件的结果是不确定的。


除非指定 HDR_NOALLOC 指令,否则链接编辑器将强制要求第一个段必须是可装入段,而不是注释段或空段。HDR_NOALLOC 不能用于用户级目标文件,因此没什么实用价值。生成操作系统内核时会使用该功能。

STACK 指令

STACK 指令指定进程栈的属性。

        STACK {
                FLAGS  = segment_flags...;
                FLAGS += segment_flags...;
                FLAGS -= segment_flags...;
};

FLAGS 属性指定段权限的空格分隔列表,其中包含表 10-3 中所描述的任意值。

该属性允许采用三种形式。简单的 "=" 赋值运算符将当前标志替换为新集合,"+=" 形式将新标志添加到现有集合中,而 "-=" 形式将指定标志从现有集合中删除。

缺省栈权限由平台 ABI 定义,并随平台的不同而变化。目标平台的值使用段标志名称 STACK 指定。

在某些平台上,ABI 要求的缺省权限包括 EXECUTE。一般很少需要 EXECUTE,并且它通常被视为一个潜在的安全风险。建议从栈中删除 EXECUTE 权限。

        STACK {
                FLAGS -= EXECUTE;
        };

STACK 指令在输出 ELF 目标文件中反映为一个 PT_SUNWSTACK 程序头项。

STUB_OBJECT 指令

STUB_OBJECT 指令通知链接编辑器可以将 mapfile 所描述的目标文件生成为一个桩目标文件。

        STUB_OBJECT;

桩共享目标文件是完全通过命令行中提供的 mapfile 中的信息生成的。当指定 -z stub 选项生成桩目标文件时,要求 mapfile 中存在 STUB_OBJECT 指令,链接编辑器使用符号 ASSERT 属性中的信息创建与实际目标文件的符号相匹配的全局符号。

SYMBOL_SCOPE / SYMBOL_VERSION 指令

SYMBOL_SCOPESYMBOL_VERSION 指令用于指定全局符号的作用域和属性。SYMBOL_SCOPE 在未命名的基础符号版本的上下文中工作,而 SYMBOL_VERSION 用于将符号收集到显式命名的全局版本中。SYMBOL_VERSION 指令允许创建稳定接口,该接口支持目标文件以向下兼容方式发展。

SYMBOL_VERSION 的语法如下。

        SYMBOL_VERSION version_name {
            symbol_scope:
                *;

                symbol_name;
                symbol_name {
                        ASSERT = {
                                ALIAS = symbol_name;
                                BINDING = symbol_binding;
                                TYPE = symbol_type;
 
                                SIZE = size_value;
                                SIZE = size_value[count];
                        };
                        AUXILIARY = soname;
                        FILTER = soname;
                        FLAGS = symbol_flags...;
 
                        SIZE = size_value;
                        SIZE = size_value[count];
 
                        TYPE = symbol_type;
                        VALUE = value;
                };
        } [inherited_version_name...];

SYMBOL_SCOPE 不接受版本名称,除此之外都相同。

        SYMBOL_SCOPE {
                ...
        };

SYMBOL_VERSION 指令中,version_name 为该符号定义集合提供一个标签。该标签标识输出目标文件中的 version definition。可以指定一个或多个由空格分隔的继承版本 (inherited_version_name),这时新定义的版本将从命名的版本继承。请参见第 5 章

symbol_scope 定义 SYMBOL_SCOPESYMBOL_VERSION 指令中符号的作用域。缺省情况下,符号被假定为具有全局作用域。通过指定 symbol_scope 并后跟一个冒号 (:) 可以修改此缺省设置。这些行确定其后所有符号的符号作用域,直至后续作用域声明做出更改。下表给出了可能的作用域值及其含义。

表 10-8 符号作用域类型

作用域
含义
default / global
此作用域的全局符号对所有外部目标文件都可见。从目标文件内部对这种符号的引用在运行时绑定,从而允许进行插入。这种可见性作用域提供了一种缺省设置,可通过其他符号可见性技术进行降级或消除。此作用域定义与具有 STV_DEFAULT 可见性的符号产生相同的效果。请参见表 12-20
hidden / local
此作用域的全局符号缩减为具有局部绑定的符号。此作用域的符号对其他外部目标文件不可见。此作用域定义与具有 STV_HIDDEN 可见性的符号产生相同的效果。请参见表 12-20
protected / symbolic
此作用域的全局符号对所有外部目标文件都可见。从目标文件内部对这些符号的引用在链接编辑时绑定,从而可以防止运行时插入。这种可见性作用域可通过其他符号可见性技术进行降级或消除。此作用域定义与具有 STV_PROTECTED 可见性的符号产生相同的效果。请参见表 12-20
exported
此作用域的全局符号对所有外部目标文件都可见。从目标文件内部对这种符号的引用在运行时绑定,从而允许进行插入。这种符号可见性不能通过任何其他符号可见性技术进行降级或消除。此作用域定义与具有 STV_EXPORTED 可见性的符号产生相同的效果。请参见表 12-20
singleton
此作用域的全局符号对所有外部目标文件都可见。从目标文件内部对这种符号的引用在运行时绑定,并确保进程中的所有引用只绑定到一个符号实例。这种符号可见性不能通过任何其他符号可见性技术进行降级或消除。此作用域定义与具有 STV_SINGLETON 可见性的符号产生相同的效果。请参见表 12-20
eliminate
此作用域的全局符号处于隐藏状态,并会删除其符号表项。此作用域定义与具有 STV_ELIMINATE 可见性的符号产生相同的效果。请参见表 12-20

symbol_name 是符号的名称。该名称可生成符号定义或符号引用,具体取决于任何限定属性。在最简单的没有任何限定属性的形式中,将创建符号引用。该引用与使用使用 -u 选项定义其他符号中所讨论的 -u 选项生成的引用完全相同。通常,如果符号名称后跟任何限定属性,则使用关联的属性生成符号定义。

定义了 local(局部)作用域时,可以将符号名称定义为特殊自动缩减指令 "*"。没有显式定义可见性的符号将在所生成的动态目标文件中降级为局部绑定。显式可见性定义源自 mapfile 定义或封装在可重定位目标文件中的可见性定义。类似地,定义了 eliminate(删除)作用域时,可以将符号名称定义为特殊自动删除指令 "*"。没有显式定义可见性的符号将从所生成的动态目标文件中删除。

如果指定了 SYMBOL_VERSION 指令,或者如果使用 SYMBOL_VERSIONSYMBOL_SCOPE 指定了自动缩减,则会在所创建的映像中记录版本控制信息。如果此映像是可执行目标文件或共享目标文件,则还会应用任何符号缩减。

如果要创建的映像是可重定位目标文件,则缺省情况下不会应用符号缩减。在这种情况下,任何符号缩减都将记录在版本控制信息中。当最终使用可重定位目标文件来生成可执行文件或共享目标文件时,将应用这些符号缩减。在生成可重定位目标文件时,可以使用链接编辑器的 -B reduce 选项强制执行符号缩减。

第 5 章中提供了版本控制信息的更详细说明。


注 - 为了确保接口定义的稳定性,定义符号名称时不提供通配符扩展功能。


symbol_name 可单独列出,以便仅将符号分配给一个版本和/或指定其作用域。可以在 {} 括号中指定可选符号属性。下面将说明各个有效属性。

ASSERT 属性

ASSERT 属性用于指定符号的预期特征。链接编辑器会比较通过链接编辑所获得的符号特征与 ASSERT 属性指定的符号特征。如果实际属性与声明的属性不一致,则会发出致命错误并且不会创建输出目标文件。

ASSERT 属性的解释取决于是使用 STUB_OBJECT 指令还是使用 -z stub 命令行选项。三种可能的情况如下所述。

  1. 不使用 STUB_OBJECT 指令时,将不需要 ASSERT 属性。但是,如果 ASSERT 属性存在,则会根据通过链接编辑收集到的实际值对其属性进行验证。如果任何 ASSERT 属性与其关联的实际值不匹配,则链接编辑过程将终止且不成功。

  2. 使用 STUB_OBJECT 指令且指定了 -z stub 命令行选项时,链接编辑器将使用 ASSERT 指令定义目标文件提供的全局符号的属性。请参见桩目标文件

  3. 使用 STUB_OBJECT 指令但未指定 -z stub 命令行选项时,链接编辑器要求所获得的目标文件中的所有全局数据都有一个将其声明为数据并提供大小的关联 ASSERT 指令。在此模式下,如果未指定 TYPE ASSERT 属性,则假定为 GLOBAL。类似地,如果未指定 SH_ATTR,则假定为缺省值 BITS。这些缺省值可确保桩目标文件和实际目标文件的数据属性是兼容的。所获得的 ASSERT 语句的计算方式与上述第一种情况相同。请参见STUB_OBJECT 指令

ASSERT 接受以下各项。

表 10-9 SH_ATTR 值

节属性
含义
BITS
节的类型不是 SHT_NOBITS
NOBITS
节的类型是 SHT_NOBITS

AUXILIARY 属性

指示此符号是共享目标文件名称 (soname) 的辅助过滤器。请参见生成辅助过滤器

FILTER 属性

指示此符号是共享目标文件 name 的过滤器。请参见生成标准过滤器。过滤器符号不需要输入可重定位目标文件提供任何后备实现。因此,使用此指令并定义符号的类型可以创建绝对符号表项。

FLAGS 属性

symbol_flags 将符号属性指定为一个或多个以下值的空格分隔列表。

表 10-10 符号 FLAG 值

标志
含义
DIRECT
指示应直接绑定到此符号。与符号定义一起使用时,此关键字会将来自所生成目标文件中的任何引用直接绑定到该定义。与符号引用一起使用时,此标志会导致直接绑定到提供定义的依赖项。请参见第 9 章。此标志还可与 PARENT 标志一起使用以便在运行时建立与任何父项的直接绑定。
DYNSORT
指示此符号应包含在排序节中。请参见符号排序节。符号类型必须为 STT_FUNCSTT_OBJECTSTT_COMMONSTT_TLS
EXTERN
指示在要创建的目标文件外部定义符号。通常定义此关键字以为回调例程设置标签。此标志会抑制将使用 -z defs 选项标记的未定义符号。此标志仅在生成符号引用时才有意义。如果在链接编辑时合并的目标文件内出现此符号的定义,则会在无提示的情况下忽略该关键字。
INTERPOSE
指示此符号将充当插入项。仅在生成动态可执行文件时才能使用此标志。在定义插入符号方面,此标志可提供比使用 -z interpose 选项更精细的控制。
NODIRECT
指示不应直接绑定到此符号。此状态适用于要创建的目标文件中的引用或外部引用中的引用。请参见第 9 章。此标志还可与 PARENT 标志一起使用以防止在运行时直接绑定到任何父项。
NODYNSORT
指示此符号不应包含在排序节中。请参见符号排序节
PARENT
指示在要创建的目标文件的父项中定义符号。父项是在运行时将此目标文件作为显式依赖项进行引用的目标文件。父项还可以使用 dlopen(3C) 在运行时引用此目标文件。通常定义此标志以为回调例程设置标签。此标志可与 DIRECTNODIRECT 标志一起使用以建立对父项的单个直接或非直接引用。此标志会抑制将使用 -z defs 选项标记的未定义符号。此标志仅在生成符号引用时才有意义。如果在链接编辑时合并的目标文件内出现此符号的定义,则会在无提示的情况下忽略该关键字。

SIZE 属性

设置大小属性。此属性会导致创建符号定义。

size_value 参数可以是数字值,或者是符号名称 addrsizeaddrsize 表示可保存一个内存地址的计算机字的大小。在生成 32 位目标文件时,链接编辑器会将 addrsize 替换为值 4,在生成 64 位目标文件时替换为值 8。addrsize 对于表示类型为 long 的指针变量和 C 变量的大小很有用,因为它会自动针对 32 位和 64 位目标文件进行调整,而无需使用条件输入。

可以选择为 size_value 参数添加一个括在方括号中的 count 值后缀。如果存在 count,则 size_valuecount 将相乘以得出最终的大小值。

TYPE 属性

符号类型属性。此属性可以是 COMMONDATAFUNCTIONCOMMON 会生成一个暂定符号定义。DATAFUNCTION 会生成一个节符号定义或绝对符号定义。请参见符号表节

数据属性会导致创建 OBJT 符号。带有大小但不含值的数据属性会通过将符号与某个 ELF 节相关联来创建节符号。此节将填充零。函数属性会导致创建 FUNC 符号。

带有大小但不含值的函数属性会通过将符号与某个 ELF 节相关联来创建节符号。一个由链接编辑器生成的带有以下签名的 void 函数将指定给此节。

        void (*)(void)

含有值的数据或函数属性将生成相应符号类型并带有一个绝对 ABS 节索引。

创建节数据符号对于创建过滤器很有用。从可执行文件中对过滤器的节数据符号的外部引用会导致生成相应的复制重定位。请参见复制重定位

VALUE 属性

指示值属性。此属性会导致创建符号定义。