Linux:ELF

前置知识

从文本文件到可执行文件经历的阶段

一个用C语言编写的高级语言程序从编写到打包、再到编译执行的基本过程如下:
在这里插入图片描述

编写 - 预处理 - 编译 - 汇编 - 链接 。
其中,编译和汇编可以合并成一步,称为编译。

  1. 编写程序:使用任意文本编辑器,如Notepad、Sublime Text、Visual Studio等。

  2. 预处理:使用预处理器对程序进行处理,例如宏替换、头文件包含等。使用预处理器,通常是C语言编译器的一部分,例如gcc、clang等。预处理器处理的文件是源代码文件,生成的文件通常是.i后缀的中间文件,例如hello.i。

  3. 编译:使用编译器将程序转换为汇编语言。使用编译器,例如gcc、clang等。编译器处理的文件是预处理器生成的.i文件,生成的文件通常是.s后缀的汇编代码文件,例如hello.s。

  4. 汇编:使用汇编器将汇编代码转换成机器码。使用汇编器,例如gas、nasm等。处理的文件是编译器生成的.s文件,生成的文件通常是.o后缀的目标文件,例如hello.o。

  5. 链接:使用链接器将程序中的不同模块连接起来,并生成可执行文件。使用链接器,例如ld、gcc等。处理的文件是目标文件(.o文件),可以链接多个目标文件,生成可执行文件。 可执行文件通常是没有后缀的,例如hello。

  6. 打包:使用压缩工具,例如tar、zip等。打包的文件通常是可执行文件和相关依赖文件,文件名可以自定义,例如hello.tar.gz或hello.zip。

在整个编译过程中,涉及到的文件可以分为源代码文件(.c文件)、预处理生成的文件(.i文件)、编译器生成的文件(.s文件、.o文件)和链接器生成的文件(可执行文件)。

因此在本示例中,文件名可以为hello.c、hello.i、hello.s、hello.o、hello等。

编译器gcc

gcc是GNU Compiler Collection的缩写,是一款开源的C编译器,支持多种操作系统和CPU架构。它由许多不同的编译器组成,包括C、C ++、Objective-C、Fortran、Ada和其他语言的编译器,并支持众多的开源项目。gcc是GNU工程的一部分,由自由软件基金会(FSF)维护。由于它的灵活性和可移植性,gcc被广泛应用于编译开源项目和商业软件。

目标文件

目标文件(Object File)是编译源代码后生成的中间文件,其中包含了编译器产生的机器代码、符号表、重定位信息等。目标文件的主要作用是在链接阶段将多个目标文件合并成一个可执行文件或者库文件。

目标文件的命名约定和后缀可以因编译器和操作系统而异。在Unix/Linux系统中,通常使用".o"作为目标文件的后缀,例如example.o。在Windows系统中,常见的目标文件后缀包括".obj"等。

目标文件是编译过程中的一个重要中间产物,通过链接器将多个目标文件合并,最终生成可执行文件或者共享库。

目标文件的详细介绍可以参阅:
计算机的目标文件是什么? 在程序中充当什么角色?

ELF

ELF(Executable and Linkable Format)是一种通用的二进制文件格式,用于可执行文件、目标文件、共享库等在Unix和类Unix系统中。ELF格式是一种规范,定义了二进制文件的结构,使得不同的编译器、链接器和操作系统能够共同使用这种格式的文件。

ELF文件包含了以下主要部分:

  1. 文件头(ELF Header): 包含了文件的基本信息,如文件类型、架构、入口点地址等。

  2. 程序头表(Program Header Table): 描述了可执行文件的段(段包含可执行代码、数据、BSS等),以及这些段在内存中的加载位置和属性。

  3. 节头表(Section Header Table): 描述了目标文件的各个节(sections),包括代码段、数据段、符号表、字符串表等。每个节都有自己的类型、大小、偏移量等属性。

  4. 数据节(Sections): 包含实际的数据,例如代码、数据、符号表等。

  5. 重定位信息: 描述了需要在链接时进行重定位的位置,以便正确地将不同目标文件的代码和数据链接在一起。

  6. 符号表(Symbol Table): 记录了各种符号(函数、变量等)的信息,包括名称、类型、地址等。

ELF格式的设计提供了灵活性和可扩展性,使得不同的操作系统和硬件架构能够支持这一格式。在Linux和许多其他类Unix系统中,可执行文件和共享库通常采用ELF格式。

