链接2:静态链接、目标文件、符号和符号表

文章目录

  • 静态链接
    • 符号解析 (symbolresolution)
    • 重定位 (relocation)
  • 目标文件
    • 1.可重定位目标文件
    • 2.可执行目标文件
    • 3.共享目标文件
  • 可重定位目标文件
      • text:
      • rodata:
      • .data
      • .bss
      • .symtab
      • .rel.text
      • .rel.data:
      • debug:
      • line:
      • strtab:
  • 符号和符号表
    • 由m定义并能被其他模块引用的全局符号
    • 由其他模块定义并被模块 m引用的全局符号
    • 只被模块 m 定义和引用的本地符号
    • 本地链接器符号和本地程序变量的区别

静态链接

像Unix ld程序这样的静态链接器 (static linker)以一组可重定位目标文件和命令行参数作为转入,生成一个完全链接的可以加载和运行的可执行目标文件作为输出。

输入的可重定位目标文件由各种不同的代码和数据节 (section) 组成。指令在一个节中,初始化的全局变量在另一个节中,而未初始化的变量又在另外一个节中。

为了创建可执行文件,链接器必须完成两个主要任务:

符号解析 (symbolresolution)

目标文件定义和引用符号。符号解析的目的是将每个符号用和一个符号定义联系起来。

重定位 (relocation)

编译器和汇编器生成从地址零开始的代码和数据节。链接器通过把每个符号定义与一个存储器位置联系起来,然后修改所有对这些符号的引用,使得它们指向这个存储器位置,从而重定位这些节。

目标文件纯粹是字节块的集合。
这些块中,有些包含程序代码,有些则包含程序数据,

而其他的则包含指导链接器和加载器的数据结构。

链接器将这些块连接起来,确定被链接块的运行时位置并且修改代码和数据块中的各种位置。链接器对目标机器了解甚少,产生目标文件的编译器和汇编器已经完成了大部分工作。

目标文件

目标文件有三种形式:

1.可重定位目标文件

包含二进制代码和数据,其形式可以在编译时与其他可重定位目标文件合并起来,创建一个可执行目标文件

2.可执行目标文件

包含二进制代码和数据,其形式可以被直接拷贝到存储器并执行。

3.共享目标文件

一种特殊类型的可重定位目标文件,可以在加载或者运行时,被动态地加载到存储器并链接。

编译器和汇编器生成可重定位目标文件(包括共享目标文件)。

链接器生成可执行目标文件。

从技术上来说,一个目标模块 (obiect module)就是一个字节序列,而一个目标文件 (object file)就是一个存放在磁盘文件中的目标模块。

各个系统之间,目标文件格式都不相同。第一个从贝尔实验室诞生的 Umix 系统使用的是 a.out格式(直到今天,可执行文件仍然指的是 a.out 文件)。

System V Unix 的早期版本使用的是 COFF(Common Obiect File
forat,一般目标文件格式)。Windows 使用的是 COFF 的一个变种,叫做PE(Portable
Executable,可移植可执行)格式。现代 Unix 系统-比如 Linux,还有 System V Unix后来的版本,各种 BSD
Unix,以及 SUN Solaris 一使用的是 Unix ELF (Executable and
LinkableFommat,可执行和可链接格式)。尽管我们的讨论集中在 ELF 上,但是不管是哪种格式,基本的概念是相似的。

可重定位目标文件

下图展示了一个典型的ELF 可重定位目标文件。
在这里插入图片描述
ELF头(ELF header)以一个 16字节的序列开始,这序列描述了字的大小和生成该文件的系统的字节顺序。

ELF 头剩下的部分包含帮助链接器解析和解释目标文件的信息。
其中包括 ELF 头的大小、目标文件的类型(比如,可重定位、可执行或者是共享的)、机器类型(比如,IA32)、节头部表 (section header table) 的文件偏移,以及节头部表中的表目大小和数量。
不同节的位置和大小是由节头部表描述的,其中目标文件中每个节都有一个固定大小的表目 (entry)。

夹在 ELF 头和节头部表之间的都是节。一个典型的 ELF 可重定位目标文件包含下面几个节:

text:

已编译程序的机器代码

rodata:

只读数据,比如 printf 语句中的格式串和开关(switch)语句的跳转表。

.data

已初始化的全局 C 变量。局部 C 变量在运行时被保存在栈中,既不出现在.data 节中,也不出现在.bss 节中。

.bss

