---
title: "ELF文件-符号表与符号可见性"
author: "Perrin Yong"
author_profile: https://www.pystone.net/profile/
published_by: "Perrin Yong"
canonical: https://www.pystone.net/notes/elf-symbol-table-visibility/
type: note
content_role: unspecified
visibility: public
id_stability: rename-stable
source_path: "10-计算机、信息技术与工程/02-编程语言与运行时/ELF文件-符号表与符号可见性.md"
content_hash: 1a7449482c68d74b85f88178ac8e44014ec80728379956539c7a4547d7bba628
knowledge_version: 224c990773de.5fa8af6e39fa
site_commit: 224c990773de166d23a886306577dd90379529ce
notes_commit: 5fa8af6e39fa3891d1b9b4832bfa6c4e0ecaaf0a
---
# ELF文件-符号表与符号可见性

﻿# ELF文件-符号表与符号可见性

## 符号表
- `.symtab` 是静态符号表，包含了所有符号（包括调试符号），用于静态链接。
- `.dynsym` 是动态符号表，包含了动态链接需要的符号，用于运行时符号解析。

#### **`.symtab` （静态）符号表**
`.symtab` 是 ELF 文件中的符号表，包含了程序或库中所有的符号信息，包括函数、全局变量等。它通常用于**静态链接**和**调试**。符号表包含符号的名称、地址、类型等信息，并且支持调试信息和符号的重定位。
- - **内容**：
	- 符号的名称。
	- 符号的地址（如果已知）。
	- 符号的类型和绑定信息（例如，是否是函数、变量等）。
	- 符号的段或节（例如，`.text`、`.data`）。
- **用途**：
	- 静态链接：编译器和链接器会通过 `.symtab` 来解析符号，进行符号重定位。
	- 调试：`.symtab` 保存了符号信息和调试信息，使得调试器能够读取符号名称、源代码行号等信息。
- **特点**：
	- 包含所有符号的详细信息。
	- 静态链接时使用。
	- 可以包含调试信息。

```bash
$ readelf -s my_program.o
```
列出 `.symtab` 中的符号信息。

#### **`.dynsym`（动态符号表）**

`.dynsym` 是 ELF 文件中的动态符号表，专门用于动态链接。它只包含程序运行时需要解析的符号，通常用于**动态链接**（即共享库）。`.dynsym` 中的符号不包含调试信息和一些其他的静态符号信息，它包含的是在运行时需要查找和链接的符号。

- **内容**：
    - 符号的名称（存储在 `.dynstr` 字符串表中）。
    - 符号的类型、地址（通常在运行时解析）。
    - 符号的绑定信息（如共享库的符号）。
- **用途**：
    - 动态链接：当程序需要加载共享库时，动态链接器会通过 `.dynsym` 来查找符号，完成符号的解析和链接。
    - 符号解析：动态加载时，`.dynsym` 中的符号会被动态链接器处理，确保外部函数和变量的调用能够正确映射。
- **特点**：
    - 只包含动态链接所需的符号。
    - 不包含调试信息。
    - 仅用于动态链接时解析符号。

```bash
$ 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`，则该符号不会出现在动态符号表中，其他程序无法通过动态链接找到该符号。
