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

类成员函数编译链接的过程

1.静态成员函数和普通成员函数

源文件编译成目标文件,静态成员函数和普通成员函数在目标文件代码段,函数添加进了符号表,地址是在代码段的相对地址,这个地址只是一个临时地址因为后面链接时还要合并代码段,函数地址还要变,然后链接合并目标文件,代码段合并后静态成员函数和普通成员函数固定了,修改符号表中的函数地址,最后靠重定位表修改代码段和数据段里函数调用的地址,就完了

2.虚函数

源文件编译成目标文件,虚函数在目标文件代码段,并且虚函数添加进了符号表,地址是在代码段的相对地址,这个地址只是一个临时地址因为后面链接时还要合并代码段,函数地址还要变,虚函数表创建好在只读数据区,函数地址和符号表一样是临时地址。然后链接合并目标文件,代码段合并后虚函数固定了,修改符号表中的函数地址,修改虚函数表里的函数地址,只读数据段合并后虚函数表固定了,向构造函数中添加虚函数表指针的硬编码指令,最后靠重定位表修改代码段和数据段里函数调用的地址,就完了

ps:虚基表过程同虚函数表,不过虚基表的内容在编译时就已经确定,只需要在链接合并只读数据段虚基表固定了,往构造函数添加虚基表指针的硬编码即可

下面是AI生成的理解

1. 重定位的核心作用

重定位 不修改符号表,而是修正 代码段(.text)和数据段(.data)中对符号的引用地址。符号表的更新是链接过程的副产品,而非重定位的直接目标。

(1) 符号表的角色
  • 编译阶段:记录符号名称、类型(函数/变量)和 临时地址(目标文件内部的偏移量)。

  • 链接阶段:链接器分配最终地址后,符号表中的地址会被更新,但 符号表本身不参与运行时执行

(2) 重定位的真实行为
  • 修正目标:代码段中的 call 指令、数据段中的指针等 对符号的引用

  • 操作方式:根据重定位表(.rel.text/.rel.data)的指示,将临时占位符替换为最终地址。


2. 具体流程示例

假设有两个文件:

// a.cpp
void foo(); // 声明
int main() { foo(); }  // 编译为:call 0x00000000(需重定位)// b.cpp
void foo() {} // 定义(临时地址0x00000010)
(1) 编译后目标文件的状态
  • a.o 的符号表

    _Z3foov: UND (未定义)     // 声明
    main: T (定义在.text段)   // 地址 0x00000000
  • a.o 的重定位表

    OFFSET=0x00000005, TYPE=R_X86_64_PC32, SYMBOL=_Z3foov

    call 指令的操作数位于 main 函数偏移 0x05 处)

(2) 链接时的操作
  1. 合并段:将 a.o 和 b.o 的 .text 段合并,假设:

    • main 函数最终地址:0x401000

    • foo 函数最终地址:0x401020

  2. 重定位修正

    • 找到 a.o 中 call 指令的位置(0x401005)。

    • 计算相对偏移:0x401020 (foo) - 0x40100A (下条指令) = 0x16

    • 将 call 0x00000000 修正为 call 0x16(实际编码为 E8 16 00 00 00)。

  3. 符号表更新(副产品):

    • _Z3foov 的地址更新为 0x401020(仅用于调试,不参与运行)。


3. 关键区别:符号表 vs. 重定位

目标文件组件作用是否影响运行时
符号表(.symtab)记录符号名称和地址的映射否(调试用)
重定位表(.rel.*)标记需要修正的指令/数据位置是(直接修改代码)
  • 符号表:像一本书的目录,帮助链接器找到符号定义。

  • 重定位表:像编辑批注,告诉链接器哪些地方需要修改。

http://www.xdnf.cn/news/243127.html

相关文章:

  • Spark-小练试刀
  • centos7 离线安装python3 保留python2
  • 华为eNSP:多区域集成IS-IS
  • 数据升降级:医疗数据的“时空穿梭“系统工程(分析与架构篇)
  • Linux btop 使用教程
  • 三元运算符与扩展运算符
  • Java 中的 CopyOnWriteArrayList
  • 11.多边形的三角剖分 (Triangulation) : 画廊问题
  • Postgresql源码(145)优化器nestloop参数化路径评估不准问题分析
  • WSGI(Web Server Gateway Interface)服务器
  • Seata服务端同步提交事务核心源码解析
  • MySQL零基础入门:Ubuntu环境安装与操作精解
  • 深度探索DeepSeek:从架构设计到性能优化的实战指南
  • WPF嵌入webapi服务器,充当微服务角色
  • ActiveMQ 性能优化与网络配置实战(二)
  • 使用Python和Pandas实现的Snowflake权限检查与SQL生成用于IT审计
  • 利用无事务方式插入数据库解决并发插入问题
  • windows系统搭建自己的ftp服务器,保姆级教程(用户验证+无验证)
  • OkHttp3.X 工具类封装:链式调用,支持HTTPS、重试、文件上传【内含常用设计模式设计示例】
  • 深度学习基础--目标检测入门简介
  • PHP之CURL通过header传参数及接收
  • day12:遗传算法及常见优化算法分享
  • 指针与算法的双人舞:蓝桥杯两道趣味题的降维打击
  • Windows 查看电脑是否插拔过U盘
  • 【业务领域】电脑主板芯片电路结构
  • 【音视频】ffplay数据结构分析
  • C++中常用的十大排序方法之1——冒泡排序
  • 内存安全的攻防战:工具链与语言特性的协同突围
  • SIEMENS PLC程序代码 赋值 + 判断
  • 数值求解Eikonal方程的方法及开源实现