Linux ELF文件学习

本文主要通过代码,了解Linux ELF文件的相关知识。

ELF文件

ELF(Executable Linkable Format)是Linux平台的可执行文件。

ELF文件的类型:

  • 可重定位类型

    • 包含代码和数据,用来链接成可执行文件或共享目标文件, linux的.o文件
  • 可执行文件

    • 可以直接执行的程序
  • 共享目标文件

    • .so文件
  • 核心转储文件

    • core dump文件,系统意外时转储文件。

源码

SimpleSection.c

#include <stdio.h>
#include <stdlib.h>

// 全局变量,data区, 4字节
int global_int_var = 1;
// 全局变量,未初始化,bss区, 4字节
int global_uninit_var;

void func1(int i)
{
	// 里面有一个"%d\n"字符串,在rodata区, 共4字节
	printf("%d\n", i);
}

int main(void)
{
	// 静态变量,data区, 4字节
	static int static_var = 1;
	// 静态变量,未初始化,bss区, 4字节 
	static int static_var2;
	// 局部变量, 栈区
	int a = 1;
	// 局部变量, 栈区
	int b;
	// 静态变量,未初始化,64位系统,占用8字节
	static int *static_ptr = NULL;
	// 局部变量,栈区
	int *p;
	// malloc申请的空间,堆区
	p = malloc(sizeof(int));

	free(p);

	// 函数调用时,也会进行入栈出栈操作,一些局部变量都需要保存在占中
	func1(static_var + static_var2 + a + b);

	return 0;
}

编译文件

只编译本文件方便分析,不连接其他的库。

编译使用的是ubuntu64位系统。

gcc -c SimpleSection.c -o SimpleSection.o

objdump查看段信息

objdump -h SimpleSection.o

#                    文件格式
SimpleSection.o:     file format elf64-x86-64
                  
Sections:
#                 大小      虚拟地址          逻辑地址          文件偏移  段边界对齐字数
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         0000007e  0000000000000000  0000000000000000  00000040  2**0
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
  1 .data         00000008  0000000000000000  0000000000000000  000000c0  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000010  0000000000000000  0000000000000000  000000c8  2**3
                  ALLOC
  3 .rodata       00000004  0000000000000000  0000000000000000  000000c8  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .comment      00000027  0000000000000000  0000000000000000  000000cc  2**0
                  CONTENTS, READONLY
  5 .note.GNU-stack 00000000  0000000000000000  0000000000000000  000000f3  2**0
                  CONTENTS, READONLY
  6 .note.gnu.property 00000020  0000000000000000  0000000000000000  000000f8  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  7 .eh_frame     00000058  0000000000000000  0000000000000000  00000118  2**3
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA

查看elf文件头

readelf -h SimpleSection.o

ELF Header:
# elf魔数
  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:                              REL (Relocatable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          1208 (bytes into file)
  Flags:                             0x0
# 文件头的大小
  Size of this header:               64 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           64 (bytes)
# 段表成员个数
  Number of section headers:         14
  Section header string table index: 13

查看elf段表

段表在ELF文件中位置有ELF文件头的"e_shoff"成员决定。

ELF文件的段结构就是由段表决定,编译器、链接器和装载器都是通过段表来定位和访问各个端的属性。

readelf -S SimpleSection.o

There are 14 section headers, starting at offset 0x4b8:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .text             PROGBITS         0000000000000000  00000040
       000000000000007e  0000000000000000  AX       0     0     1
  [ 2] .rela.text        RELA             0000000000000000  00000368
       00000000000000a8  0000000000000018   I      11     1     8
  [ 3] .data             PROGBITS         0000000000000000  000000c0
       0000000000000008  0000000000000000  WA       0     0     4
  [ 4] .bss              NOBITS           0000000000000000  000000c8
       0000000000000010  0000000000000000  WA       0     0     8
  [ 5] .rodata           PROGBITS         0000000000000000  000000c8
       0000000000000004  0000000000000000   A       0     0     1
  [ 6] .comment          PROGBITS         0000000000000000  000000cc
       0000000000000027  0000000000000001  MS       0     0     1
  [ 7] .note.GNU-stack   PROGBITS         0000000000000000  000000f3
       0000000000000000  0000000000000000           0     0     1
  [ 8] .note.gnu.pr[...] NOTE             0000000000000000  000000f8
       0000000000000020  0000000000000000   A       0     0     8
  [ 9] .eh_frame         PROGBITS         0000000000000000  00000118
       0000000000000058  0000000000000000   A       0     0     8
  [10] .rela.eh_frame    RELA             0000000000000000  00000410
       0000000000000030  0000000000000018   I      11     9     8
  [11] .symtab           SYMTAB           0000000000000000  00000170
       0000000000000180  0000000000000018          12     9     8
  [12] .strtab           STRTAB           0000000000000000  000002f0
       0000000000000078  0000000000000000           0     0     1
  [13] .shstrtab         STRTAB           0000000000000000  00000440
       0000000000000074  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  D (mbind), l (large), p (processor specific)

重定位表

有一个".rel.text"段,链接器在处理目标文件时,需要对目标文件中某些部位进行重定位,即代码段和数据段中那些对绝对地址的引用位置。

自定义段

通过attribute((section("name")))把变量或者函数放到以"name"作为段名的段中。

__attribute__((section(".var_section"))) 
int var_test;

__attribute__((section(".func_section"))) 
int func_test()
{   
	printf("helloworld\n");
}

通过objdump查看,可以发现多了两个段

  3 .var_section  00000004  0000000000000000  0000000000000000  000000c8  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  5 .func_section 0000001a  0000000000000000  0000000000000000  000000db  2**0
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE

本文参考

《程序员的自我修养》

https://blog.csdn.net/SlowIsFastLemon/article/details/103593719

posted @ 2022-08-13 20:10  SuperTao1024  阅读(205)  评论(0编辑  收藏  举报