当前位置: 首页 > article >正文

gcc符号表生成机制

符号表生成机制

我们以C语言的编译链接过程为例,详细讲解符号表(Symbol Table)的流程,涵盖编译和链接两个阶段。理解符号表是理解链接器如何解决符号引用(如函数、变量)的关键。

符号表分为两种:

  • 目标文件(.o文件)中的符号表:由编译器生成,记录该文件内定义和引用的符号。
  • 可执行文件或共享库中的符号表:由链接器生成,包含所有合并后的符号信息。

流程分为四个阶段:预处理、编译、汇编、链接。符号表主要在编译(生成汇编代码)和汇编(生成目标文件)阶段创建,在链接阶段被合并和解析。

存在
不存在
已定义
未定义
源代码
编译阶段
符号声明
添加到符号表
符号引用
检查符号表
标记为已解析
记录为未定义符号
生成目标文件
链接阶段
收集所有目标文件符号
检查所有符号
地址重定位
查找静态库/共享库
是否找到定义
链接到可执行文件
链接错误
生成可执行文件

1. 第一步:编译阶段(生成目标文件)

当我们编译一个源文件(如main.c)时:

gcc -c main.c -o main.o

编译器(如GCC)会进行以下操作:

  1. 语法分析、语义分析、中间代码生成、优化等。
  2. 生成汇编代码(main.s)。
  3. 汇编器将汇编代码翻译成机器指令(目标文件main.o)。

目标文件(main.o)的组成(以ELF格式为例):

名称作用
.text段存放代码(函数体)。
.data段存放已初始化的全局变量。
.bss段存放未初始化的全局变量(预留位置,不占磁盘空间)。
.symtab符号表,记录本文件中定义和引用的符号信息。

符号表包含以下信息:

名称作用
符号名(name)符号的唯一标识
符号值(value)对于函数和变量,表示其在相应段内的偏移地址(暂时,在链接前是0或相对偏移)。
大小(size)
类型(type)例如数据(变量)、函数、未定义等。
绑定信息(binding)全局(global)或局部(local)。
所在段(section)符号属于哪个段(text/data/bss),未定义的符号标记为UND。

例如,假设main.c中有如下代码:

extern int external_var; // 声明外部变量
int global_var = 10; // 全局变量,初始化,位于.data段
static int static_var; // 静态变量,未初始化,位于.bss段,且是local符号
void external_func(); // 声明外部函数int main() {
static_var = 1;
external_func();
return 0;
}

那么main.o的符号表中会有以下重要条目:

  • global_var:类型为数据(object),在.data段,全局(global),value为0(待重定位)。
  • static_var:类型为数据,在.bss段,局部(local),value为0。
  • main:类型为函数(FUNC),在.text段,全局(global),value为0。
  • external_var:类型为未定义(UND),全局(global)。
  • external_func:类型为未定义(UND),全局(global)。

2. 第二步:链接阶段

当我们链接多个目标文件(例如还有func.o)生成可执行文件时:

gcc main.o func.o -o program

链接器(ld)的工作:

  1. 合并所有目标文件中的段(.text合并到.text,.data合并到.data等)。
  2. 符号解析:将所有目标文件的符号表合并为一个全局符号表,并解决符号引用。

符号解析过程:

  • 链接器扫描所有目标文件,构建一个全局符号表。
  • 对于每个未定义的符号,在全局符号表中查找是否有定义。
  • 如果找到,则将引用指向该定义(在合并段中的地址)。
  • 如果找不到,则报错:undefined reference to …。

例如,假设func.c中有:

int external_var = 100; // 定义external_var
void external_func() { // 定义external_func
}

则func.o的符号表中有:

  • external_var:全局,定义在.data段。
  • external_func:全局,定义在.text段。
    链接器在合并时会:

将main.o中未定义的external_var和external_func解析到func.o中的定义。
同时,在合并段后,重新计算每个符号在最终可执行文件中的地址(即重定位)。

3. 第三步:重定位

链接器在完成符号解析后,还要修改代码段和数据段中对这些符号的引用地址(因为在合并段后,符号的地址发生了变化)。这一步由重定位表(.rel.text, .rel.data)指导完成。

重定位表(在目标文件中)记录了哪些位置需要重定位(即引用了外部符号的位置)。例如,在main.o中,调用external_func()的汇编指令中有一个占位符(地址为0)。链接器根据重定位表将该位置修改为external_func在最终可执行文件中的实际地址。