Section(节)

Section(段)是在汇编和链接中用于组织和描述不同类型数据的一个概念。在汇编程序中,.section指令用于声明一个Section。每个Section都包含特定类型的数据,比如代码、数据、符号表、字符串表等。

以下是一些常见的Section类型:

  1. 代码段(.text): 包含可执行的机器代码。

  2. 数据段(.data): 包含已初始化的全局和静态变量。

  3. BSS段: 包含未初始化的全局和静态变量。BSS是"Block Started by Symbol"的缩写。

  4. 符号表段(.symtab): 包含符号表,记录了程序中的符号(函数、变量等)信息。

  5. 字符串表段(.strtab): 包含字符串表,存储了符号表中的字符串。

  6. 重定位表段(.rel.text、.rel.data等): 包含重定位信息,记录了需要在链接时进行重定位的位置。

每个Section都有一个名称和一组属性,这些属性描述了Section的内容和用途。在链接过程中,多个目标文件中的相同类型的Section会被合并成一个更大的Section,以便最终生成可执行文件或共享库。

Section在汇编和链接中起到了组织和管理代码、数据以及其他信息的作用,使得程序的各个部分能够被正确地组合在一起。

Segment(段)

Segment(段)是在可执行文件在运行时加载到内存时用于组织和描述内存布局的一个概念。一个Segment通常包含一个或多个相邻的Section,这些Section在运行时被映射到内存中的相邻区域。

ELF文件格式中的Program Header Table描述了可执行文件在内存中的布局,其中的每一项对应一个Segment。Segment的类型和属性决定了在运行时如何加载和使用这一段内存。

常见的Segment类型包括:

  1. 加载可执行代码的Segment: 包含机器代码的Section,通常标记为可执行和可读。在内存中,这一段被映射为可执行的代码段。

  2. 加载可读写数据的Segment: 包含已初始化的全局和静态变量的Section,通常标记为可读和可写。在内存中,这一段被映射为可读写的数据段。

  3. 加载可读写BSS段的Segment: 包含未初始化的全局和静态变量的Section,通常标记为可读和可写。在内存中,这一段被映射为可读写的BSS段。

  4. 加载只读数据的Segment: 包含只读数据的Section,通常标记为只读。在内存中,这一段被映射为只读数据段。

每个Segment都有一个虚拟地址和一个文件偏移量,描述了它在内存中的位置和在文件中的位置。加载器(Loader)使用这些信息来将文件中的Segment映射到内存中的相应位置。

Segment在可执行文件加载时决定了程序在内存中的布局,它通过包含相关的Section来组织和描述内存中的数据和代码。这种设计提供了对内存分布的更高级别的抽象,使得可执行文件能够在不同环境中正确地加载和运行。

从链接角度和从程序角度看ELF文件

ELF文件在汇编器和链接器看来是由Section Header Table描述的一系列Section的集合,而在加载器(Loader)看来是由Program Header Table描述的一系列Segment(段)的集合。这两个表提供了不同的视角,分别对应着文件在链接和加载过程中的不同需求。如图:
在这里插入图片描述

1. Section Header Table:

  • 描述: Section Header Table包含了关于文件中各个Section的信息。每个Section对应于文件中的一部分数据,如代码段、数据段、符号表等。
  • 用途: 汇编器和链接器使用Section信息来组织和管理不同类型的数据。符号表、字符串表、代码段、数据段等都以Section的形式存在。

2. Program Header Table:

  • 描述: Program Header Table描述了可执行文件在内存中的布局,以及如何加载这些Segment。如前面描述的,Segment是一个更高层次的概念,它可能包含多个Section,但是在内存中以更连续的方式存在。
  • 用途: 加载器使用Program Header信息来决定如何加载文件中的Segment,将它们映射到内存中的合适位置,并设置程序的入口点等。

通过这两个表,ELF文件格式在设计上实现了灵活性和可扩展性。Section提供了对文件中不同类型数据的详细描述,而Segment则更侧重于在运行时的内存布局。这样的设计使得ELF文件在不同阶段(编译、链接、加载)都能够提供必要的信息,以便于文件的正确处理和执行。

参考

https://blog.csdn.net/daide2012/article/details/73065204

  • 7
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林树杰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值