近期研究了一下elf文件格式,发现好多资料写的都比較繁琐,可能会严重打击学习者的热情,我把自己研究的结果和大家分享,希望我的描写叙述可以简洁一些。

一、基础知识

elf是一种文件格式,用于存储Linux程序. 它内部都有一些什么信息呢?大概包含编制好的计算机指令,数据,计算机在须要的时候把这个文件读取到内存中,cpu就能够从内存中一条一条的读取指令来运行了。

所以说想明确elf格式,我们应该了解一下计算机运行程序须要那些信息。所以这一节,我们补充一些计算机系统的基础知识。

进程和虚拟内存:

Linux系统给每一个进程分配了4GB的空间,当中 0xC0000000到0xFFFFFFFF 这个地址段是留给系统使用的,主要用于系统(linux 内核)和进程通信和交换数据,   用户能够使用3GB的空间从(0x00000000-0xBFFFFFFF).

事实上计算机的内存是没有那么大的,比方我们实际使用的计算机仅仅有2G,曾经更小,仅仅有几百M,并且一台计算机上不仅仅执行一个进程,一个占用4G,假设有10个进程,那就得着用40G了,哪有那么打的内存呢?事实上这个不要紧,由于操作系统分配给用户的是虚拟内存,程序要能够使用3个G的内存。至于操作系统如何把虚拟内存转化成物理内存,对于开发应用程序的project师来说,是不须要了解的。我们直接使用虚拟内存就能够了,而不用操心其他进程会侵犯到你的内存空间。

进程的创建和执行进程的创建和执行:

大致经历了下面步骤

1.用户请求执行程序时,操作系统会读取存储在磁盘上的可执行文件,在linux系统上这个文件就是我们的elf格式文件,为用户分配4G的虚拟内存空间,

2. 依据文件的信息指示,把不同的文件内容放到为你分配的这3G虚拟内存

3. 然后依据文件的指示,系统设置设置代码段和数据段寄存器

4.然后依据文件的指示,    跳转到用户的代码的入口地址(一般就是我们的main函数)

5.从main開始,计算机就一条一条的运行我们给的指令,处理我们的数据了,直到我们程序结束。尽管在这个过程中,系统会多次切换到其它进程,但对用户程序来说没有影响,我们能够觉得计算机仅仅为我们服务。

通过以上我们多次看到计算机是依据文件指示这种语言,所以学习elf 首先要理解elf指示了那些信息。

二、可运行的elf文件。

elf文件分三种类型: 1、目标文件(一般是.o); 2、可执行文件(我们的执行文件)   3、动态库(.so)

我们先讲一下可运行文件。

可运行文件一般分成4个部分,能扩展,我们理解这4部分就够了。

1、elf文件头 ,这个文件是对elf文件总体信息的描写叙述,在32位系统下是56的字节,在64位系统下是64个字节。

对于可运行文件来说,文件头包括的一下信息与进程启动相关

e_entry      程序入口地址

e_phoff      segment偏移

e_phnum   segment数量

2.   segment表, 这个表是载入指示器,操作系统(确切的说是载入器,有些elf文件,比方操作系统内核,是由其它程序载入的),该表的结构很重要。

typedef struct

{

  Elf64_Word    p_type;            /* Segment type */

  Elf64_Word    p_flags;        /* Segment flags */  /*segment权限,6表示可读写,5表示可读可运行

  Elf64_Off    p_offset;        /* Segment file offset */     /*段在文件里的偏移*/

  Elf64_Addr    p_vaddr;        /* Segment virtual address */   /*虚拟内存地址,这个表示内存中的

  Elf64_Addr    p_paddr;        /* Segment physical address  /*物理内存地址,相应用程序来说,这个字段无用*/

  Elf64_Xword    p_filesz;        /* Segment size in file */        /*段在文件里的长度*/

  Elf64_Xword    p_memsz;        /* Segment size in memory */       /在内存中的长度,一般和p_filesz的值一样*/

  Elf64_Xword    p_align;        /* Segment alignment */                  /* 段对齐*/

} Elf64_Phdr;

3.   elf的主题,对于可运行文件来说,最基本的就是数据段和代码段

4.   section表,对可运行文件来说,没实用,在链接的时候实用,是对代码段数据段在链接是的一种描写叙述。

整个elf文件的组成能够使用下图来描写叙述

该图片使用的是Linux C编程作者 宋劲斌的图片