未初始化的全局C 变量。在目标文件中这个节不占据实际的空间,它仅仅是一个占位符。目标文件格式区分初始化和未初始化变量是为了空间效率:在目标文件中,未初始化变量不需要占据任何实际的磁盘空间。

.symtab

一个符号表 (symbol table),它存放在程序中被定义和引用的函数和全局变量的信息一些程序员错误地认为必须通过-g 选项来编译一个程序,得到符号表信息。实际上,每人可重定位目标文件在.symtab 中都有一张符号表。然而,和编译器中的符号表不同,symtab 符号表不包含局部变量的表目。

.rel.text

当链接器把这个目标文件和其他文件结合时,.text 节中的许多位置都需要修改。一般而言,任何调用外部函数或者引用全局变量的指令都需要修改。另一方面,调用本地函数的指令则不需要修改。注意,可执行目标文件中并不需要重定位信息,因此通常省略,除非使用者显式地指示链接器包含这些信息。

.rel.data:

被模块定义或引用的任何全局变量的信息。一般而言,任何已初始化全局变量的初始值是全局变量或者外部定义函数的地址都需要被修改。

debug:

一个调试符号表,其有些表目是程序中定义的局部变量和类型定义,有些表目是程序中定义和引用的全局变量,有些是原始的 C 源文件。只有以- 选项调用编译驱动程序时,才会得到这张表。

line:

原始 C 源程序中的行号和text 节中机器指令之间的映射。只有以-g 选项调用编译驱动程序时,才会得到这张表。

strtab:

一个字符串表,其内容包括symtab 和debug 节中的符号表,以及节头部中的节名字。字符串表就是以 null 结尾的字符串序列。

符号和符号表

每个可重定位目标模块 m 都有一个符号表,它包含 m 所定义和引用的符号的信息。在链接器的上下文中,有三种不同的符号:

由m定义并能被其他模块引用的全局符号

由m定义并能被其他模块引用的全局符号。全局链接器符号对应于非静态的 C 函数以及被定义为不带 C的 static 属性的全局变量。

由其他模块定义并被模块 m引用的全局符号

由其他模块定义并被模块 m引用的全局符号。这些符号称为外部符号 (exteal),对应于定义在其他模块中的 C函数和变量。

只被模块 m 定义和引用的本地符号

只被模块 m 定义和引用的本地符号。有的本地链接器符号对应于带 static 属性的 C 函数和全局变量。这些符号在模块 m 中的任何地方都是可见的,但是不能被其他模块引用。目标文件中对应于模块 m 的节和相应的源文件的名字也能获得本地符号。

本地链接器符号和本地程序变量的区别

认识到本地链接器符号和本地程序变量的不同是很重要的。.symtab 中的符号表不包含对应于本地非静态程序变量的任何符号。这些符号在运行时在栈中被管理,链接器对此类符号不感兴趣。

有趣的是,定义为带有 C static 属性的本地过程变量是不在栈中管理的。取而代之,编译器在.data和.bss 中为每个定义分配空间,并在符号表中创建一个有惟一名字的本地链接器符号。

比如,假设在同一模块中的两个函数定义了一个静态本地变量 x:

int f() {
    static int x = 0;
    return x;
}

int g() {
    static int x = 1;
    return x;
}

在这种情况中,编译器在bss 中为两个整数分配空间,并引出 (export)两个惟一的本地链接器符号给汇编器。
比如,它可以用 x.1 表示函数f中的定义,而用 x.2 表示数 g中的定义。

C 程序员使用 static 属性在模块内部隐藏变量和函数声明,就像你在 Java 和 C++中使用 public和 private 声明一样。C 源代码文件扮演模块的角色。任何声明带有 static 属性的全局变量或者函数都是模块私有的。类似地,任何声明为不带 staic 属性的全局变量和函数都是公共的,可以被其他莫块访问,尽可能用 static 属性来保护你的变量和函数是很好的编程习惯。

符号表是由汇编器构造的,使用编译器输出到汇编语言s 文件中的符号。symtab 节中包含 ELF符号表。这张符号表包含一个关于表目的数组。图7.4 展示了每个表目 (entry)的格式

typedef struct {
    int name; /* string table offset */
    int value; /* section offset, or VM address */
    int size; /* object size in bytes */
    char type:4; /* data, func, section, or src file name (4 bits) */
    char binding:4; /* local or global (4 bits) */
    char reserved; /* unused */
    char section; /* section header index, ABS, UNDEF, or COMMON */
} Elf_Symbol;

