Skip to content

链接

C 语言程序内存结构

../../System/Picture/Elf-layout--en.svg

  1. gcc –E hello.c –o hello.i

  2. gcc –S hello.i –o hello.s

  3. as hello.s -o hello.o

预处理(Prepressing)

  • 处理#define,#include
  • 处理#if,#ifdef,#elif,#else,endif.
  • 删除注释
  • 添加行号,便于调试产生相关信息
  • 保留#pragma

目标文件

  • ELF Header 描述整个文件的基本属性
  • .text 代码段
  • .data 数据段
  • .bss段 为未初始化的全局变量和局部静态变量预留位置,它并没有内容,所以它在文件中不占据空间。
  • Section Header Table

binutils使用方法

gcc -c 只编译不链接

objdump -h 查看ELF的基本信息 -x 查看ELF的全部信息 -s 将段中的内容以十六进制打印出来 -d 将包含指令的段反汇编

readelf -a 查看ELF的全部信息 -h 查看ELF的 header -S 查看所有的段表信息 -s 查看文件的符号 size 查看ELF各个段长度

nm 查看ELF文件的符号

代码

/*
 * SimpleSection.c
 *
 * Linux:
 *   gcc -c SimpleSection.c
 *
 * Windows:
 *   cl SimpleSection.c /c /Za
 */

int printf(const char *format, ...);

int global_init_var = 84;
int global_uninit_var;

void func1(int i)
{
    printf("%d\n", i);
}

int main(void)
{
    static int static_var = 85;
    static int static_var2;

    int a = 1;
    int b;

    func1(static_var + static_var2 + a + b);

    return a;
}

结果

../../System/Picture/Pasted image 20230711155428.png

  • .text: 已编译程序的机器代码

  • .rodata: 只读数据,比如 printf 语句中的格 图 7-3 典型的 ELF 可重定位目标文件式串和开关语句的跳转表。

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

  • .bss: 未初始化的全局和静态 C 变量,以及所有被初始化为 0 的全局或静态变量。在目标文件中这个节不占据实际的空间,它仅仅是一个占位符。目标文件格式区分已初始化和未初始化变量是为了空间效率:在目标文件中,未初始化变量不需要占据任何实际的磁盘空间。运行时,在内存中分配这些变量,初始值为 0 。

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

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

  • .rel.data: 被模块引用或定义的所有全局变量的重定位信息。一般而言,任何已初始化的全局变最,如果它的初始值是一个全局变量地址或者外部定义函数的地址,都需要被修改。

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

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

  • .strtab: 一个字符串表,其内容包括 .symtab 和 .debug 节中的符号表,以及节头部中的节名字。字符串表就是以 null 结尾的字符串的序列。 ../../System/Picture/Pasted image 20230711185717.png

../../System/Picture/Pasted image 20230711191742.png

../../System/Picture/Pasted image 20230711192047.png