关于动态符号表及“全局符号表”

elf.h中对符号表的类型定义如下:
#define DT_STRTAB 5 /* Address of string table */
#define DT_SYMTAB 6 /* Address of symbol table */

这里DT_SYMTAB与DT_STRTAB对应的section其实是.dynsym和.dynstr,而非.symtab和.symstr!

.symtab和.dynsym两个不同的symbol table, 它们有什么区别?
.dynsym是.symtab的一个子集, 为什么要两个信息重合的结构?
需要先了解allocable/non-allocable ELF section, ELF文件包含一些sections(如code和data)是在运行时需要的, 这些sections被称为allocable; 而其他一些sections仅仅是linker,debugger等工具需要, 在运行时并不需要, 这些sections被称为non-allocable的. 当linker构建ELF文件时, 它把allocable的数据放到一个地方, 将non-allocable的数据放到其他地方. 当OS加载ELF文件时, 仅仅allocable的数据被映射到内存, non-allocable的数据仍静静地呆在文件里不被处理. strip就是用来移除某些non-allocable sections的.
.symtab包含大量linker,debugger需要的数据, 但并不为runtime必需, 它是non-allocable的; .dynsym包含.symtab的一个子集, 比如共享库所需要在runtime加载的函数对应的symbols, 它世allocable的.
因此, 得到答案:
1. strip移除的应是.symtab.
2. nm读取的应是.symtab: 上面发现的libattr等nm结果为空, libpthread nm结果非空应是正常的. 3. 共享库包含的.dynsym是runtime必需的, 是allocable的.

另外,很多资料上经常用到的一个概念是“全局符号表“,其实这是一个伪概念,内存中并不存在这样一个表,libdl中会将所有已加载到内存中的可执行模块(主程序或动态库)的相关指针放入一个全局的链表中,通过这个全局链表可以访问到所有可执行模块的动态符号表,仅此而以。我们可以假定这个全局链表是一个“全局符号表“,但其存储的内容远远不止符号表这么简单,而是可执行模块的所有相关信息,如重定位信息、代码段地址、got段地址等。

例子:
[lubo@localhost src]$ mipsel-linux-readelf -S main.elf
There are 42 section headers, starting at offset 0xef4:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 00400154 000154 000014 00 A 0 0 1
[ 2] .reginfo MIPS_REGINFO 00400168 000168 000018 18 A 0 0 4
[ 3] .dynamic DYNAMIC 00400180 000180 000110 08 A 6 0 4
[ 4] .hash HASH 00400290 000290 0000a4 04 A 5 0 4
[ 5] .dynsym DYNSYM 00400334 000334 000160 10 A 6 1 4
[ 6] .dynstr STRTAB 00400494 000494 00010a 00 A 0 0 1
[ 7] .gnu.version VERSYM 0040059e 00059e 00002c 02 A 5 0 2
[ 8] .gnu.version_r VERNEED 004005cc 0005cc 000020 00 A 6 1 4
[ 9] .rel.plt REL 004005ec 0005ec 000018 08 A 5 11 4
[10] .init PROGBITS 00400604 000604 000048 00 AX 0 0 4
[11] .plt PROGBITS 00400660 000660 000050 00 AX 0 0 32
[12] .text PROGBITS 004006b0 0006b0 000240 00 AX 0 0 16
[13] .MIPS.stubs PROGBITS 004008f0 0008f0 000020 00 AX 0 0 4
[14] .fini PROGBITS 00400910 000910 000038 00 AX 0 0 4
[15] .eh_frame_hdr PROGBITS 00400948 000948 000014 00 A 0 0 4
[16] .eh_frame PROGBITS 0041095c 00095c 000030 00 WA 0 0 4
[17] .ctors PROGBITS 0041098c 00098c 000008 00 WA 0 0 4
[18] .dtors PROGBITS 00410994 000994 000008 00 WA 0 0 4
[19] .jcr PROGBITS 0041099c 00099c 000004 00 WA 0 0 4
[20] .data PROGBITS 004109a0 0009a0 000010 00 WA 0 0 16
[21] .rld_map PROGBITS 004109b0 0009b0 000004 00 WA 0 0 4
[22] .got.plt PROGBITS 004109b4 0009b4 000014 00 WA 0 0 4
[23] .got PROGBITS 004109d0 0009d0 00000c 04 WAp 0 0 16
[24] .sdata PROGBITS 004109dc 0009dc 000004 00 WAp 0 0 4
[25] .bss NOBITS 004109e0 0009e0 000020 00 WA 0 0 16
[26] .pdr PROGBITS 00000000 0009e0 000080 00 0 0 4
[27] .comment PROGBITS 00000000 000a60 000038 01 MS 0 0 1
[28] .debug_aranges MIPS_DWARF 00000000 000a98 000020 00 0 0 1
[29] .debug_pubnames MIPS_DWARF 00000000 000ab8 00001b 00 0 0 1
[30] .debug_info MIPS_DWARF 00000000 000ad3 0000cc 00 0 0 1
[31] .debug_abbrev MIPS_DWARF 00000000 000b9f 00006a 00 0 0 1
[32] .debug_line MIPS_DWARF 00000000 000c09 000040 00 0 0 1
[33] .debug_frame MIPS_DWARF 00000000 000c4c 00002c 00 0 0 4
[34] .debug_str MIPS_DWARF 00000000 000c78 0000a5 01 MS 0 0 1
[35] .debug_loc MIPS_DWARF 00000000 000d1d 00002c 00 0 0 1
[36] .debug_pubtypes MIPS_DWARF 00000000 000d49 000012 00 0 0 1
[37] .gnu.attributes LOOS+ffffff5 00000000 000d5b 000010 00 0 0 1
[38] .mdebug.abi32 PROGBITS 00000030 000d6b 000000 00 0 0 1
[39] .shstrtab STRTAB 00000000 000d6b 000186 00 0 0 1
[40] .symtab SYMTAB 00000000 001584 000540 10 41 63 4
[41] .strtab STRTAB 00000000 001ac4 00022c 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
从此处看出,symtab和strtab并没有被加载到内存中。
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在 Linux ELF(可执行与可链接格式)中,有两个相关的符号表:静态符号表动态符号表。它们与程序运行时的函数符号表有以下关系: 1. 静态符号表:静态符号表是在编译时由编译器创建的一张符号表,它包含了可执行文件中的所有符号信息,包括函数、全局变量、局部变量等。静态符号表记录了符号的名称、类型、地址等信息。它在链接过程中用于解析符号的引用关系,以确定符号的最终地址。 2. 动态符号表动态符号表是在运行时由动态链接器(如 ld.so)创建的一张符号表,它包含了可执行文件中需要在运行时解析的动态符号信息,如共享库中的函数和变量。动态符号表记录了符号的名称、类型、地址等信息。它用于在程序运行时进行动态链接,将程序与共享库中的符号关联起来。 3. 函数符号表:函数符号表是在程序运行时动态生成的,用于记录程序当前可见的函数符号及其地址。这个表主要由动态链接器和调试器使用,用于调试目的或者在运行时查找函数地址。 静态符号表动态符号表都记录了程序中的符号信息,但它们的使用方式和目的略有不同。静态符号表用于链接过程,解析符号引用关系以确定符号的地址。动态符号表用于动态链接过程,在程序运行时将符号与共享库中的实际地址关联起来。函数符号表则是在程序运行时动态生成的,用于调试和查找函数地址。 需要注意的是,函数符号表是一个在运行时动态生成和维护的结构,它的具体实现可能会因操作系统、编译器、调试器等因素而有所不同。以上是一般情况下的概述,具体实现细节可能会有所差异。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值