这段代码定义了一个名为Elf_Symbol的结构体,用于表示ELF格式的符号表中的一个符号。该结构体包含了以下成员:

  • name:整型变量,表示符号名在字符串表中的偏移量。
  • value:整型变量,表示符号在节区(Section)中的偏移量,或者在虚拟内存地址中的地址。
  • size:整型变量,表示符号所占空间的大小。
  • type:一个占据4个比特位的字符变量,表示符号的类型。共有四种取值:data(数据)、func(函数)、section(节区)和src file name(源文件名)。
  • binding:一个占据4个比特位的字符变量,表示符号的绑定类型。共有两种取值:local(局部)和global(全局)。
  • reserved:一个字节的保留字段。
  • section:一个字节的变量,表示符号所在的节区的索引,或者特殊的值如ABS(绝对符号)、UNDEF(未定义符号)或COMMON(常量符号)。

好的,下面是一个简单的GUN READELF工具显示例子:

  1. 首先,我们需要创建一个简单的可执行文件,例如下面一个C语言程序:
// main.c

#include <stdio.h>

int main(void) {
    printf("Hello, World!\n");
    return 0;
}

我们可以使用以下命令将其编译成可执行文件:

gcc -o hello main.c
  1. 然后,我们可以使用readelf工具来查看可执行文件的头部信息,命令如下:
readelf -h hello

输出:

ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x400440
  Start of program headers:          64 (bytes into file)
  Start of section headers:          9552 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         9
  Size of section headers:           64 (bytes)
  Number of section headers:         30
  Section header string table index: 27

该命令将会显示可执行文件的ELF头部信息,包括识别码(Magic)、文件类型(Type)、目标机器(Machine)、入口点地址(Entry point address)等等。

  1. 我们还可以使用readelf来查看可执行文件的符号表信息,命令如下:
readelf -s hello

输出:

Symbol table '.symtab' contains 72 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000400230     0 SECTION LOCAL  DEFAULT    1
     2: 0000000000400250     0 SECTION LOCAL  DEFAULT    2
     3: 0000000000400270     0 SECTION LOCAL  DEFAULT    3
     4: 0000000000400290     0 SECTION LOCAL  DEFAULT    4
     5: 00000000004002b0     0 SECTION LOCAL  DEFAULT    5
     6: 00000000004002d0     0 SECTION LOCAL  DEFAULT    6
     7: 00000000004002f0     0 SECTION LOCAL  DEFAULT    7
     8: 0000000000400310     0 SECTION LOCAL  DEFAULT    8
     9: 0000000000400330     0 SECTION LOCAL  DEFAULT    9
    10: 0000000000400350     0 SECTION LOCAL  DEFAULT   10
    11: 0000000000400370     0 SECTION LOCAL  DEFAULT   11
    12: 0000000000400390     0 SECTION LOCAL  DEFAULT   12
    13: 00000000004003b0     0 SECTION LOCAL  DEFAULT   13
    14: 00000000004003d0     0 SECTION LOCAL  DEFAULT   14
    15: 00000000004003f0     0 SECTION LOCAL  DEFAULT   15
    16: 0000000000400410     0 SECTION LOCAL  DEFAULT   16
    17: 0000000000400430     0 SECTION LOCAL  DEFAULT   17
    18: 0000000000400450     0 SECTION LOCAL  DEFAULT   18
    19: 0000000000400470     0 SECTION LOCAL  DEFAULT   19
    20: 0000000000400490     0 SECTION LOCAL  DEFAULT   20
    21: 00000000004004b0     0 SECTION LOCAL  DEFAULT   21
    22: 00000000004004d0     0 SECTION LOCAL  DEFAULT   22
    23: 00000000004004f0     0 SECTION LOCAL  DEFAULT   23
    24: 0000000000400510     0 SECTION LOCAL  DEFAULT   24
    25: 0000000000400530     0 SECTION LOCAL  DEFAULT   25
    26: 0000000000400550     0 SECTION LOCAL  DEFAULT   26
    27: 0000000000400570     0 SECTION LOCAL  DEFAULT   27
    28: 0000000000400590     0 SECTION LOCAL  DEFAULT   28
    29: 00000000004005b2     0 FUNC    GLOBAL DEFAULT   14 main
    30: 0000000000601008     0 OBJECT  GLOBAL DEFAULT   23 stdout
    31: 0000000000000000     0 OBJECT  GLOBAL DEFAULT  ABS __bss_start
    32: 0000000000601008     0 NOTYPE  GLOBAL DEFAULT   23 _edata
    33: 0000000000601018     0 OBJECT  GLOBAL DEFAULT   24 _end
    34: 0000000000400600     0 FUNC    GLOBAL DEFAULT   14 _start
    35: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
    36: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND printf@@GLIBC_2.2.5
    37: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
    38: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterTMCloneTable
    39: 0000000000000000     0 FUNC    WEAK   DEFAULT  UND __libc_start_main@@GLIBC_2.2.5
    40: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMCloneTable
    41: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __cxa_finalize@@GLIBC_2.2.5