4. 第四步:生成可执行文件

链接器输出一个可执行文件(如ELF格式),其中包含:

  • 所有段(.text, .data等)的合并内容。
  • 符号表(通常可执行文件中的符号表可以被去除以减小体积,但若使用-g选项则保留)。
  • 其他信息(重定位信息在可执行文件中不再需要,因为地址已固定,但动态链接信息除外)。

动态链接的符号解析与静态链接不同:

  • 静态链接在链接阶段完全解析符号(ld直接解析了)。
  • 动态链接在运行时由动态链接器(ld-linux.so)完成解析。

例如,如果我们在程序中使用了动态库(如libc.so)中的函数,在链接阶段,链接器只记录该函数在动态库中的符号名,并不解析具体地址。在可执行文件中,这些符号被标记为动态符号(在.dynsym节中),并且需要重定位表(.rel.plt, .rel.dyn)在运行时进行重定位。

5. 总结:

符号表的流程:

  1. 编译阶段:每个源文件编译成目标文件,生成局部符号表。
  2. 链接阶段:
    • 合并所有目标文件的段。
    • 合并符号表,进行符号解析(将未定义的符号绑定到定义的地方)。
    • 重定位:根据新的段布局修改符号引用的地址(利用重定位表)。
    • 输出可执行文件或共享库。

通过这个流程,链接器确保了程序中的所有符号引用都有唯一的定义,并位于正确的地址。

符号检查工具

# 查看目标文件符号
nm target.o# 详细符号信息
readelf -s target.o# 检查未定义符号
nm -u target.o# 显示动态符号表
readelf --dyn-syms program# 查看符号版本
objdump -T libc.so.6 | grep memcpy# 详细链接日志
ld --verbose# 跟踪链接过程
LD_DEBUG=all ./program# 重定位表检查
readelf -r program.o
​​场景​​​​示例错误信息​​ ​​原因​​
函数未定义undefined reference to ‘func()’函数声明存在,但无实现代码
函数签名不匹配undefined reference to ‘func(int)’声明与定义的参数类型/数量不一致
库文件未链接unresolved external symbol依赖的静态库未加入链接命令
C/C++ 混合编程未处理?func@@YAHHH@Z(名称修饰不一致)未用 extern “C” 声明 C 函数

相关文章:

gcc符号表生成机制

符号表生成机制 我们以C语言的编译链接过程为例,详细讲解符号表(Symbol Table)的流程,涵盖编译和链接两个阶段。理解符号表是理解链接器如何解决符号引用(如函数、变量)的关键。 符号表分为两种&#xff…...

达梦数据库 Windows 系统安装教程

🧑 博主简介:CSDN博客专家、CSDN平台优质创作者,高级开发工程师,数学专业,10年以上C/C, C#, Java等多种编程语言开发经验,拥有高级工程师证书;擅长C/C、C#等开发语言,熟悉Java常用开…...

unix/linux source 命令,其基本概念、定义、性质、定理

从计算机科学的角度,特别是形式语言、操作系统和编程语言设计的角度来看,source (或 .) 命令虽然看似简单,但其背后也蕴含着一些核心的概念、定义、性质和可以类比的“定理”(或者说,更准确地是“设计原则”或“行为模式”)。 让我们尝试从一个更理论和结构化的视角来剖…...

【Java EE初阶】计算机是如何⼯作的

计算机是如何⼯作的 计算机发展史冯诺依曼体系(Von Neumann Architecture)CPU指令(Instruction)CPU 是如何执行指令的(重点) 操作系统(Operating System)进程(process) 进程 PCB 中的…...

RAG理论基础总结

