3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Executable and Linkable Format (ELF) バイナリのロード方法

Posted at

概要

Linuxで使われるバイナリのフォーマットのELFについて、特にexecシステムコールから呼ばれる実行ファイルのロードの処理を調べた。

ELFの構造

ヘッダが3つと、それらでポイントされるデータによって構成されている。
フラグの意味と構造体の表はWikipediaにまとまっている。

  • File header
  • Program header
  • Section header

File header

ファイルの最初にあり、バイナリそのものの属性と、他のヘッダ情報のテーブル開始位置のファイルオフセットe_*hoff、と個数e_*hnumを格納している。

juntaki@dev ~> readelf -e (which ls)
ELF ヘッダ:
  マジック:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  クラス:                            ELF64
  データ:                            2 の補数、リトルエンディアン
  バージョン:                        1 (current)
  OS/ABI:                            UNIX - System V
  ABI バージョン:                    0
  型:                                EXEC (実行可能ファイル)
  マシン:                            Advanced Micro Devices X86-64
  バージョン:                        0x1
  エントリポイントアドレス:               0x4049a0
  プログラムの開始ヘッダ:          64 (バイト)
  セクションヘッダ始点:          124728 (バイト)
  フラグ:                            0x0
  このヘッダのサイズ:                64 (バイト)
  プログラムヘッダサイズ:            56 (バイト)
  プログラムヘッダ数:                9
  セクションヘッダ:                  64 (バイト)
  セクションヘッダサイズ:            29
  セクションヘッダ文字列表索引:      28

構造体はこんな感じ。

typedef struct elf64_hdr {
  unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */
  Elf64_Half e_type;
  Elf64_Half e_machine;
  Elf64_Word e_version;
  Elf64_Addr e_entry;   /* Entry point virtual address */
  Elf64_Off e_phoff;    /* Program header table file offset */
  Elf64_Off e_shoff;    /* Section header table file offset */
  Elf64_Word e_flags;
  Elf64_Half e_ehsize;
  Elf64_Half e_phentsize;
  Elf64_Half e_phnum;
  Elf64_Half e_shentsize;
  Elf64_Half e_shnum;
  Elf64_Half e_shstrndx;
} Elf64_Ehdr;

Program header

load_elf_phdrs()でポインタ配列として読み込まれる。

load_elf_phdrs()
  size = sizeof(struct elf_phdr) * elf_ex->e_phnum;
  if (size > ELF_MIN_ALIGN)
    goto out;

  elf_phdata = kmalloc(size, GFP_KERNEL);
  if (!elf_phdata)
    goto out;

  /* Read in the program headers */
  retval = kernel_read(elf_file, elf_ex->e_phoff,
           (char *)elf_phdata, size);

Program headerの構造体で、ファイル内でのオフセットはp_offset、ファイル上でのサイズはp_fileszで指定して各ヘッダが指す内容を読み取ることができる。
ファイル上でのサイズはメモリ上でのサイズp_memszより小さくなりうる(差分はゼロ埋めされる)
特に実行ファイルの場合、p_flagsPT_LOADのものがメモリ上にロードされる。

typedef struct elf64_phdr {
  Elf64_Word p_type;
  Elf64_Word p_flags;
  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 */
  Elf64_Xword p_align;    /* Segment alignment, file & memory */
} Elf64_Phdr;

メモリへのPT_LOADタイプのロードの関数では、p_vaddrから、p_memsz分バイナリファイルがマップされる。

load_elf_binary()
  /* Now we do a little grungy work by mmapping the ELF image into
     the correct location in memory. */
// elf_phdataはProgram headerの配列
  for(i = 0, elf_ppnt = elf_phdata;
      i < loc->elf_ex.e_phnum; i++, elf_ppnt++) {

// PT_LOADのみ対象
    if (elf_ppnt->p_type != PT_LOAD)
      continue;
...

    if (unlikely (elf_brk > elf_bss)) {
      unsigned long nbyte;

      /* There was a PT_LOAD segment with p_memsz > p_filesz
         before this one. Map anonymous pages, if needed,
         and clear the area.  */
  
// ファイル上のサイズより、大きいメモリサイズ(p_memsz)の指定があった場合、
// ファイルをマップするだけではダメなので、setbrkでmemsz分のメモリの確保と
// 初期化をする。
...

    }

// メモリに対する権限(elf_prot)、Read/Write/Executeの設定、
// 共有ライブラリのロードのため、mmapの開始位置(load_bias)を変更する
...

// elf_map()でmmapする
    error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt,
        elf_prot, elf_flags, total_size);

とりあえず、一旦ここまで!

3
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?