该命令将会显示可执行文件的符号表信息,包括符号的值(Value)、大小(Size)、类型(Type)、绑定类型(Bind)、可见性(Vis)以及所在的节区(Ndx)等等。

当然,readelf工具还有很多其他的选项和功能,以上只是其中的一些示例,你可以通过查阅文档来了解更多信息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/198699.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【用unity实现100个游戏之17】从零开始制作一个类幸存者肉鸽(Roguelike)游戏3(附项目源码)

文章目录 本节最终效果前言近战武器控制近战武器生成升级增加武器伤害和数量查找离主角最近的敌人子弹预制体生成子弹发射子弹参考源码完结 本节最终效果 前言 本节紧跟着上一篇&#xff0c;主要实现武器功能。 近战武器 新增Bullet&#xff0c;子弹脚本 public class Bull…

REST-Assured--JAVA REST服务自动化测试的Swiss Army Knife

什么是REST-Assured REST Assured是一套基于 Java 语言实现的开源 REST API 测试框架 Testing and validation of REST services in Java is harder than in dynamic languages such as Ruby and Groovy. REST Assured brings the simplicity of using these languages into t…

Java第二十章多线程

一、线程简介 线程是操作系统能够进行运算调度的最小单位&#xff0c;它被包含在进程之中&#xff0c;是进程中的实际运作单位。一个进程可以包含多个线程&#xff0c;这些线程可以并发执行。线程拥有自己的栈和局部变量&#xff0c;但是它们共享进程的其他资源&#xff0c;如…

STM32_10(I2C)

I2C通信 I2C&#xff08;Inter IC Bus&#xff09;是由Philips公司开发的一种通用数据总线两根通信线&#xff1a;SCL&#xff08;Serial Clock&#xff09;、SDA&#xff08;Serial Data&#xff09;同步&#xff0c;半双工带数据应答支持总线挂载多设备&#xff08;一主多从…

网络和信息系统指令 ( NIS2 ) 及其全球影响

网络和信息系统指令 ( NIS2 ) 将于 2024 年 10 月生效&#xff0c;旨在提高欧盟 (EU) 的网络弹性。 不过&#xff0c;其影响可能会更广泛&#xff0c;带来更严格的流程和控制&#xff0c;并重新定义我们向被视为国家关键的组织提供服务的方式。 该强制性指令将具有效力&#x…

如果每天工资按代码行数来算,来看看你每天工资是多少

说在前面 &#x1f63c;&#x1f63c;如果每天的工资取决于我们所编写的代码行数&#xff0c;那么我们的生活会发生怎样的改变&#xff1f;来看看你的同事们今天都提交了多少代码吧&#xff0c;看看谁是卷王&#xff0c;谁在摸鱼&#xff08;&#x1f436;&#x1f436;狗头保命…

利用Spring Boot构建restful web service的详细流程

本文档构建一个简单的restful webservice&#xff0c; 在官网原文Getting Started | Building a RESTful Web Service (spring.io)的基础上进行操作 文章目录 一、项目创建流程1.1 创建项目1.2 创建资源表示类1.3 创建资源控制类 二、项目运行参考资料 一、项目创建流程 本文的…

笔记61:注意力提示

本地笔记地址&#xff1a;D:\work_file\&#xff08;4&#xff09;DeepLearning_Learning\03_个人笔记\3.循环神经网络\第10章&#xff1a;动手学深度学习~注意力机制 a a a a a a a a

七、Lua字符串

文章目录 一、字符串&#xff08;一&#xff09;单引号间的一串字符&#xff08;二&#xff09;local str "Hello, "&#xff08;三&#xff09;[[ 与 ]] 间的一串字符&#xff08;四&#xff09;例子 二、字符串长度计算&#xff08;一&#xff09;string.len&…

