Linux下ELF文件格式

简介: 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/feilengcui008/article/details/44811085 In...
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/feilengcui008/article/details/44811085

In this article,I will talk about the ELF files for Linux,and their diffs as to comprehend the linking process in a diff view angle.There are many articles talking about that topic in the way of compiling->linking->loading->executing.I think once we understand the ELF files,then we can understand why and how and understand the whole process more precisely.

ELF(Executable and Linkable Format) is the default file format of executable files,object files,shared object files and core file for Linux.Why should we know about the ELF?I think there are at least the following reasons:

  • Guess what the back end of compilers(esp for c) wants to achieve(yeah,it’s “guess”,if you want to learn more about compilers,you should learn related theories more precisely)
  • Learn about the linking and loading process
  • Better understanding of the organization of our code,that’s helpful to debug and profiling(such the effects of static/local/global/extern,debug coredump file…)
  • guess how the OS loader loads the exec file to memory and run it(yeah,guess again^_^,I will analyze the loading process in some article later)
  • Better understanding of how the disk exec file mapped into memory space of process

I will choose the first three representative ELF files in Linux to analyze,that is the object files,executable files,and shared object files.Actually,the are very simmilar except some differences(bacause they share elf struct which is defined in the elf.h^_^)

Here is the code used for the analysis purpose of this article(main.c and print.c):

//main.c 
//note that we define diff kinds of vars so we can test where they are lied in within diff sections or segments,thus we can better understand the layout of c file

#include <stdio.h>

int main_global_unitialized;
int main_global_initialized = 1;
static int main_local_uninitialized;
static int main_local_uninitialized = 2;

extern void print(int);
void print1(int);
static void print2(int);

int main()
{
    int main_stack_uninitialized;
    int main_stack_initialized = 3;
    static main_func_local_uninitialized;
    static main_func_local_initialized = 4;
    print(2);
    print1(2);
    print2(2);
    return 0;
}

void print1(int a)
{
    fprintf(stdout, "%d\n", a);
}

static void print2(int a)
{
    fprintf(stdout, "%d\n", a);
}
//print.c
#include <stdio.h>

//in module vars
int print_global_uninitialized;
int print_global_initialized = 1;
static int print_local_static_uninitialized;
static int print_local_static_initialized = 2;

void print(int a)
{
    int print_stack_uninitialized;
    int print_stack_initialized = 3;
    static int print_func_local_static_uninitialized;
    static int print_func_local_static_initialized = 4;
    fprintf(stdout, "%d\n", a);
}

static void print2(int a)
{
    fprintf(stdout, "%d\n", a);
}

We use the above two souce files to generate the following file:

gcc -o print.o -c print.c
gcc -o main.o -c main.c
gcc -shared -fPIC -o print.so print.c
gcc -o exec main.o print.o
//and the tools we may use:
//readelf/objdump/nm/size...
//the platform is Linux tan 3.13.0-51-generic #84-Ubuntu SMP x86_64 x86_64 x86_64 GNU/Linux

这里写图片描述


We will look into some diffs of the aboved mentioned 3 kinds of ELF files,we mainly use readelf.
Usually,ELF files (may) consists of the following parts:

  • file headers: describe file info such as start point,section header start poit etc
  • program header table: info of mapping sections to segments
  • section header table: section entry info
  • sections: each section contents such as .data .text etc

1.file headers

executable file headers:

这里写图片描述

object file headers:

这里写图片描述

shared object file headers:

这里写图片描述

As we can see,the file header of exec/.o/.so are almost the same except some options like type,start point…:

           #define EI_NIDENT 16
           typedef struct {
               //magic number denotes the file,16 byte,for ELF:7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
               unsigned char e_ident[EI_NIDENT]; 
               //ELF file type:exec/.o/.so/core/unknown
               uint16_t      e_type;
               uint16_t      e_machine;
               uint32_t      e_version;
               //_start point of the program
               Elf64_Addr     e_entry;
               //program header table offset,no for .o file
               Elf64_Off      e_phoff;
               //section header table offset
               Elf64_Off      e_shoff;
               uint32_t      e_flags;
               //header size
               uint16_t      e_ehsize;
               //entry size for program header table
               uint16_t      e_phentsize;
               //program entry numbers
               uint16_t      e_phnum;
               //entry size for section header table
               uint16_t      e_shentsize;
               //section entry number
               uint16_t      e_shnum;

               uint16_t      e_shstrndx;
           } Elf64_Ehdr;

