由相邻的 .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] 0x4b0 0x1c FUNC GLOB D 0 .text bar [38] 0x4b0 0x1c 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] 0x4b0 0x1c FUNC WEAK D 0 .text foo
如果链接编辑器发现一个全局符号和一个弱符号引用同一个项,通常会保留弱符号。排序数组中忽略符号 bar 是因为与弱符号 foo 之间的关联。
以下 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] 0x4b0 0x1c FUNC GLOB D 0 .text bar
.SUNW_dynsymsort 节和 .SUNW_dyntlssort 节,要求 .SUNW_ldynsym 节存在。因此,使用 –z noldynsym 选项还会阻止创建任何排序节。