上图program header table 实际上就是我们说的segment table.   segments 是从执行的角度来描写叙述elf文件, sections是从链接的角度来描写叙述elf文件的。

本节我们仅仅将elf文件的运行,所以我们仅仅讲segment相关的内容。

我们将通过一个样例来解说系统载入elf的过程(64位平台)。

我们编写一个简单的汇编程序

.section .data

.global data_item

data_item:

.long 3,67,28

.section .text

.global _start

_start:

    mov $1,%eax

    mov $4,%ebx

    int $0x80

编译链接后生成hello文件,我们分析hello文件.

运行:readelf -h ../asm/hello   (readelf -h 是读取elf文件头的命令)

ELF Header:

  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:                              EXEC (Executable file)

  Machine:                           Advanced Micro Devices X86-64

  Version:                           0x1

  Entry point address:               0x4000b0                                       //程序的入口地址是0x4000b0

  Start of program headers:          64 (bytes into file)                    //segment表在文件64字节偏移处

  Start of section headers:          240 (bytes into file)                    

  Flags:                             0x0

  Size of this header:               64 (bytes)                                       


  Size of program headers:           56 (bytes)                                 //segment头项的长度是56字节(32系统是32字节)  


  Number of program headers:         2

  Size of section headers:           64 (bytes)

  Number of section headers:         6

  Section header string table index: 3

对于程序的装载,我们关心这三项:

Entry point address:               0x4000b0                                       //程序的入口地址是0x4000b0

Start of program headers:          64 (bytes into file)                    //segment表在文件64字节偏移处

Size of program headers:           56 (bytes)                                 //segment头项的长度是56字节(32系统是32字节)

以上内容告诉我们segment表在文件的64字节处,我们看看64字节处有什么内容。

运行 readelf -l ../asm/hello  输出segments信息。(readelf -l 读取segments)

Program Headers:

  Type           Offset             VirtAddr           PhysAddr

                 FileSiz            MemSiz              Flags  Align

  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000

                 0x00000000000000bc 0x00000000000000bc  R E    200000

  LOAD           0x00000000000000bc 0x00000000006000bc 0x00000000006000bc

                 0x000000000000000c 0x000000000000000c  RW     200000



 Section to Segment mapping:

  Segment Sections...

   00     .text

01     .data

我们看到程序有两个segment ,分别叫做.text 和.data

.text的Offset是0,FileSiz是0x0,MemSiz是0xbc, VirtAddr是0x400000,Flags是R E,表示载入起将把elf文件里从0字节開始直到oxbc处的内容载入到虚拟内存中的0x400000处,占用0xbc长度的内存。设置该内存的权限是RE(可读,可运行),这一段的内容正好是elf头,segments table,和代码段。

在看看elfheader 的e_entry  的地址  0x4000b0,这个地址正好是代码段的起始地址。

.data的Offset是0,FileSiz是0xbc,MemSiz是0x0c, VirtAddr是0x6000bc,Flags是R W,表示载入起将把elf文件里从bc字节開始直到oxbc + 0xc处的内容载入到虚拟内存中的0x6000bc处,占用0x0c长度的内存。设置该内存的权限是RE(可读,可运行)

为什么数据段的事实上地址是0x6000bc,而不是0x6000000呢,这是由Align决定的,Align决定内存和磁盘以1M为单位进行映射,在文件里.data 和.text处于一个页面中,在映射的时候,直接把整个页面都映射到了0x6000000处,所以把数据段的偏移设置成了0x60000bc,0x600000到0x6000bc的内容不使用。

有了以上内容,系统就能够依据elf文件创建进程了。

下一节,我们将讲述静态链接编译的过程。

