ELF檔案格式解析

2023-04-16 21:00:33

   ELF(Executable and Linkable Format) 即可執行可連結檔案格式,是目前作業系統上最常見的可執行檔案格式。不同系統的目標檔案不一樣,Windows是PE(Portable Executable),linux是ELF(Executable Linkable Format),它們都是COFF(Common file format)格式的變種。

1、基本格式

      ELF格式的目標檔案和可執行檔案在結構上沒有本質差異,ELF不僅僅描述目標檔案,也用於描述可執行檔案,Windows下的dll和.lib, Linux下的.so和.a檔案都是按照類ELF格式儲存,下圖描述了ELF連結檢視(.o檔案、.so檔案)和執行檢視,連結檢視描述了各個段(section)的組成,如.text、.data、bss段。執行檢視由segment組成,segment用於表示一個一定長度的區域,按照唯讀/可讀寫劃分,不區分資料的屬性,如程式碼段、資料段。

      目標檔案是未經過連結的,裡面的符號和地址沒有調整導致無法執行。例如直接執行目標檔案,系統提示無法執行該二進位制檔案。

$ . hello.o
bash: .: hello.o: cannot execute binary file
$ file hello.o
hello.o: Intel amd64 COFF object file, no line number info, not stripped, 7 sections, symbol offset=0x2a0, 22 symbols, 1st section name ".text"

     ELF檔案格式在位元組對齊和元素解析時,與系統架構、字長有密切關係,ELF 檔案由ELF header和各種段組成,其結構圖如下所示。詳細檔案可以查閱https://elinux.org/Executable_and_Linkable_Format_(ELF)

 

2、ELF檔案頭

     ELF 檔案的最前面是檔案頭,描述了ELF檔案的基本屬性,比如ELF檔案版本、目標機器型號、程式入口地址。

     詳細的描述可以參考:https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.eheader.html

#define EI_NIDENT 16

typedef struct {
        unsigned char   e_ident[EI_NIDENT];
        Elf32_Half      e_type;
        Elf32_Half      e_machine;
        Elf32_Word      e_version;
        Elf32_Addr      e_entry;
        Elf32_Off       e_phoff;
        Elf32_Off       e_shoff;
        Elf32_Word      e_flags;
        Elf32_Half      e_ehsize;
        Elf32_Half      e_phentsize;
        Elf32_Half      e_phnum;
        Elf32_Half      e_shentsize;
        Elf32_Half      e_shnum;
        Elf32_Half      e_shstrndx;
} Elf32_Ehdr;


$ readelf -h /bin/ls 
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:                              DYN (Position-Independent Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x6180
  Start of program headers:          64 (bytes into file)
  Start of section headers:          145256 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         11
  Size of section headers:           64 (bytes)
  Number of section headers:         30
  Section header string table index: 29

上面結構體裡成員型別長度的定義為:

名稱

大小

說明

Elf32_Addr

4

無符號程式地址

Elf32_Half

2

無符號中等整數

Elf32_Off

4

無符號檔案偏移

Elf32_SWord

4

有符號大整數

Elf32_Word

4

無符號大整數

unsigned char

1

無符號笑整數

Elf32_Ehdr 各個成員簡介:

  • e_ident magic bytes (0x7fELF), class, ABI version....是一組包含多個標誌的陣列。
  • e_typeobject file type—ET{REL,DYN,EXEC,CORE} 00-未知, 01--RT_REL,02--ET_EXEC, 03---ET_DY
  • e_machine required architecture—EM X86 64, ... 其中3h=386, 28h=ARM
  • e_version EV CURRENT, always 」1」
  • e_entry virt. addr. of entry point, dl start, jmp *%r12
  • e_phoff program header offset
  • e_shoff section header offset
  • e_flags CPU-specific flags
  • e_ehsize ELF header size
  • e_phentsize size of program header entry, consistency check
  • e_phnum number of program header entries
  • e_shentsize size of section header entry
  • e_shnum number of section header entries
  • e_shstrndx section header string table index

     其中e_ident 對應了對各欄位,有MAGIC、Class、Data、Version、 ABI這幾個引數。

Name

Value

Purpose

EI_MAG0

0

File identification

EI_MAG1

1

File identification

EI_MAG2

2

File identification

EI_MAG3

3

File identification

EI_CLASS

4

File class

EI_DATA

5

Data encoding

EI_VERSION

6

File version

EI_OSABI

7

Operating system/ABI identification

EI_ABIVERSION

8

ABI version

EI_PAD

9

Start of padding bytes

EI_NIDENT

16

Size of e_ident[]

1)MAGIC是ELF標誌碼:魔數,佔4位元組,byte0固定為0x7F,byte1--byte3是'E', 'L', 'F' 的ASCII碼。

