美文网首页
linux 实例讲解elf文件

linux 实例讲解elf文件

作者: tracy_668 | 来源:发表于2018-12-01 14:14 被阅读21次

    elf是一种文件格式,用于存储linux程序,它内部有什么信息呢?大概包括编制好的计算机指令,数据,计算机在需要的时候把这个文件读取到内存中,cpu就可以从内存中一条一条的读取指令来执行。要想明白elf的格式,应该先了解下计算机执行程序需要哪些信息,对此我们先来回顾下计算机系统的一些基础知识:

    虚拟内存

    对于32位的总线,linux系统给每个进程分配了4g的空间,其中 0xC0000000到0xFFFFFFFF 这个地址段是留给系统使用的,主要用于linux内核程序的运行, 用户可以使用3GB的空间从(0x00000000-0xBFFFFFFF)。当然这4g的内存是虚拟内存,一个系统有那么多进程,要是物理内存那还得了,操作系统的虚拟性也是其一重大特征,使用虚拟内存的好处就是各个进程之间的运行空间看起来是独立的,彼此相互不干扰。那么一个进程的创建过程是什么样的呢?

    程序执行过程
    1. 用户请求运行程序时,操作系统会读取存储在磁盘上的可执行文件,(对于linux系统,这个文件就是elf格式文件),然后为用户分配4g的虚拟内存空间。
    2. 根据可执行文件的信息指示,把不同的文件内容放到为你分配的这3g虚拟内存。
    3. 根据可执行文件的信息指示,系统设置代码段和数据段寄存器
    4. 根据可执行文件的信息指示,跳转到用户的代码入口地址(一般就是我们的main函数)
    5. 从main开始,cpu一条条执行我们给的指令,处理我们的数据,直到程序结束。

    我们看到在执行指令前有多次“根据可执行文件提示”,而学习elf就是学习到底是指示了哪些信息。

    可执行的elf文件

    elf文件分三种类型: 目标文件(.o)、可执行文件、动态库(.so),可执行文件一般分成,elf文件头、segment表、section表。下面我们通过一个例子一一介绍下:

    • elf文件头: 这个文件是对elf文件整体信息的描述,在32位系统下是56的字节,在64位系统下是64个字节。
    • segment表:这个表是加载指示器。
     .section .data
    
    .global data_item
    
    data_item:
    
    .long 3,67,28
    
    .section .text
    
    .global _start
    
    _start:
    
        mov $1,%eax
    
        mov $4,%ebx
    
        int $0x80
    

    上面是一段简单的汇编代码,编译: as -o hello.o hello.s 链接: ld -o hello hello.o 完成之后执行readelf -h hello (-h 表示读取elf文件头的命令)

    readelf -h hello
    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   // 程序的入口地址
      Start of program headers:          64 (bytes into file)
      Start of section headers:          472 (bytes into file)
      Flags:                             0x0
      Size of this header:               64 (bytes) 
      Size of program headers:           56 (bytes) //  头长度是56字节(32位系统是56字节)
      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   // 程序入口地址
     Start of program headers:          64 (bytes into file) // segment表在文件64字节偏移处
      Size of program headers:           56 (bytes)
    

    上面内容告诉我们segment表在文件的64字节处,我们看看64字节处有什么内容:
    执行readelf -l hello 输出segments信息,(-l 表示读取segment)

     readelf -l hello
    
    Elf file type is EXEC (Executable file)
    Entry point 0x4000b0
    There are 2 program headers, starting at offset 64
    
    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的entry地址是0x4000b0,这个地址是代码段的起始地址。
    • .data的Offset是0,FileSiz是0xbc,MemSiz是0x0c, VirtAddr是0x6000bc,Flags是R W,表示加载起将把elf文件中从bc字节开始直到oxbc + 0xc处的内容加载到虚拟内存中的0x6000bc处,占用0x0c长度的内存。设置该内存的权限是RE(可读,可执行)
      这样系统就可以根据elf文件提供的这些信息创建进程了。

    相关文章

      网友评论

          本文标题:linux 实例讲解elf文件

          本文链接:https://www.haomeiwen.com/subject/rbkccqtx.html