Conclusions or diffs:
+ type is different
+ no start point for .o file
+ no program header for .o file


2.section header table

exec file section header table:

这里写图片描述
这里写图片描述

.so file section header table:

这里写图片描述
这里写图片描述

.o file section header table:

这里写图片描述

typedef struct {
    uint32_t   sh_name;// section name
    uint32_t   sh_type;//section type:RELA,STRTAB,SYMTAB...
    uint64_t   sh_flags;//rwe...
    Elf64_Addr sh_addr; //virtual address(no for .o file)
    Elf64_Off  sh_offset;
    uint64_t   sh_size;
    uint32_t   sh_link;
    uint32_t   sh_info;
    uint64_t   sh_addralign;//address align 
    uint64_t   sh_entsize;
} Elf64_Shdr;

Conclusions or diffs:
+ the sections of exec file and .so file are almost the same
+ more sections in exec and .so file than .o file since some sections like .fini/.init_array/.fini_array/.got/.got.plt/.init … are added during linking process
+ the virtual address of every section in .o file is 0,but not in exec and .so file


3.program header table

exec file program header:

这里写图片描述

.so file program header:

这里写图片描述

.o file program header:

这里写图片描述

typedef struct {
               uint32_t   p_type; //segment type
               uint32_t   p_flags; //permission
               Elf64_Off  p_offset; // offset
               Elf64_Addr p_vaddr; //virtual address
               Elf64_Addr p_paddr; //phisical address
               uint64_t   p_filesz; //size
               uint64_t   p_memsz;
               uint64_t   p_align;
           } Elf64_Phdr;

Conclusions or diffs:
+ there is no program header for .o file
+ some sections are divided into one segment according to the permisson flag


4.common sections explain

.intern 
#path for elf interpretor
#here is an article about changing the ld
#http://nixos.org/patchelf.html
.dynsym
#the dynamic linking symbol table
.dynstr
#strings needed for dynamic linking
.init
#executable instructions that contribute to the process initialization code(before main)
.plt
#procedure linkage table
#for GOT dynamic linker
.text
#executable instructions of a program
.fini
#executable instructions that contribute to the process termination code
.rodata
# read-only data
.dynamic
#dynamic linking information
.got
#global offset table
#for dynamic linker to resolve global elements
.data
# initialized data
.bss
#uninitialized data
.comment
#version control info
.shstrtab
#section names
.strtab
#string table
.symtab
#symble table
.debug
#debug info

for C++:

.ctors
#initialized pointers to the C++ constructor functions
.dtors
#initialized pointers to the C++ destructor functions

The sections contain important data for linking and relocation , while segments contain information that is necessary for runtime execution of the file.

About program header:http://www.sco.com/developers/gabi/latest/ch5.pheader.html
here is picture portraits the diff views for sections and segments:
这里写图片描述

5.code mapped into sections

In the last part we take a look at the symble table for our code in main.c and print.c and verify the scope of vars.

//get symble info use nm
nm exec | egrep "main|print"
----------------------------
the 3 columns:
--vaddress (dynamic linking is NULL)
--symble type and local or global
1.uppercase stands for global,lowercase is local
2.
B|b:uninitialized(BSS)
D|d:initialized data section
T|t:text (code) section
R|r: read only data section
...
--symble

这里写图片描述

So we can check the symbles in main.c and print.c,you can find how the code and data are mapper to each sections,and then organized into segments when linked into executable elf files,so it can be easily loaded into memory(actually mapped) by the OS loader(to some extent we can think it’s execve syscall)

6 to the end

In all,I talk about the three parts of the elf files in Linux especially some diffs between exec,.so and .o files and the organization for sections and segments.
If you want to know more precisely about these topics,you can refer to the following materials:

