跳过导航链接 | |
退出打印视图 | |
Oracle Solaris 11.1 链接程序和库指南 Oracle Solaris 11.1 Information Library (简体中文) |
目标文件的符号表包含定位和重定位程序的符号定义和符号引用所需的信息。符号表索引是此数组的下标。索引 0 指定表中的第一项并用作未定义的符号索引。请参见表 12-22。
符号表项具有以下格式。请参见 sys/elf.h。
typedef struct { Elf32_Word st_name; Elf32_Addr st_value; Elf32_Word st_size; unsigned char st_info; unsigned char st_other; Elf32_Half st_shndx; } Elf32_Sym; typedef struct { Elf64_Word st_name; unsigned char st_info; unsigned char st_other; Elf64_Half st_shndx; Elf64_Addr st_value; Elf64_Xword st_size; } Elf64_Sym;
目标文件的符号字符串表的索引,其中包含符号名称的字符表示形式。如果该值为非零,则表示指定符号名称的字符串表索引。否则,符号表项没有名称。
关联符号的值。根据上下文,该值可以是绝对值或地址。请参见符号值。
许多符号具有关联大小。例如,数据目标文件的大小是目标文件中包含的字节数。如果符号没有大小或大小未知,则此成员值为零。
符号的类型和绑定属性。表 12-19 中显示了值和含义的列表。以下代码说明了如何处理这些值。请参见 sys/elf.h。
#define ELF32_ST_BIND(info) ((info) >> 4) #define ELF32_ST_TYPE(info) ((info) & 0xf) #define ELF32_ST_INFO(bind, type) (((bind)<<4)+((type)&0xf)) #define ELF64_ST_BIND(info) ((info) >> 4) #define ELF64_ST_TYPE(info) ((info) & 0xf) #define ELF64_ST_INFO(bind, type) (((bind)<<4)+((type)&0xf))
符号的可见性。表 12-21 中显示了值和含义的列表。以下代码说明了如何处理 32 位目标文件和 64 位目标文件的值。其他位设置为零,并且未定义任何含义。
#define ELF32_ST_VISIBILITY(o) ((o)&0x3) #define ELF64_ST_VISIBILITY(o) ((o)&0x3)
所定义的每一个符号表项都与某节有关。此成员包含相关节头表索引。部分节索引会表示特殊含义。请参见表 12-4。
如果此成员包含 SHN_XINDEX,则实际节头索引会过大而无法放入此字段中。实际值包含在 SHT_SYMTAB_SHNDX 类型的关联节中。
根据符号的 st_info 字段确定的符号绑定可确定链接可见性和行为。
表 12-19 ELF 符号绑定 ELF32_ST_BIND 和 ELF64_ST_BIND
|
此范围内包含的值(包括这两个值)保留用于特定于操作系统的语义。
此范围内包含的值(包括这两个值)保留用于特定于处理器的语义。
链接编辑器合并多个可重定位目标文件时,不允许多次定义相同名称的 STB_GLOBAL 符号。但是,如果存在已定义的全局符号,则出现相同名称的弱符号不会导致错误。链接编辑器会接受全局定义,并忽略弱定义。
同样,如果存在通用符号,则出现相同名称的弱符号也不会导致错误。链接编辑器将使用通用定义,并忽略弱定义。通用符号具有包含 SHN_COMMON 的 st_shndx 字段。请参见符号解析。
链接编辑器搜索归档库时,将会提取包含未定义全局符号或暂定全局符号的定义的归档成员。此成员的定义可以是全局符号或弱符号。
缺省情况下,链接编辑器不会提取归档成员来解析未定义的弱符号。未解析的弱符号的值为零。使用 -z weakextract 可覆盖此缺省行为。使用此选项,弱引用可提取归档成员。
注 - 弱符号主要适用于系统软件。建议不要在应用程序中使用弱符号。
在每个符号表中,具有 STB_LOCAL 绑定的所有符号都优先于弱符号和全局符号。如节中所述,符号表节的 sh_info 节头成员包含第一个非局部符号的符号表索引。
根据符号的 st_info 字段确定的符号类型用于对关联实体进行一般等级划分。
表 12-20 ELF 符号类型 ELF32_ST_TYPE 和 ELF64_ST_TYPE
|
未指定符号类型。
此符号与变量、数组等数据目标文件关联。
此符号与函数或其他可执行代码关联。
此符号与节关联。此类型的符号表各项主要用于重定位,并且通常具有 STB_LOCAL 绑定。
通常,符号的名称会指定与目标文件关联的源文件的名称。文件符号具有 STB_LOCAL 绑定和节索引 SHN_ABS。此符号(如果存在)位于文件的其他 STB_LOCAL 符号前面。
符号索引为 1 的 SHT_SYMTAB 是表示目标文件的 STT_FILE 符号。通常,此符号后跟文件的 STT_SECTION 符号。这些节符号又后跟已降为局部符号的任何全局符号。
此符号标记未初始化的通用块。此符号的处理与 STT_OBJECT 的处理完全相同。
此符号指定线程局部存储实体。定义后,此符号可为符号指明指定的偏移,而不是实际地址。
线程局部存储重定位只能引用 STT_TLS 类型的符号。从可分配节中引用 STT_TLS 类型的符号只能通过使用特殊线程局部存储重定位来实现。有关详细信息,请参见第 14 章。从不可分配节中引用 STT_TLS 类型的符号没有此限制。
此范围内包含的值(包括这两个值)保留用于特定于操作系统的语义。
此范围内包含的值(包括这两个值)保留用于特定于处理器的语义。
符号的可见性根据其 st_other 字段确定。此可见性可以在可重定位目标文件中指定。此可见性定义了在符号成为可执行文件或共享目标文件的一部分后访问该符号的方式。
表 12-21 ELF 符号可见性
|
具有 STV_DEFAULT 属性的符号的可见性与符号的绑定类型指定的可见性相同。全局符号和弱符号在其定义组件(可执行文件或共享目标文件)外部可见。局部符号处于隐藏状态。另外,还可以替换全局符号和弱符号。可以在另一个组件中通过定义相同的名称插入这些符号。
如果当前组件中定义的符号在其他组件中可见,但不能被替换,则该符号处于受保护状态。定义组件中对这类符号的任何引用都必须解析为该组件中的定义。即使在另一个组件中存在按缺省规则插入的符号定义,也必须进行此解析。具有 STB_LOCAL 绑定的符号将没有 STV_PROTECTED 可见性。
如果当前组件中定义的符号的名称对于其他组件不可见,则该符号处于隐藏状态。必须对这类符号进行保护。此属性用于控制组件的外部接口。由这样的符号命名的目标文件仍可以在另一个组件中引用(如果将目标文件的地址传到外部)。
如果可执行文件或共享目标文件中包括可重定位目标文件,则该目标文件中包含的隐藏符号将会删除或转换为使用 STB_LOCAL 绑定。
此可见性属性以与 STV_HIDDEN 相同的方式进行解释。
此可见性属性确保符号保持为全局。不能使用任何其他符号可见性技术对此可见性进行降级或消除。具有 STB_LOCAL 绑定的符号将没有 STV_EXPORTED 可见性。
此可见性属性确保符号保持为全局,并且符号定义的一个实例绑定到一个进程中的所有引用。不能使用任何其他符号可见性技术对此可见性进行降级或消除。具有 STB_LOCAL 绑定的符号将没有 STV_SINGLETON 可见性。不能直接绑定到 STV_SINGLETON。
此可见性属性扩展 STV_HIDDEN。当前组件中定义为要消除的符号对其他组件不可见。该符号未写入使用该组件的动态可执行文件或共享目标文件的任何符号表中。
STV_SINGLETON 可见性属性可以影响链接编辑过程中可执行文件或共享目标文件中的符号的解析。从一个进程中的任意引用只能绑定到单件的一个实例。
STV_SINGLETON 可以与 STV_DEFAULT 可见性属性组合,其中 STV_SINGLETON 优先级较高。STV_EXPORT 可以与 STV_DEFAULT 可见性属性组合,其中 STV_EXPORT 优先级较高。STV_SINGLETON 或 STV_EXPORT 可见性不能与任何其他可见性属性组合。链接编辑会将此类事件视为致命错误。
在链接编辑过程中,其他可见性属性不会影响可执行文件或共享目标文件中符号的解析。这样的解析由绑定类型控制。一旦链接编辑器选定了其解析,这些属性即会强加两种要求。两种要求都基于以下事实,即所链接的代码中的引用可能已优化,从而可利用这些属性。
所有非缺省可见性属性在应用于符号引用时都表示,在链接的目标文件中必须提供满足该引用的定义。如果在链接的目标文件中没有定义此类型的符号引用,则该引用必须具有 STB_WEAK 绑定。在此情况下,引用将解析为零。
如果任何名称的引用或定义是具有非缺省可见性属性的符号,则该可见性属性将传播给链接的目标文件中的解析符号。如果针对符号的不同实例指定不同的可见性属性,则最具约束的可见性属性将传播给链接的目标文件中的解析符号。这些属性按最低到最高约束进行排序,依次为 STV_PROTECTED、STV_HIDDEN 和 STV_INTERNAL。
如果符号的值指向节中的特定位置,则符号的节索引成员 st_shndx 会包含节头表的索引。节在重定位过程中移动时,符号的值也会更改。符号的引用仍然指向程序中的相同位置。一些特殊节索引值会具有其他语义:
此符号标记尚未分配的通用块。与节的 sh_addralign 成员类似,符号的值也会指定对齐约束。链接编辑器在值为 st_value 的倍数的地址位置为符号分配存储空间。符号的大小会指明所需的字节数。
此节表索引表示未定义符号。链接编辑器将此目标文件与用于定义所表示的符号的另一目标文件合并时,此文件中对该符号的引用将与该定义绑定。
如之前所述,索引 0 (STN_UNDEF) 的符号表项将会保留。此项具有下表中列出的值。
表 12-22 ELF 符号表项:索引 0
|
不同目标文件类型的符号表的各项对于 st_value 成员的解释稍有不同。
在可重定位文件中,st_value 包含所定义符号的节偏移。st_value 表示从 st_shndx 所标识的节的起始位置的偏移。
在可执行文件和共享目标文件中,st_value 包含虚拟地址。为使这些文件的符号更适用于运行时链接程序,节偏移(文件解释)会替换为与节编号无关的虚拟地址(内存解释)。
尽管符号表值对于不同的目标文件具有类似含义,但通过适当的程序可以有效地访问数据。
按照以下顺序将符号写入符号表。
任何符号表中的索引 0 用于表示未定义的符号。符号表中的第一项始终完全为零。因此符号类型为 STT_NOTYPE。
如果符号表包含任何局部符号,符号表中的第二项是提供文件名的 STT_FILE 符号。
STT_SECTION 类型的节符号。
STT_REGISTER 类型的寄存器符号。
缩减到局部作用域的全局符号。
对于提供局部符号的每个输入文件,提供输入文件名称的 STT_FILE 符号,后跟相关符号。
在符号表中,全局符号紧跟局部符号。第一个全局符号由符号表 sh_info 值标识。局部符号和全局符号始终以这种方式保持彼此独立,不能混合。
这些符号表是 Oracle Solaris OS 中的特殊内容。
此符号表包含说明关联的 ELF 文件的每个符号。此符号表通常是不可分配的,因此在进程的内存映像中不可用。
通过使用 mapfile 和 ELIMINATE 关键字可以从 .symtab 中消除全局符号。请参见删除符号和SYMBOL_SCOPE / SYMBOL_VERSION 指令。
此表包含 .symtab 表中支持动态链接所需的符号的子集。此符号表可供分配,因此在进程的内存映像中可用。
.dynsym 表以标准 NULL 符号开始,后跟文件全局符号。STT_FILE 符号通常不包含在此符号表中。如果重定位项需要,可能会包含 STT_SECTION 符号。
扩充 .dynsym 表中包含的信息的可选符号表。.SUNW_ldynsym 表包含局部函数符号。此符号表可供分配,因此在进程的内存映像中可用。当不可分配的 .symtab 不可用,或已从文件中剥离时,调试器通过使用此节可在运行时上下文中产生精确的栈跟踪。此节还可以为运行时环境提供其他符号信息,以便与 dladdr(3C) 一起使用。
仅当 .dynsym 表存在时,才存在 .SUNW_ldynsym 表。当 .SUNW_ldynsym 节和 .dynsym 节同时存在时,链接编辑器会将其数据区域紧邻彼此放置,其中 .SUNW_ldynsym 放置在前面。这种放置方式可以使两个表看起来像是一个更大的连续符号表。此符号表遵从先前枚举的标准布局规则。
.SUNW_ldynsym 表可以通过使用链接编辑器的 -z noldynsym 选项进行消除。
由相邻的 .SUNW_ldynsym 节和 .dynsym 节构成的动态符号表可用于将内存地址映射到其对应的符号。这种映射可用于确定给定地址表示哪个函数或变量。但是,按照符号写入符号表的顺序分析符号表以确定映射是很复杂的。请参见符号表布局和约定。此布局使地址与符号名称之间的关联变得复杂,具体表现在以下几个方面。
符号不是按地址排序的,这将强制对整个表进行线性搜索,从而增大开销。
可能有多个符号指向给定地址。尽管这些符号均有效且正确,但调试工具应选择使用这些等效名称中的哪一个可能并不明确。不同的工具可能会使用不同的备用名称。这些问题可能会给用户带来困惑。
许多符号提供无地址信息。搜索时不应考虑这类符号。
符号排序节就是用于解决这些问题的。符号排序节是 Elf32_Word 或 Elf64_Word 目标文件的数组。此数组中的每个元素都是 .SUNW_ldynsym – .dynsym 组合的符号表的索引。对数组中的元素进行排序,从而使引用的符号也按照排好的顺序提供。其中仅包含表示函数或变量的符号。使用 elfdump(1) 和 -S 选项来显示与排序数组关联的符号。
不能同时排序常规符号和线程局部存储符号。常规符号的值是符号所引用的函数或变量的地址。线程局部存储符号的值是变量的线程偏移。因此,常规符号和线程局部存储符号使用两种不同的排序节。
SHT_SUNW_SYMSORT 类型的节(其中包含 .SUNW_ldynsym – .dynsym 组合符号表中常规符号的索引)按照地址进行排序。不表示变量或函数的符号不包括在内。
SHT_SUNW_TLSSORT 类型的节(其中包含 .SUNW_ldynsym – .dynsym 组合符号表中 TLS 符号的索引)按照偏移进行排序。仅当目标文件包含 TLS 符号时会生成此节。
链接编辑器按照显示的顺序使用以下规则来选择排序节引用的符号。
符号必须具有函数或变量类型:STT_FUNC、STT_OBJECT、STT_COMMON 或 STT_TLS。
以下符号如果存在,则始终包含在内:_DYNAMIC、_end、_fini、_GLOBAL_OFFSET_TABLE_、_init、_PROCEDURE_LINKAGE_TABLE_ 和 _start。
如果全局符号和弱符号引用同一个项,则会包含弱符号而排除全局符号。
符号必须已定义。
符号的大小不得为零。
这些规则可筛选出由编译器自动生成以及由链接编辑器生成的符号。所选择的符号是用户关注的符号。然而,在两种情况下可能需要手动干预来改进选择过程。
规则未能选择所需的特殊符号。例如,某些特殊符号大小为零。
选择了不需要的多余符号。例如,共享目标文件可以定义引用相同地址并且大小相同的多个符号。这些别名符号均有效地引用相同的项。您可能希望在排序节中仅包含多符号系列中的一个。
mapfile 的关键字 DYNSORT 和 NODYNSORT 可以为符号选择提供更多的控制。请参见SYMBOL_SCOPE / SYMBOL_VERSION 指令。
例如,目标文件可能会提供以下符号表定义。
$ elfdump -sN.symtab foo.so.1 | egrep "foo$|bar$" [37] 0x000004b0 0x0000001c FUNC GLOB D 0 .text bar [38] 0x000004b0 0x0000001c FUNC WEAK D 0 .text foo
符号 foo 和 bar 表示一个别名对。缺省情况下,创建排序数组时,仅表示符号 foo。
$ cc -o foo.so.1 -G foo.c $ elfdump -S foo.so.1 | egrep "foo$|bar$" [13] 0x000004b0 0x0000001c FUNC WEAK D 0 .text foo
如果链接编辑器发现一个全局符号和一个弱符号引用同一个项,通常会保留弱符号。因为与弱符号 foo 之间的关联,将从存储数组中省略符号 bar。
以下 mapfile 会导致在排序数组中表示符号 bar。忽略了符号 foo。
$ cat mapfile { global: bar = DYNSORT; foo = NODYNSORT; }; $ cc -M mapfile -o foo.so.2 -Kpic -G foo.c $ elfdump -S foo.so.2 | egrep "foo$|bar$" [13] 0x000004b0 0x0000001c FUNC GLOB D 0 .text bar
.SUNW_dynsymsort 节和 .SUNW_dyntlssort 节,要求 .SUNW_ldynsym 节存在。因此,使用 -z noldynsym 选项还会阻止创建任何排序节。
SPARC 体系结构支持寄存器符号,这些符号用于初始化全局寄存器。下表中列出了寄存器符号的符号表项包含的各项。
表 12-23 SPARC: ELF 符号表项:寄存器符号
|
下表中列出了为 SPARC 定义的寄存器值。
表 12-24 SPARC: ELF 寄存器编号
|
如果缺少特定全局寄存器的项,则意味着目标文件根本没有使用特定全局寄存器。