本文目录 6 个章节
ELF文件-符号表与符号可见性
# ELF文件-符号表与符号可见性
符号表
.symtab是静态符号表,包含了所有符号(包括调试符号),用于静态链接。.dynsym是动态符号表,包含了动态链接需要的符号,用于运行时符号解析。
.symtab (静态)符号表
.symtab 是 ELF 文件中的符号表,包含了程序或库中所有的符号信息,包括函数、全局变量等。它通常用于静态链接和调试。符号表包含符号的名称、地址、类型等信息,并且支持调试信息和符号的重定位。
- 内容:
- 符号的名称。
- 符号的地址(如果已知)。
- 符号的类型和绑定信息(例如,是否是函数、变量等)。
- 符号的段或节(例如,
.text、.data)。
- 内容:
- 用途:
- 静态链接:编译器和链接器会通过
.symtab来解析符号,进行符号重定位。 - 调试:
.symtab保存了符号信息和调试信息,使得调试器能够读取符号名称、源代码行号等信息。
- 静态链接:编译器和链接器会通过
- 特点:
- 包含所有符号的详细信息。
- 静态链接时使用。
- 可以包含调试信息。
$ readelf -s my_program.o
列出 .symtab 中的符号信息。
.dynsym(动态符号表)
.dynsym 是 ELF 文件中的动态符号表,专门用于动态链接。它只包含程序运行时需要解析的符号,通常用于动态链接(即共享库)。.dynsym 中的符号不包含调试信息和一些其他的静态符号信息,它包含的是在运行时需要查找和链接的符号。
- 内容:
- 符号的名称(存储在
.dynstr字符串表中)。 - 符号的类型、地址(通常在运行时解析)。
- 符号的绑定信息(如共享库的符号)。
- 符号的名称(存储在
- 用途:
- 动态链接:当程序需要加载共享库时,动态链接器会通过
.dynsym来查找符号,完成符号的解析和链接。 - 符号解析:动态加载时,
.dynsym中的符号会被动态链接器处理,确保外部函数和变量的调用能够正确映射。
- 动态链接:当程序需要加载共享库时,动态链接器会通过
- 特点:
- 只包含动态链接所需的符号。
- 不包含调试信息。
- 仅用于动态链接时解析符号。
$ readelf -sW my_program.so
列出 .dynsym 中的符号信息。
函数名称修饰
extern "C":禁用名称修饰
让 C++ 符号变得与 C 符号一样,不会进行名称修饰,这样在不同语言间(如 C/C++、Java)进行调用时,可以确保符号一致性,避免因名称修饰导致的链接错误。
在 C++ 中,函数名称通常会被编译器名称修饰(name mangling)以支持函数重载等特性。extern "C" 是一种指示编译器使用 C 的链接方式,禁止对符号进行名称修饰,使得 C++ 编译器生成的符号与 C 编译器一样,保持简单的函数名。
__attribute__((visibility("default"))):控制符号的可见性
__attribute__((visibility("default"))) 用于控制符号在共享库中的可见性。它告诉编译器将符号暴露给外部程序或库,使得该符号可被动态链接器找到。
默认情况下,C++ 编译器会将符号标记为“隐藏”(“hidden”),这意味着只有定义它的模块内部可以访问该符号。
通过 visibility("default"),符号将变为“公共的”,可以被其他程序链接和使用。
- 对于动态链接的库,只有可见的符号(标记为
default)会被添加到动态符号表(.dynsym)中,这些符号可以被外部程序或其他共享库引用和解析。
- 如果符号的可见性是
hidden,则该符号不会出现在动态符号表中,其他程序无法通过动态链接找到该符号。