链接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 00Class:                             ELF64Data:                              2's complement, little endianVersion:                           1 (current)OS/ABI:                            UNIX - System VABI Version:                       0Type:                              EXEC (Executable file)Machine:                           Advanced Micro Devices X86-64Version:                           0x1Entry point address:               0x400440Start of program headers:          64 (bytes into file)Start of section headers:          9552 (bytes into file)Flags:                             0x0Size of this header:               64 (bytes)Size of program headers:           56 (bytes)Number of program headers:         9Size of section headers:           64 (bytes)Number of section headers:         30Section 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 Name0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND1: 0000000000400230     0 SECTION LOCAL  DEFAULT    12: 0000000000400250     0 SECTION LOCAL  DEFAULT    23: 0000000000400270     0 SECTION LOCAL  DEFAULT    34: 0000000000400290     0 SECTION LOCAL  DEFAULT    45: 00000000004002b0     0 SECTION LOCAL  DEFAULT    56: 00000000004002d0     0 SECTION LOCAL  DEFAULT    67: 00000000004002f0     0 SECTION LOCAL  DEFAULT    78: 0000000000400310     0 SECTION LOCAL  DEFAULT    89: 0000000000400330     0 SECTION LOCAL  DEFAULT    910: 0000000000400350     0 SECTION LOCAL  DEFAULT   1011: 0000000000400370     0 SECTION LOCAL  DEFAULT   1112: 0000000000400390     0 SECTION LOCAL  DEFAULT   1213: 00000000004003b0     0 SECTION LOCAL  DEFAULT   1314: 00000000004003d0     0 SECTION LOCAL  DEFAULT   1415: 00000000004003f0     0 SECTION LOCAL  DEFAULT   1516: 0000000000400410     0 SECTION LOCAL  DEFAULT   1617: 0000000000400430     0 SECTION LOCAL  DEFAULT   1718: 0000000000400450     0 SECTION LOCAL  DEFAULT   1819: 0000000000400470     0 SECTION LOCAL  DEFAULT   1920: 0000000000400490     0 SECTION LOCAL  DEFAULT   2021: 00000000004004b0     0 SECTION LOCAL  DEFAULT   2122: 00000000004004d0     0 SECTION LOCAL  DEFAULT   2223: 00000000004004f0     0 SECTION LOCAL  DEFAULT   2324: 0000000000400510     0 SECTION LOCAL  DEFAULT   2425: 0000000000400530     0 SECTION LOCAL  DEFAULT   2526: 0000000000400550     0 SECTION LOCAL  DEFAULT   2627: 0000000000400570     0 SECTION LOCAL  DEFAULT   2728: 0000000000400590     0 SECTION LOCAL  DEFAULT   2829: 00000000004005b2     0 FUNC    GLOBAL DEFAULT   14 main30: 0000000000601008     0 OBJECT  GLOBAL DEFAULT   23 stdout31: 0000000000000000     0 OBJECT  GLOBAL DEFAULT  ABS __bss_start32: 0000000000601008     0 NOTYPE  GLOBAL DEFAULT   23 _edata33: 0000000000601018     0 OBJECT  GLOBAL DEFAULT   24 _end34: 0000000000400600     0 FUNC    GLOBAL DEFAULT   14 _start35: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses36: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND printf@@GLIBC_2.2.537: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__38: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterTMCloneTable39: 0000000000000000     0 FUNC    WEAK   DEFAULT  UND __libc_start_main@@GLIBC_2.2.540: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMCloneTable41: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __cxa_finalize@@GLIBC_2.2.5

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Pix2Struct的文档信息提取【DocVQA】

文档信息提取涉及使用计算机算法从非结构化或半结构化文档&#xff08;例如报告、电子邮件和网页&#xff09;中提取结构化数据&#xff08;例如员工姓名、地址、职务、电话号码等&#xff09;。 提取的信息可用于各种目的&#xff0c;例如分析和分类。 DocVQA&#xff08;文档…

MySQL基础进阶篇

进阶篇 存储引擎 MySQL体系结构&#xff1a; 存储引擎就是存储数据、建立索引、更新/查询数据等技术的实现方式。存储引擎是基于表而不是基于库的&#xff0c;所以存储引擎也可以被称为表引擎。 默认存储引擎是InnoDB。 相关操作&#xff1a; -- 查询建表语句 show create …

BGP综合实验(IP)

实验要求&#xff1a; 实验思路&#xff1a; 1.划分IP地址&#xff1a; 将172.16.0.0/16的网段划分为172.16.0.0/24的多个网段&#xff0c;因为在实际工程当中&#xff0c;24的网段更符合用户网段&#xff0c;因此先将网段划分为172.16.0.0 /24的多个子网掩码为24的网段&…

filebeat(远程收集日志工具)

&#xff08;一&#xff09;filebeat 1、filebeat和logstash相同 &#xff08;1&#xff09;filebeat是一个轻量级的日志收集工具&#xff0c;所使用的系统资源比logstash部署和启动时使用的资源要小的多 &#xff08;2&#xff09;filebeat可以运行在非Java环境、可以代理l…

C语言——计算Fibonacci数列

方式一 for循环 (20位) #define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h> int main() {int n;int a[20]{1,1};for ( n 1; n <20; n){a[n]a[n-2]a[n-1];}for ( n 0; n < 20; n){if(n%50)printf("\n");printf("%12d ",a[n]);}return 0; …

【小黑嵌入式系统第十课】μC/OS-III概况——实时操作系统的特点、基本概念(内核任务中断)、与硬件的关系实现