2)EI_CLASS 是CPU字長型別。

Name

Value

Meaning

ELFCLASSNONE

0

Invalid class

ELFCLASS32

1

32-bit objects

ELFCLASS64

2

64-bit objects

3)EI_DATA

0:非法格式

1:小端位元組序LSB

2:大端位元組序MSB

4)EI_VERSION: ELF版本號,為1

5)EI_OSABI

Name

Value

Meaning

ELFOSABI_NONE

0

No extensions or unspecified

ELFOSABI_HPUX

1

Hewlett-Packard HP-UX

ELFOSABI_NETBSD

2

NetBSD

ELFOSABI_LINUX

3

Linux

ELFOSABI_SOLARIS

6

Sun Solaris

ELFOSABI_AIX

7

AIX

ELFOSABI_IRIX

8

IRIX

ELFOSABI_FREEBSD

9

FreeBSD

ELFOSABI_TRU64

10

Compaq TRU64 UNIX

ELFOSABI_MODESTO

11

Novell Modesto

ELFOSABI_OPENBSD

12

Open BSD

ELFOSABI_OPENVMS

13

Open VMS

ELFOSABI_NSK

14

Hewlett-Packard Non-Stop Kernel

 

64-255

Architecture-specific value range

3、段表--Section

1)段表的結構

    ELF 檔案中有很多段,段表(Section Header Table)就是儲存這些段的基本屬性的結構。段表描述了ELF各個段的資訊,如段名、段的長度、在檔案中的偏移、讀寫許可權等。段表在ELF檔案中 的偏移是由檔案頭的e_shoff成員決定的。

typedef struct{
    Elf32_Word sh_name;
    Elf32_Word sh_type;
    Elf32_Word sh_flags;
    Elf32_Addr sh_addr;
    Elf32_Off  sh_offset;
    Elf32_Word sh_size;
    Elf32_Word sh_link;
    Elf32_Word sh_info;
    Elf32_Word sh_addralign;
    Elf32_Word sh_entsize;
}Elf32_Shdr

Elf32_Shdr成員含義:

  • sh_name 段名,但此次只是記錄了段名字串在 .shstrtab 中的偏移
  • sh_type 段的型別
  • sh_flags 段的標誌位
  • sh_addr 段的虛擬地址,如果此段可以被載入則表示在程序中的虛擬地址,否則為0
  • sh_offset 如果此段位於檔案中則表示此段在檔案中的偏移
  • sh_size 段的長度
  • sh_link This member holds a section header table index link, whose interpretation depends on the section type.
  • sh_info This member holds extra information, whose interpretation depends on the section type.
  • sh_addralign 段對齊,以2的n次方表示,如果為0或1,表示沒有對齊要求。
  • sh_entsize Section Entry Size段的長度

 sh_type :段的型別。

Name

Value

SHT_NULL

0

SHT_PROGBITS

1

SHT_SYMTAB

2

SHT_STRTAB

3

SHT_RELA

4

SHT_HASH

5

SHT_DYNAMIC

6

SHT_NOTE

7

SHT_NOBITS

8

SHT_REL

9

SHT_SHLIB

10

SHT_DYNSYM

11

SHT_LOPROC

0x70000000

SHT_HIPROC

0x7fffffff

SHT_LOUSER

0x80000000

SHT_HIUSER

0xffffffff

sh_flag:段的標誌位,表示該段在程序的虛擬地址空間中的屬性,如是否可讀、寫、執行。

Name

Value

notes

SHF_WRITE

0x1

可讀

SHF_ALLOC

0x2

需要分配空間

SHF_EXECINSTR

0x4

可執行

