ELF可执行文件的结构详解

HarderHeng Lv5

一、ELF文件是什么

ELF可以是目标文件静态或者动态的链接文件可执行文件

前两种文件是中间文件,目标文件需要链接成为可执行文件或者链接文件,最终执行的只有可执行文件。

一个具有代码的源文件,经过预编译,编译,汇编之后得到了.o目标文件,通过将.o文件已经是具有实际机器指令的文件。

将所有的目标文件和静态库还有动态库一起链接起来,就得到了最终的可执行文件。

二、内存的基本构成

要了解ELF文件的构成,我们需要知道执行一个程序的内存是什么样的。

一个程序在运行过程中会占用:

  • data数据段,存放全局变量和静态变量
  • rodata只读数据段,存放不可被更改的只读数据
  • stack栈,存放程序运行过程中的函数调用、返回地址、传递参数
  • heap堆,动态申请的内存
  • text代码段,存放着实际执行的指令代码,是只读的

根据这些我们可以知道,stack和heap是程序运行时才会使用到,那么elf文件中基本存储的就是data数据段,也就是全局变量和静态变量,以及执行的text代码段

实际上,数据段在程序中被分成了两部分来存储分别是databss段。data段存储已经初始化的静态变量和全局变量,bss段存储没有初始化额静态变量和全局变量。如果是被初始化为0的静态变量或者全局变量也会被存放到bss段。为什么会专门分成data和bss两部分呢?

对data段来说每一个变量都需要有一个,而bss段中则不需要,只需要记录变量本身的长度,在操作系统加载程序时才会将这些bss段的变量初始化为0,节省了elf文件的空间。

三、ELF实际组成

  • ELF头:

    包含了elf文件的总体信息,包括文件的类型(可执行文件、目标文件、链接库),目标机器的架构,程序入口点的位置等等基础信息。

  • ProgramHeaderTable

    程序头表描述了程序在内存中的布局,也就是描述了各个段的大小、内存位置等等信息,在加载这个elf文件时根据程序头表将elf文件中的段加载到内存的各个位置。

  • SectionHeaderTable

    段表描述了各个段在整个文件中的布局,包括**.code、.data、.bss还有符号表**等等,每一个段都有自己的属性,在文件中的偏移地址。

  • 实际数据

    这部分就是在上面的段表中描述的各个段的实际数据。

生成静态链接库和动态链接库

1. 静态链接库

  • 将.c文件编译成目标文件.o

    1
    gcc -c myfunc.c
  • 将.o目标文件变成静态链接库

    1
    ar rcs libmyfunc.a myfunc.o

    在这里,一个静态链接库的名称为了符合规范,尽可能写成lib[name].a的形式。

  • 编译源文件时将静态链接库链接在一起

    1
    gcc test.c -L. -lmyfunc -o test

    在这里,-L指示库文件的位置,-l指示静态链接库的名字,不包含lib和.a的中间那部分。

  • 这样就生成了最终的可执行文件。

2. 动态链接库

  • 同样的将.c文件编译成.o

    1
    gcc -c myfunc.c
  • 将.o文件变成动态链接库

    1
    gcc -shared -o libmyfunc.so myfunc.o
  • 将动态链接库和源文件链接在一起

    1
    gcc test.c -L. -lmyfunc -o test
  • 定义动态链接库的环境变量

    1
    export LD_LIBRARY_PATH=.
  • Title: ELF可执行文件的结构详解
  • Author: HarderHeng
  • Created at : 2024-12-03 09:38:07
  • Updated at : 2024-12-23 15:25:02
  • Link: https://harderheng.life/2024/12/03/ELF可执行文件的结构详解/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments