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

news2024/11/26 9:48:44

文章目录

  • 静态链接
    • 符号解析 (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.coloradmin.cn/o/1264905.html

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

相关文章

【开题报告】基于深度学习的驾驶员危险行为检测系统

研究的目的、意义及国内外发展概况 研究的目的、意义&#xff1a;我国每年的交通事故绝对数量是一个十分巨大的数字&#xff0c;造成了巨大的死亡人数和经济损失。而造成交通事故的一个很重要原因就是驾驶员的各种危险驾驶操作行为。如果道路驾驶员的驾驶行为能够得到有效识别…

奇数求和(C++)

系列文章目录 进阶的卡莎C++_睡觉觉觉得的博客-CSDN博客数1的个数_睡觉觉觉得的博客-CSDN博客双精度浮点数的输入输出_睡觉觉觉得的博客-CSDN博客足球联赛积分_睡觉觉觉得的博客-CSDN博客大减价(一级)_睡觉觉觉得的博客-CSDN博客小写字母的判断_睡觉觉觉得的博客-CSDN博客纸币(…

详细介绍如何使用深度学习自动车牌(ALPR)识别-含(数据集+源码下载)

深度学习一直是现代世界发展最快的技术之一。深度学习已经成为我们日常生活的一部分,从语音助手到自动驾驶汽车,它无处不在。其中一种应用程序是自动车牌识别 (ALPR)。顾名思义,ALPR是一项利用人工智能和深度学习的力量自动检测和识别车辆车牌字符的技术。这篇博文将重点讨论…

Servlet-Vue-JSON交互

Servlet-Vue-JSON交互 统一结果返回 定义 package org.example.result;import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;Data NoArgsConstructor AllArgsConstructor public class Result<T> {private Integer code;private St…

人工智能_AI服务器安装清华开源_CHATGLM大语言模型_GLM-6B安装部署_人工智能工作笔记0092

看到的这个开源的大模型,很牛,~关键让我们自己也可以部署体验一把了,虽然不知道具体内部怎么构造的但是,也可以自己使用也挺好. 可以部署在自己的机器上也可以部署在云服务器上. 安装以后,是可以使用python代码进行提问,然后返回结果的,这样就可以实现我们自己的chat应用了, …

5面试题--redis

慢查询⽇志&#xff1a;⽤于记录执⾏时间超过给定时⻓的命令请求&#xff0c;⽤户可以通过这个功能产⽣的⽇志来监视和 优化查询速度。 布隆过滤器&#xff1a;⼆进制数组进⾏存储&#xff0c;若判断元素存在则可能实际存在&#xff0c;若判断不存在则⼀定不存在。 redis中inc…

Linux文件目录结构_文件管理

Linux文件目录结构 Linux目录结构简洁 windows:以多根的方式组织文件 C:\ D:\ E:\ Linux: 以单根的方式组织文件/ Linux目录结构视图 注意区分&#xff1a; 系统管理员&#xff1a;中文“根”&#xff0c;root 系统目录&#xff08;文件夹&#xff09;&#xff1a;根&#xf…

解决ssh使用public key远程登录服务器拒绝问题

目录 使用场景windows安装ssh客户端使用powershell ssh登录服务器生成密钥文件ubuntu ssh服务器配置使用vscode远程登录使用Xshell远程登录使用MobaXtem远程登录Server refused our key问题解决方案 使用场景 使用vscode远程ssh登录使用public key不需要输入密码,比较方便. w…

使用opencv实现更换证件照背景颜色

1 概述 生活中经常要用到各种要求的证件照电子版&#xff0c;红底&#xff0c;蓝底&#xff0c;白底等&#xff0c;大部分情况我们只有其中一种&#xff0c;本文通过opencv实现证件照背景的颜色替换。 1.1 opencv介绍 OpenCV&#xff08;Open Source Computer Vision Librar…

Leetcode 380. O(1) 时间插入、删除和获取随机元素

文章目录 题目代码&#xff08;11.28 首刷看解析&#xff09; 题目 Leetcode 380. O(1) 时间插入、删除和获取随机元素 代码&#xff08;11.28 首刷看解析&#xff09; 1.length:表示的是数组的长度 数组 2.length():表示的是字符串的长度 字符串 3.size():表示的是集合中有多…

人工智能|机器学习——感知器算法原理与python实现

感知器算法是一种可以直接得到线性判别函数的线性分类方法&#xff0c;它是基于样本线性可分的要求下使用的。 一、线性可分与线性不可分 为了方便讨论&#xff0c;我们蒋样本增加了以为常数&#xff0c;得到增广样向量 y&#xff08;1;;;...;&#xff09;,则n个样本的集合为&a…

vue项目中使用jsonp跨域请求百度联想接口

一. 内容简介 vue项目中使用jsonp跨域请求百度联想接口 二. 软件环境 2.1 Visual Studio Code 1.75.0 2.2 chrome浏览器 2.3 node v18.14.0 三.主要流程 3.1 代码 核心代码 // 这个是请求函数doLeno() {// 挂载回调函数&#xff0c;不挂载&#xff0c;会报不存在window…

短视频账号矩阵系统源码/saas独立源头技术开发

一、批量剪辑&#xff08;采用php语言&#xff0c;数学建模&#xff09; 短视频合成批量剪辑的算法主要有以下几种&#xff1a; 1. 帧间插值算法&#xff1a;通过对多个视频的帧进行插帧处理&#xff0c;从而合成一段平滑的短视频。 2. 特征提取算法&#xff1a;提取多个视频中…

viple模拟器使用(四):unity模拟器中实现沿右墙迷宫算法

沿右墙迷宫算法 引导 线控模拟可以使得通过用户手动操作&#xff0c;实现机器人在模拟环境下在迷宫中行走&#xff08;即&#xff1a;运动&#xff09;&#xff0c;算法可以使得机器人按照一定的策略自动行走&#xff0c;沿右墙迷宫算法就是其中的一种策略。 目的 运行程序后&…

MFC容器中使用标准库容器,内存违规

问题描述 CArray中元素不管是直接或间接使用标准库容器&#xff0c;会引发内存违规。与CArray内部实现有关。测试代码如下&#xff1a; struct tagData {std::vector<int> m_Values; }; CArray<tagData, tagData> mIntVecArray; {tagData mData;mData.m_Values.p…

【08】Python运算符

文章目录 1.算术运算符2.赋值运算符3.条件运算符4.逻辑运算符5.比较运算符6.运算符的优先级本期博客中,我们将学习python中常用的运算符的用法。              1.算术运算符 1.加法运算符(+): a = 10 b = 5 c = a + b print(c

仿制剧情吧网站源码 帝国CMS剧情介绍模板

帝国CMS7.5剧情介绍模板&#xff0c;仿制剧情吧网站的风格。该模板并非用于直接播放电影&#xff0c;而是用文字描述剧情&#xff0c;同时包含手机版。本站免费分享供站长学习研究使用。采用伪静态技术&#xff0c;无需生成HTML。出于美观考虑&#xff0c;自带数据仅供本地环境…

跨越威胁的传说:揭秘Web安全的七大恶魔

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

OpenCV | 傅里叶变换——低通滤波器与高通滤波器

import cv2 #opencv 读取的格式是BGR import numpy as np import matplotlib.pyplot as plt #Matplotlib是RGB %matplotlib inline def cv_show(img,name):cv2.imshow(name,img)cv2.waitKey()cv2.destroyAllWindows() 傅里叶变换 傅里叶变换的作用 高频&#xff1a;变化剧烈…

什么是计算机病毒?

计算机病毒 1. 定义2. 计算机病毒的特点3. 计算机病毒的常见类型和攻击方式4. 如何防御计算机病毒 1. 定义 计算机病毒是计算机程序编制者在计算机程序中插入的破坏计算机功能或者破坏数据&#xff0c;影响计算机使用并且能够自我复制的一组计算机指令或程序代码。因其特点与生…