ELFのことを少し勉強した
ELFについて
ELFとは、Executable and Linkable Format のことです。Linuxのシステムにおいて標準のバイナリフォーマットになっています。
ELFの構成
ELFは大きく以下の4つに分けることができます。
- 実行可能ヘッダー
- プログラムヘッダー
- セクション
- セクションヘッダー
ELFの定義を見る
ターミナルでman elf
を入力すると見ることができます。
↓実行可能ヘッダーのみ抜粋
#define EI_NIDENT 16 typedef struct { unsigned char e_ident[EI_NIDENT]; uint16_t e_type; uint16_t e_machine; uint32_t e_version; ElfN_Addr e_entry; ElfN_Off e_phoff; ElfN_Off e_shoff; uint32_t e_flags; uint16_t e_ehsize; uint16_t e_phentsize; uint16_t e_phnum; uint16_t e_shentsize; uint16_t e_shnum; uint16_t e_shstrndx; } ElfN_Ehdr;
準備
#inlucde <stdio.h> void main() { printf("Hello World!\n"); }
このプログラムをgcc hello.c
でコンパイルします。
実行可能ヘッダーを見る
hello.cをコンパイルした時に作られたa.outの実行可能ヘッダーを見てみます。
実行可能ヘッダーを見るときはreadelf -h a.out
を打ちます。
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 (Shared object file) Machine: Advanced Micro Devices X86-64 Version: 0x1 Entry point address: 0x1060 Start of program headers: 64 (bytes into file) Start of section headers: 14712 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 13 Size of section headers: 64 (bytes) Number of section headers: 31 Section header string table index: 30
実行可能ヘッダーでは、このバイナリファイルの種類やアーキテクチャのビット数、バイトオーダーなどを確認することができます。
プログラムヘッダー
次はプログラムヘッダーを確認しましょう。readelf -l -W a.out
を入力してください。
Elf file type is DYN (Shared object file) Entry point 0x1060 There are 13 program headers, starting at offset 64 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align PHDR 0x000040 0x0000000000000040 0x0000000000000040 0x0002d8 0x0002d8 R 0x8 INTERP 0x000318 0x0000000000000318 0x0000000000000318 0x00001c 0x00001c R 0x1 [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x0005f8 0x0005f8 R 0x1000 LOAD 0x001000 0x0000000000001000 0x0000000000001000 0x0001e5 0x0001e5 R E 0x1000 LOAD 0x002000 0x0000000000002000 0x0000000000002000 0x000160 0x000160 R 0x1000 LOAD 0x002db8 0x0000000000003db8 0x0000000000003db8 0x000258 0x000260 RW 0x1000 DYNAMIC 0x002dc8 0x0000000000003dc8 0x0000000000003dc8 0x0001f0 0x0001f0 RW 0x8 NOTE 0x000338 0x0000000000000338 0x0000000000000338 0x000020 0x000020 R 0x8 NOTE 0x000358 0x0000000000000358 0x0000000000000358 0x000044 0x000044 R 0x4 GNU_PROPERTY 0x000338 0x0000000000000338 0x0000000000000338 0x000020 0x000020 R 0x8 GNU_EH_FRAME 0x002014 0x0000000000002014 0x0000000000002014 0x000044 0x000044 R 0x4 GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10 GNU_RELRO 0x002db8 0x0000000000003db8 0x0000000000003db8 0x000248 0x000248 R 0x1 Section to Segment mapping: Segment Sections... 00 01 .interp 02 .interp .note.gnu.property .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt 03 .init .plt .plt.got .plt.sec .text .fini 04 .rodata .eh_frame_hdr .eh_frame 05 .init_array .fini_array .dynamic .got .data .bss 06 .dynamic 07 .note.gnu.property 08 .note.gnu.build-id .note.ABI-tag 09 .note.gnu.property 10 .eh_frame_hdr 11 12 .init_array .fini_array .dynamic .got
プログラムヘッダーはELFを実行するための情報を持っています。
セクションヘッダー
続いてセクションヘッダーです。readelf -S -W a.out
を入力してください。
There are 31 section headers, starting at offset 0x3978: Section Headers: [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 [ 1] .interp PROGBITS 0000000000000318 000318 00001c 00 A 0 0 1 [ 2] .note.gnu.property NOTE 0000000000000338 000338 000020 00 A 0 0 8 [ 3] .note.gnu.build-id NOTE 0000000000000358 000358 000024 00 A 0 0 4 [ 4] .note.ABI-tag NOTE 000000000000037c 00037c 000020 00 A 0 0 4 [ 5] .gnu.hash GNU_HASH 00000000000003a0 0003a0 000024 00 A 6 0 8 [ 6] .dynsym DYNSYM 00000000000003c8 0003c8 0000a8 18 A 7 1 8 [ 7] .dynstr STRTAB 0000000000000470 000470 000082 00 A 0 0 1 [ 8] .gnu.version VERSYM 00000000000004f2 0004f2 00000e 02 A 6 0 2 [ 9] .gnu.version_r VERNEED 0000000000000500 000500 000020 00 A 7 1 8 [10] .rela.dyn RELA 0000000000000520 000520 0000c0 18 A 6 0 8 [11] .rela.plt RELA 00000000000005e0 0005e0 000018 18 AI 6 24 8 [12] .init PROGBITS 0000000000001000 001000 00001b 00 AX 0 0 4 [13] .plt PROGBITS 0000000000001020 001020 000020 10 AX 0 0 16 [14] .plt.got PROGBITS 0000000000001040 001040 000010 10 AX 0 0 16 [15] .plt.sec PROGBITS 0000000000001050 001050 000010 10 AX 0 0 16 [16] .text PROGBITS 0000000000001060 001060 000175 00 AX 0 0 16 [17] .fini PROGBITS 00000000000011d8 0011d8 00000d 00 AX 0 0 4 [18] .rodata PROGBITS 0000000000002000 002000 000011 00 A 0 0 4 [19] .eh_frame_hdr PROGBITS 0000000000002014 002014 000044 00 A 0 0 4 [20] .eh_frame PROGBITS 0000000000002058 002058 000108 00 A 0 0 8 [21] .init_array INIT_ARRAY 0000000000003db8 002db8 000008 08 WA 0 0 8 [22] .fini_array FINI_ARRAY 0000000000003dc0 002dc0 000008 08 WA 0 0 8 [23] .dynamic DYNAMIC 0000000000003dc8 002dc8 0001f0 10 WA 7 0 8 [24] .got PROGBITS 0000000000003fb8 002fb8 000048 08 WA 0 0 8 [25] .data PROGBITS 0000000000004000 003000 000010 00 WA 0 0 8 [26] .bss NOBITS 0000000000004010 003010 000008 00 WA 0 0 1 [27] .comment PROGBITS 0000000000000000 003010 00002b 01 MS 0 0 1 [28] .symtab SYMTAB 0000000000000000 003040 000618 18 29 46 8 [29] .strtab STRTAB 0000000000000000 003658 000203 00 0 0 1 [30] .shstrtab STRTAB 0000000000000000 00385b 00011a 00 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), l (large), p (processor specific)
ELFは、バイナリのコードとデータをセクションに分割します。セクションの構造自体はその内容によって異なり、各セクションの説明はセクションヘッダーに記載されています。
セクション
セクションヘッダーに書かれていたセクションには、具体的にどのようなものがあるのでしょうか。
- .initセクション
このセクションには、初期化を行う実行可能コードが含まれています。 - .textセクション
プログラムのメインコードを含んでいるセクションです。 - .rodata
定数値の格納を目的とするセクションです。
上記で紹介したのはセクションの一部です。
おわりに
ELFの勉強目的でこのブログを書いてみましたが、まだまだわからないことだらけです。各ヘッダーの詳しいことなどは今後書いていこうと思います。