RabbitMQ高级特性2 、TTL、死信队列和延迟队列

MQ高级特性 1.削峰 设置 消费者 测试 添加多条消息 拉取消息 每隔20秒拉取一次 一次拉取五条 然后在20秒内一条一条消费 TTL Time To Live&#xff08;存活时间/过期时间&#xff09;。 当消息到达存活时间后&#xff0c;还没有被消费&#xff0c;会被自动清除。 RabbitMQ…

服务器主机安全如何保障

随着互联网的快速发展&#xff0c;服务器主机安全问题日益凸显。服务器主机是网络世界中的核心&#xff0c;其安全性关乎着整个网络系统的稳定性和可靠性。 当前&#xff0c;服务器主机面临着多种安全威胁。其中&#xff0c;网络攻击是最为常见的一种。网络攻击者利用各种手段…

ELK+Filebeat

Filebeat概述 1.Filebeat简介 Filebeat是一款轻量级的日志收集工具&#xff0c;可以在非JAVA环境下运行。 因此&#xff0c;Filebeat常被用在非JAVAf的服务器上用于替代Logstash&#xff0c;收集日志信息。实际上&#xff0c;Filebeat几乎可以起到与Logstash相同的作用&…

Linux—进程状态

目录 一.前言 1.1.通过系统调用获取进程标示符 1.2.通过系统调用创建进程 二.进程状态 三.Z(zombie)-僵尸进程 四.僵尸进程危害 一.前言 学习进程的状态&#xff0c;我们首先了解一下进程的基本数据 1.1.通过系统调用获取进程标示符 由getpid&#xff08;&#xff09…

多个nginx共享值、缓存问题

背景 目前我在集成登录认证功能&#xff08;cas&#xff09;&#xff0c;使用的架构是nginxlua&#xff0c;由于我们有多个系统&#xff08;全是前端项目&#xff09;&#xff0c;每套系统都采用nginxlua的方式进行部署&#xff08;即每个系统都是一个nginx&#xff09;&#…

pytorch读取tiny-imagenet-200的验证集(val)

ori_train torchvision.datasets.ImageFolder(root args.datadir /tiny-imagenet-200/train/, transformtransform)#可以获取class_idx的映射class_idx ori_train.class_to_idx val_annotations.txt中存储着每个图片对应的类别 获取验证集的标签 test_target []#读取val_…

java:jpa、Hibernate、Spring Data JPA、ORM以及和mybatis的区别

文章目录 Java连接数据库几种方式JPAHibernate和Spring Data JPAORM框架jpa和mybatis区别Spring Boot JPA使用例子1、创建库和表2、添加依赖3、配置数据源和Hibernate属性4、配置实体类5、创建一个继承JpaRepository的接口&#xff1a;6、创建一个控制器&#xff08;Controller…

汽车电子 -- 车载ADAS之FCTA/FCTB(前方横向来车碰撞预警/制动)

参看&#xff1a;功能定义-前方交通穿行提示&制动 1、前方横向来车碰撞预警/制动 FCTA/FCTB&#xff08; Front Cross Traffic Alert /Brake&#xff09; 前方横向来车碰撞预警FCTA&#xff08; Front Cross Traffic Alert &#xff09; 其功能表现为在车辆低速前进时&am…

解锁 ElasticJob 云原生实践的难题

发生了什么 最近在逛 ElasticJob 官方社区时发现很多小伙伴都在头疼这个 ElasticJob 上云的问题&#xff0c;ElasticJob 本就号称分布式弹性任务调度框架&#xff0c;怎么在云原生环境就有了问题了呢&#xff0c;这就要从 Kubenertes 和 ElasticJob 的一些状态化说起。 有意思的…

Java SE

目录 编程编的其实就是启动之后的内存⭐配置环境Java环境Windows配置Java环境变量Linux配置Java环境变量前言&#xff1a;常见Linux系统 Java基础类型八大基本数据类型数值型非数值型 void引用数据类型 运算符位运算符其他 基本结构表达式方法类实例&#xff08;对象&#xff0…

战略制定|竞争战略管理分析六大常用工具

企业战略可从多个角度理解&#xff0c;体现为著名的5P模型。首先&#xff0c;从未来发展视角看&#xff0c;战略是一种计划(Plan)&#xff0c;指导企业朝向既定目标前进。而从过去的发展历程看&#xff0c;它呈现为一种模式(Pattern)&#xff0c;反映了企业的历史行为趋势。在产…
最新文章