Ref:
some articles:
http://man7.org/linux/man-pages/man5/elf.5.html(man manual is so powerful^_^)
https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
http://www.sco.com/developers/gabi/latest/ch5.pheader.html
http://tech.meituan.com/linker.html
some books:
1.CSAPP
2.《程序员的自我修养》

相关文章
|
6月前
|
Linux 开发工具
7种比较Linux中文本文件的最佳工具
7种比较Linux中文本文件的最佳工具
7种比较Linux中文本文件的最佳工具
|
4月前
|
存储 数据管理 Linux
区分Linux中.tar文件与.tar.gz文件的不同。
总之,".tar"文件提供了一种方便的文件整理方式,其归档但不压缩的特点适用于快速打包和解压,而".tar.gz"文件通过额外的压缩步骤,尽管处理时间更长,但可以减小文件尺寸,更适合于需要节约存储空间或进行文件传输的场景。用户在选择时应根据具体需求,考虑两种格式各自的优劣。
717 13
|
5月前
|
安全 Linux
Linux赋予文件000权限的恢复技巧
以上这些步骤就像是打开一扇锁住的门,步骤看似简单,但是背后却有着严格的逻辑和规则。切记,在任何时候,变更文件权限都要考虑安全性,不要无谓地放宽权限,那样可能
190 16
|
6月前
|
Linux
【Linux】 Linux文件I/O常见操作技巧
以上就是Linux文件I/O操作的一些技巧,接纳它们,让它们成为你在Linux世界中的得力伙伴,工作会变得轻松许多。不过记住,技巧的运用也需要根据实际情况灵活掌握,毕竟,最适合的才是最好的。
211 28
|
5月前
|
存储 Linux 数据处理
深入剖析Linux中一切即文件的哲学和重定向的机制
在计算机的奇妙世界中,Linux的这套哲学和机制减少了不同类型资源的处理方式,简化了抽象的概念,并蕴藏着强大的灵活性。就像变戏法一样,轻轻松松地在文件、程序与设备之间转换数据流,标准输入、输出、错误流就在指尖舞动,程序的交互和数据处理因此变得既高效又富有乐趣。
104 4
|
6月前
|
Ubuntu Linux
"unzip"命令解析:Linux下如何处理压缩文件。
总的来说,`unzip`命令是Linux系统下一款实用而方便的ZIP格式文件处理工具。本文通过简明扼要的方式,详细介绍了在各类Linux发行版上安装 `unzip`的方法,以及如何使用 `unzip`命令进行解压、查看和测试ZIP文件。希望本文章能为用户带来实际帮助,提高日常操作的效率。
900 12
|
7月前
|
Linux Shell
Linux系统下快速批量创建和删除文件的方法
总的来说,使用shell脚本来批量处理文件是一种非常强大的工具,只要你愿意花时间学习和实践,你会发现它能大大提高你的工作效率。
436 19
|
7月前
|
Linux
Linux命令的基本格式解析
总的来说,Linux命令的基本格式就像一个食谱,它可以指导你如何使用你的计算机。通过学习和实践,你可以成为一个真正的“计算机厨师”,创造出各种“美味”的命令。
191 15
|
5月前
|
Linux
linux文件重命名命令
本指南介绍Linux文件重命名方法,包括单文件操作的`mv`命令和批量处理的`rename`命令。`mv`可简单更改文件名并保留扩展名,如`mv old_file.txt new_name.txt`;`rename`支持正则表达式,适用于复杂批量操作,如`rename &#39;s/2023/2024/&#39; *.log`。提供实用技巧如大小写转换、数字序列处理等,并提醒覆盖风险与版本差异,建议使用`-n`参数预览效果。
|
8月前
|
监控 Linux
Linux基础:文件和目录类命令分析。
总的来说,这些基础命令,像是Linux中藏匿的小矮人,每一次我们使用他们,他们就把我们的指令准确的传递给Linux,让我们的指令变为现实。所以,现在就开始你的Linux之旅,挥动你的命令之剑,探索这个充满神秘而又奇妙的世界吧!
163 19
下一篇
oss云网关配置