SHF_MASKPROC

0xf0000000

 

sh_link 和 sh_info: 如果段是與連結相關的,比如重定位表符號表等,sh_link和sh_info這兩個成員所包含的意義如下所示。

sh_type

sh_link

sh_info

SHT_DYNAMIC

該段所使用的字串表在段表中的下標

0

SHT_HASH

該段所使用的符號表在段表中的下標

0

SHT_REL

該段所使用的相應符號表在段表中的下標

該重定位表所作用的段在段表中的下標

SHT_RELA

該段所使用的相應符號表在段表中的下標

該重定位表所作用的段在段表中的下標

SHT_SYMTAB

作業系統相關的

作業系統相關的

SHT_DYNAMIC

作業系統相關的

作業系統相關的

other

SHN_UNDEF

0

2)重定位表

    rel.txt段就是重定位表,型別sh_type為SHT_REL(9)。連結器在處理目標檔案時,對目標檔案某些部位進行重定位,即程式碼段和資料段中的那部分絕對地址參照。這些重定位資訊記錄在ELF檔案的重定位表中。

3)字串表

    ELF中有很多字串,如變數名段名等,但是字串長度是不定長的,如果用固定的長度來表示比較困難,常見的做法是把字串集中起來放到一個表中,然後使用字串在表中的偏移來參照字串。

4)符號表

    在ELF檔案中,把函數和變數統稱為符號(Sysbol),每個符號有一個相應的值叫做符號值。對函數和變數來說,符號值就是它們的地址。在ELF檔案中,用.symtab這個段來記錄符號表。

typedef struct{
    Elf32_Word st_name;
    Elf32_Addr st_value;
    Elf32_Word st_size;
    unsigned char st_info;
    unsigned char st_other;
    Elf32_Half st_shndx;
}Elf32_Sym
  • st_name 符號名,符號名稱在字串表中的索引
  • st_value 符號相應的值,可能是地址或一個絕對值數
  • st_size 符號大小
  • st_info 符號型別和繫結值
  • st_other 預設0
  • st_shndx 符號所在的段

st_info 高4位元表示符號繫結資訊,低4位元表示符號型別。

Symbol Binding, ELF32_ST_BIND

Name

Value

STB_LOCAL

0

STB_GLOBAL

1

STB_WEAK

2

STB_LOPROC

13

STB_HIPROC

15

Symbol Types, ELF32_ST_TYPE

Name

Value

STT_NOTYPE

0

STT_OBJECT

1

STT_FUNC

2

STT_SECTION

3

STT_FILE

4

STT_LOPROC

13

STT_HIPROC

15

5)全域性偏移表和跳轉表

.plt和.got 動態連結的跳轉表和全域性入口表。

 

6)其它

程式碼段(.text): 程式碼資料

資料段(.data): 初始化過了的全域性變數和區域性靜態變數

唯讀資料段(.rodata) 唯讀資料如const值、字串常數。

.bss段:未初始化的全域性變數和區域性變數,是否為全域性變數和區域性變數預留空間和編譯器的實現相關。

自定義段:在變數和函數前加__attribute__((section("name"))) 屬性就可以把相應的函數或變數放到以name作為段名的段中。

 

4、ELF檔案載入檢視

    雖然ELF把可變資料和不可變資料分的很細,使用者也可以自己新增段或命名一個段,但載入器把ELF檔案載入到記憶體時,並不按照ELF的結構讀取。例如目標檔案.o裡的程式碼段.text是section,連結時多個可重定位檔案整合成一個可執行的檔案,為了提高程式的效率,連結器把目標檔案中相同的section 整合成一個segment,方便執行時載入器載入程式。由於虛擬記憶體的對映和優化的存在,ELF檔案在載入到虛擬記憶體時,也會合並不同的段來達到節約資源的目的。

 

5、參考文獻

1、Linux Referenced Specifications https://refspecs.linuxbase.org/

2、Executable and Linkable Format (ELF) https://elinux.org/Executable_and_Linkable_Format_(ELF)

3、ELF檔案格式 https://zhuanlan.zhihu.com/p/286088470

尊重原創技術文章,轉載請註明: https://www.cnblogs.com/pingwen/p/17323862.html