elf格式分析的更多相关文章

  1. Linux ELF格式分析

    http://www.cnblogs.com/hzl6255/p/3312262.html ELF, Executable and Linking Format, 是一种用于可执行文件.目标文件.共享 ...

  2. ELF格式文件分析以及运用

    基于本文的一个实践<使用Python分析ELF文件优化Flash和Sram空间的案例>. 1.背景 ELF是Executable and Linkable Format缩写,其官方规范在& ...

  3. Lab_1:练习4——分析bootloader加载ELF格式的OS的过程

    一.实验内容 通过阅读bootmain.c,了解bootloader如何加载ELF文件.通过分析源代码和通过qemu来运行并调试bootloader&OS, bootloader如何读取硬盘扇 ...

  4. 从实例分析ELF格式的.gnu.hash区与glibc的符号查找

    前言 ELF格式的.gnu.hash节在设计上比较复杂,直接从glibc源码进行分析的难度也比较大.今天静下心来看了这篇精彩的文章,终于将布隆滤波器.算数运算转为位运算等一系列细节搞懂了(值得一提的是 ...

  5. 鸿蒙内核源码分析(ELF格式篇) | 应用程序入口并不是main | 百篇博客分析OpenHarmony源码 | v51.04

    百篇博客系列篇.本篇为: v51.xx 鸿蒙内核源码分析(ELF格式篇) | 应用程序入口并不是main | 51.c.h.o 加载运行相关篇为: v51.xx 鸿蒙内核源码分析(ELF格式篇) | ...

  6. Lab1:练习四——分析bootloader加载ELF格式的OS的过程

    练习四:分析bootloader加载ELF格式的OS的过程. 1.题目要求 通过阅读bootmain.c,了解bootloader如何加载ELF文件.通过分析源代码和通过qemu来运行并调试bootl ...

  7. linux实践之ELF文件分析

    linux实践之ELF文件分析 下面开始elf文件的分析. 我们首先编写一个简单的C代码. 编译链接生成可执行文件. 首先,查看scn15elf.o文件的详细信息. 以16进制形式查看scn15elf ...

  8. 可执行文件(ELF)格式之讲解

    ELF(Executable and Linking Format)是一种对象文件的格式,用于定义不同类型的对象文件(Object files)中都放了什么东西.以及都以什么样的格式去放这些东西.它自 ...

  9. Hex、bin、axf、elf格式文件小结

    转自Hex.bin.axf.elf格式文件小结 一.HEX Hex文件,一般是指Intel标准的十六进制文件.Intelhex 文件常用来保存单片机或其他处理器的目标程序代码.它保存物理程序存储区中的 ...

随机推荐

  1. Python 3语法小记(四)字典 dictionary

    字典是Python里面一种无序存储结构,存储的是键值对 key - value.关键字应该为不可变类型,如字符串.整数.包含不可变对象的元组. 字典的创建很简单,用 d = {key1 : value ...

  2. longest incresing sequence

    动态规划基本题目,longest incresing sequence,找出序列中的最长递增子序列: 例如给出序列{8,3,5,2,4,9,7,11}, 其中最长递增子序列为{3,5,9,11}或{3 ...

  3. CentOS的ssh sftp配置及权限设置(流程相当完整)(关闭了SElinux才能上传了)

    从技术角度来分析,几个要求: 1.从安全方面看,sftp会更安全一点 2.线上服务器提供在线服务,对用户需要控制,只能让用户在自己的home目录下活动 3.用户只能使用sftp,不能ssh到机器进行操 ...

  4. 解决Charles Response 中文乱码

    Response中文乱码:在Info.plist 中 的vmoption 添加-Dfile.encoding=UTF-8 info.plist路径 应用程序->Charles.app->显 ...

  5. 图示CCScrollView的相关概念

    (转载请注明原文地址:http://blog.csdn.net/while0/article/details/11527899) 见下图: 1)设置ScrollView的视口大小的函数是:setVie ...

  6. 遍历关联数组 index by varchar2

    --字符串序列要这样 declare     type t   is table of number(3) index by varchar2(3);    hash_t t;      l_row ...

  7. Response.AppendCookie

    //写入 protected void Button2_Click(object sender, EventArgs e) { HttpCookie cookie=new HttpCookie(&qu ...

  8. ASP.NET Core 中文文档

    ASP.NET Core 中文文档 翻译计划 五月中旬 .NET Core RC2 如期发布,我们遂决定翻译 ASP.NET Core 文档.我们在 何镇汐先生. 悲梦先生. 张仁建先生和 雷欧纳德先 ...

  9. Qt 中文乱码解决大全

    源地址:http://blog.csdn.net/xcy2011sky/article/details/7168376 解决中文乱码,最好知道乱码是什么格式比如说:utf-8. 解决方案: 1.让整个 ...

  10. .net生成Excel,并下载

    生成Excel的方式有很多种,这里记录两个最简单的: 1.将数据保存为html,然后输出到客户端,保存为Excel文件: 2.通过\t\n生成字符串,然后输出到客户端,保存为Excel. 以上两者的原 ...