目录 概念 流程 文档收集和切割 读取文档 转换文档 写入文档 向量转换和存储 搜索请求构建 向量存储工作原理 向量数据库 文档过滤和检索 检索前 检索 检索后 查询增强和关联 QuestionAnswerAdvisor查询增强 高级RAG架构 自纠错 RAG(C-RAG&#xf…...

列表推导式(Python)

[表达式 for 变量 in 列表] 注意:in后面不仅可以放列表,还可以放range ()可迭代对象 [表达式 for 变量 in 列表 if 条件]...

嵌入式RTC工作原理及应用场景

20ppm 是衡量 RTC(实时时钟)精度的关键指标,表示 每百万秒(约11.57天)的最大时间误差范围。以下是通俗易懂的解释: 1. ppm 的含义 ppm Parts Per Million(百万分之一) 1 ppm 1/1,…...

一天搞懂深度学习--李宏毅教程笔记

目录 1. Introduction of Deep Learning1.1. Neural Network - A Set of Function1.2. Learning Target - Define the goodness of a function1.3. Learn! - Pick the best functionLocal minimaBackpropagation 2. Tips for Training Deep Neural Network3. Variant of Neural…...

Go语言常见接口设计技巧-《Go语言实战指南》

在 Go 中,接口是连接代码组件的桥梁。合理设计接口可以大幅提升程序的可维护性、可扩展性和测试友好性。本章将分享 Go 开发中常见的接口设计技巧与最佳实践。 一、接口设计原则 1. 面向接口编程,而非面向实现编程 尽量使用接口类型作为函数参数或返回值…...

python打卡训练营打卡记录day43

复习日 作业: kaggle找到一个图像数据集,用cnn网络进行训练并且用grad-cam做可视化 进阶:并拆分成多个文件 数据集来源:Flowers Recognition 选择该数据集原因: 中等规模:4242张图片 - 训练快速但足够展示效…...

Camera相机人脸识别系列专题分析之十一:人脸特征检测FFD算法之低功耗libvega_face.so人脸属性(年龄,性别,肤色,微笑,种族等)检测流程详解

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:Camera相机人脸识别系列专题分析之十:人脸特征检测FFD算法之低功耗libvega_face.so人脸识别检测流程详解 这一篇我们开始讲: Camera相机人脸识别系列专题分析之十一:人脸特征检测FFD算法之低功耗lib…...

解决:输入SSH后,仍无法通过网址登录以及紧接着的新问题Permission denied(publickey,password).

现象: 管理员: Windows PowerShell输入SSH后,仍无法通过网址登录 例如输入你的ssh命令:ssh -CNg -L xxxx:127.0.0.1:xxxx rootaaaaaaaaa.com -p yyyyy 得到终端提示:ssh无法识别为 cmdlet、函数、脚本文件或可运行程序的名称。 解…...

【QT控件】QWidget 常用核心属性介绍 -- 万字详解

目录 一、控件概述 二、QWidget 核心属性 2.1 核心属性概览 2.2 enabled ​编辑 2.3 geometry 2.4 windowTitle 2.5 windowIcon 使用qrc文件管理资源 2.6 windowOpacity 2.7 cursor 2.8 font ​编辑 2.9 toolTip 2.10 focusPolicy 2.11 styleSheet QT专栏&…...

uniapp-商城-77-shop(8.2-商品列表,地址信息添加,级联选择器picker)

地址信息,在我们支付订单上有这样一个接口,就是物流方式,一个自提,我们就显示商家地址。一个是外送,就是用户自己填写的地址。 这里先说说用户的地址添加。需要使用到的一些方式方法,主要有关于地址选择器,就是uni-data-picker级联选择。 该文介绍了电商应用中地址信息处…...

HTTPS加密通信详解及在Spring Boot中的实现

HTTPS(Hyper Text Transfer Protocol Secure)是HTTP的安全版本,通过SSL/TLS协议为通讯提供加密、身份验证和数据完整性保护。 一、HTTPS核心原理 1.加密流程概述 客户端发起HTTPS请求(连接到服务器443端口)服务器返…...

如何让 Git 停止跟踪文件?停止后又如何恢复跟踪?

在使用 Git 管理代码时,有时我们希望某些文件不再被 Git 跟踪(比如本地配置文件、临时文件等),但保留这些文件在本地;过了一段时间,可能又需要恢复跟踪这些文件。本文将用通俗易懂的语言,教你如…...

【第16届蓝桥杯 | 软件赛】CB组省赛第二场

个人主页:Guiat 归属专栏:算法竞赛 文章目录 A. 密密摆放(5分填空题)B. 脉冲强度之和(5分填空题)C. 25 之和D. 旗帜E. 数列差分F. 树上寻宝G. 翻转硬币H. 破解信息 正文 总共8道题。 A. 密密摆放&#xff0…...

SQL进阶之旅 Day 10:执行计划解读与优化

【SQL进阶之旅 Day 10】执行计划解读与优化 开篇 今天是我们的"SQL进阶之旅"系列的第10天,我们将深入探讨SQL执行计划的解读与优化技巧。随着数据库规模的增长和业务复杂度的提升,理解SQL语句在数据库引擎中的执行过程变得至关重要。 执行计…...

AR/MR实时光照阴影开发教程

一、效果演示 1、PICO4 Ultra MR 发光的球 2、AR实时光照 二、实现原理 PICO4 Ultra MR开发时,通过空间网格能力扫描周围环境,然后将扫描到的环境网格材质替换为一个透明材质并停止扫描;基于Google ARCore XR Plugin和ARFoundation进行安卓手…...

Visual studio 中.sln/.vcxproj/.vcxproj.filters和.vcxproj.user文件的作用

在 Visual Studio (尤其是 C 项目) 中,.sln、.vcxproj、.vcxproj.filters 和 .vcxproj.user 文件各自承担着不同的关键角色。理解它们的作用对于项目管理和协作至关重要。 核心原则: .vcxproj 和 .sln 是项目/解决方案的核心定义文件,必须纳…...

【汽车电子入门】一文了解LIN总线

前言:LIN(Local Interconnect Network)总线,也就是局域互联网的意思,它的出现晚于CAN总线,于20世纪90年代末被摩托罗拉、宝马、奥迪、戴姆勒、大众以及沃尔沃等多家公司联合开发,其目的是提供一…...

JVM学习(七)--JVM性能监控

目录 一、JVM性能监控 1、JVM监控及诊断工具-命令行篇 2、JVM监控及诊断工具-GUI篇 3、JVM运行时参数 一、JVM性能监控 1、JVM监控及诊断工具-命令行篇 面试题: 1、你使用过Java虚拟机性能监控和故障处理工具吗? 2、怎么打出线程栈信息。 3、怎么获取 Jav…...

关于 java:5. Java IO 与文件操作

一、File 类(读取文件属性) 1.1 java.io.File 类概述 File 是 Java IO 中的核心类,用于表示文件或目录的路径名。 它是一个抽象路径名,可以表示实际存在或不存在的文件/文件夹。 File 类提供了创建、删除、重命名、判断属性、获…...

【笔记】为 Python 项目安装图像处理与科学计算依赖(MINGW64 环境)

📝 为 Python 项目安装图像处理与科学计算依赖(MINGW64 环境) 🎯 安装目的说明 本次安装是为了在 MSYS2 的 MINGW64 工具链环境中,搭建一个完整的 Python 图像处理和科学计算开发环境。 主要目的是支持以下类型的 Pyth…...

【笔记】MLA矩阵吸收分析

文章目录 一、张量运算的计算量1. FLOPs定义2. 张量计算顺序对计算量的影响 二、MLA第一次矩阵吸收的计算量分析1. 原始注意力计算2. MLA源代码中的吸收方式3. 提前吸收4. 比较分析4.1 比较顺序1和顺序24.2 比较顺序2和顺序3 三、MLA第二次矩阵吸收的计算量分析1. 原始输出计算…...

600+纯CSS加载动画一键获取指南

CSS-Loaders.com 完整使用指南:600纯CSS加载动画库 🎯 什么是 CSS-Loaders.com? CSS-Loaders.com 是一个专门提供纯CSS加载动画的资源网站,拥有超过600个精美的单元素加载器。这个网站的最大特色是所有动画都只需要一个HTML元素…...

开源的JT1078转GB28181服务器

JT1078转GB28181流程 项目地址: JT1078转GB28181的流媒体服务器: https://github.com/lkmio/lkm JT1078转GB28181的信令服务器: https://github.com/lkmio/gb-cms 1. 创建GB28181 UA 调用接口: http://localhost:9000/api/v1/jt/device/add 请求体如下&#xf…...

智能守护电网安全:探秘输电线路测温装置的科技力量

在现代电力网络的庞大版图中,输电线路如同一条条 “电力血管”,日夜不息地输送着能量。然而,随着电网负荷不断增加,长期暴露在户外的线路,其线夹与导线在电流热效应影响下,极易出现温度异常。每年因线路过热…...

Java垃圾回收算法及GC触发条件

一、引言 在Java编程语言的发展历程中,内存管理一直是其核心特性之一。与C/C等需要手动管理内存的语言不同,Java通过自动垃圾回收(Garbage Collection,简称GC)机制,极大地减轻了开发人员的负担&#xff0c…...

【Hot 100】118. 杨辉三角

目录 引言杨辉三角我的解题代码优化优化说明 🙋‍♂️ 作者:海码007📜 专栏:算法专栏💥 标题:【Hot 100】118. 杨辉三角❣️ 寄语:书到用时方恨少,事非经过不知难! 引言 …...