文章目录 一、为什么要学习μC/OS-III二、嵌入式操作系统的发展历史三、实时操作系统的特点四、基本概念1. 前后台系统2. 操作系统3. 实时操作系统&#xff08;RTOS&#xff09;4. 内核5. 任务6. 任务优先级7. 任务切换8. 调度9. 非抢占式&#xff08;合作式&#xff09;内核10…

轻量级web开发框架:Flask本地部署及实现公网访问界面

轻量级web开发框架&#xff1a;Flask本地部署及实现公网访问界面 文章目录 轻量级web开发框架&#xff1a;Flask本地部署及实现公网访问界面前言1. 安装部署Flask2. 安装Cpolar内网穿透3. 配置Flask的web界面公网访问地址4. 公网远程访问Flask的web界面 前言 本篇文章讲解如何…

CI/CD 构建中能保护好 SSHKEY吗?

目录 背景 方案 编码存储 逐行存储 合并存储 打马赛克 结论 背景 使用极狐GitLab CI/CD&#xff0c;在部署方面&#xff0c;主要有两种方式&#xff1a; 部署到K8S集群 Push模式&#xff1a;流水线通过kubectl执行命令部署&#xff0c;这需要把K8S的权限给流水线&#xf…

GoWeb学习-第二天

文章目录 从零开始学Go web——第二天一、安装Go语言二、建立web目录2.1 创建GO语言包目录2.2 创建Go web文件 三、编译并运行Go web应用3.1 编译并运行3.2 查看结果 从零开始学Go web——第二天 ​ 第一天我们了解了与web息息相关的HTTP协议&#xff0c;聊了聊Go与web的关系等…

LeetCode Hot100 42.接雨水

题目&#xff1a; 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 方法一&#xff08;相向双指针&#xff09;&#xff1a;竖着计算面积 代码&#xff1a; class Solution {public int trap(int[] he…

无分类编址 CIDR

在域名系统出现之后的第一个十年里&#xff0c;基于分类网络进行地址分配和路由IP数据包的设计就已明显显得可扩充性不足&#xff08;参见RFC 1517&#xff09;。为了解决这个问题&#xff0c;互联网工程工作小组在1993年发布了一新系列的标准——RFC 1518和RFC 1519——以定义…

初识数据结构及复杂度

1、数据结构 数据结构数据结构&#xff08;描述和组织数据&#xff09;&#xff0c;Java会把一些数据结构封装起来&#xff0c;在java中数据结构叫做集合。 数据结构&#xff1a;&#xff08;data structer&#xff09;是计算机存储、组织数据的方式&#xff0c;指相互之间存在…

mac电脑下载Netflix Mac(奈飞客户端)安装教程

Netflix Mac&#xff0c;奈飞官方客户端&#xff0c;带给您无限的电影和剧集体验&#xff01;与朋友分享最新热门剧集、电影&#xff0c;与家人一起享受高品质的流媒体内容。 通过Netflix Mac&#xff0c;您可以轻松地搜索、浏览和观看各种类型的影片&#xff0c;包括剧情片、…

【鸿蒙应用ArkTS开发系列】- 选择图片、文件和拍照功能实现

文章目录 前言创建多媒体Demo工程创建MediaBean 实体类创建MediaHelper工具类API标记弃用问题动态申请多媒体访问权限实现选择图片显示功能打包测试 前言 在使用App的时候&#xff0c;我们经常会在一些社交软件中聊天时发一些图片或者文件之类的多媒体文件&#xff0c;那在鸿蒙…

GitHub 2023排名前十的最佳开源项目

开源软件&#xff08;OSS&#xff09;彻底改变了当今软件开发的方式。在数百万个开源GitHub项目中&#xff0c;要找到最适合需求的开源项目可能会让人不知所措。 今天给大家列出2023年增长最快的前10个开源GitHub仓库。通过这些增长最快的开源项目&#xff0c;也可以从整体上了…

算法 离散化

整数离散化 适用条件 适用于有序的整数序列该序列的值域很大&#xff0c;该序列的数的个数很少使用的是数的相对大小而非绝对大小 算法思路 原数组 a &#xff1a; 数组下标&#xff1a;0 1 2 3 4 数组元素&#xff1a;1 2 2 5 109 映射数组 &#xff1a; 数组下标&…

Flask教程入门

1.学习Flask之前&#xff0c;首先需要对URL进行一定的了解。 URL的一些知识&#xff1a; 1.URL只能包含ASCII码里面一些可显示的字符&#xff0c;如A-Z&#xff0c;a-z&#xff0c;0-9&#xff0c;&&#xff0c;#&#xff0c;%&#xff0c;&#xff1f;&#xff0c;/等字符…

数据链路层——以太网协议、ARP协议

目录 以太网协议 以太网协议的简介 以太网协议所处的位置 以太网帧&#xff08;或者说MAC帧&#xff09;的格式 局域网通信原理 碰撞避免算法&#xff08;包含MTU的知识点&#xff09; 局域网攻击原理 ARP协议 ARP协议所在的位置 为什么要存在ARP协议&#xff08;或者…

nodejs669在线图书借阅管理系统vue前端

系统的设计与实现主要实现角色有管理员和用户,管理员在后台管理用户模块、用户表模块、图书借阅模块、图书归还模块、图书分类模块、token表模块、收藏表模块、书籍信息模块、图书资讯模块、留言板模块、书籍信息评论表模块、注册用户模块、配置文件模块、处罚记录模块、在线客…

Mysql更新Blob存储的Josn数据

Mysql更新blob存储的Josn数据 记录一次mysql操作blob格式存储的json字符串数据 1、检查版本 -- 版本5.7以上才可以能执行json操作 select version(); 2、创建测试数据 -- 创建测试表及测试数据 CREATE TABLE test_json_table AS SELECT UUID(), {"test1": {"…