わらばんし仄聞記

南の国で引きこもってるWeb屋さん

ELFファイルを作る part3

part2では非常に単純化したELFファイルを作成しましたが、この状態から作成されるファイルに対してobjdump等を実行してもメインの実行コードについての情報が出てきません。
なので、今後進めていった際、不具合に遭遇した場合の問題解決を容易にするためにも、これにsectionヘッダーを追加してそれらの情報が出るようにします。

目標

part2で作成したELFファイルにsectionヘッダーを追加し、objdumpでメインの実行コード(_start配下に記載される箇所)を検出できるようにする

実装

part2でのELFをベースとし、sectionヘッダー部を追加。それに会わせてELFヘッダー部も調整する。

コード

sectionヘッダーの各バイトへ格納する値を示す構造体定義は、programヘッダーと同様に /usr/include/linux/elf.h へ記述があります。

typedef struct elf64_shdr {
  Elf64_Word sh_name;       /* Section name, index in string tbl */
  Elf64_Word sh_type;       /* Type of section */
  Elf64_Xword sh_flags;     /* Miscellaneous section attributes */
  Elf64_Addr sh_addr;       /* Section virtual addr at execution */
  Elf64_Off sh_offset;      /* Section file offset */
  Elf64_Xword sh_size;      /* Size of section in bytes */
  Elf64_Word sh_link;       /* Index of another section */
  Elf64_Word sh_info;       /* Additional section information */
  Elf64_Xword sh_addralign; /* Section alignment */
  Elf64_Xword sh_entsize;   /* Entry size if section holds table */
} Elf64_Shdr;

これらの値についての説明は仕様書を見るなり、他のサイトを参照して貰った方が既に纏まってるので割愛。
個人的なメモとしては

  • sh_name:このsectionの名前がstringテーブル(前述のelf64-section.asmでshstrtblとラベルが設定されている箇所)でどこに指定されているかを表すインデックス値(=stringテーブル先頭からのオフセット値)。|
  • sh_addr:プロセスメモリ中に、このsectionヘッダが示す内容が保持される際の最初のアドレス。プロセスメモリ中へは現れないなら0を入れる。
  • sh_offset:このsectionヘッダが何について書かれているか、その対象がどこにあるかを指すオフセット値。

といったように、基本的にsectionヘッダはどこかの領域に対しての説明を持つ事になり、オフセットやアドレス、サイズといった値の指定はその対象の領域についてを示す事になる。

sectionヘッダーは複数記述することができ、これらを記述する際、最初のsectionヘッダーは全て0で埋める事が決められている。
http://downloads.openwatcom.org/ftp/devel/docs/elf-64-gen.pdf (PDFファイル)より、

The first entry in the section header table (with an index of 0) is reserved, and must contain all zeroes.

elf64-section.asmでは、「各sectionヘッダーの名前を保持するテーブル」についてのsectionヘッダーは、sectionヘッダーの列挙内では2番目=indexは1の位置に記述されているので、ELFヘッダーのe_shstrndxに対応する箇所が1になっている。また、e_shnumも予約として0で埋められているsectionヘッダーを含めた数の3となっている。

実行

$ nasm -f bin -o nasm.out elf64-sectino.asm
$ ./nasm.out
$ echo $?
42

処理自体は期待される値を得られ、

$ objdump -S -M intel nasm.out
nasm.out:     file format elf64-x86-64


Disassembly of section .text:

0000000008048078 <.text>:
 8048078:       b8 3c 00 00 00          mov    eax,0x3c
 804807d:       bf 2a 00 00 00          mov    edi,0x2a
 8048082:       0f 05                   syscall

objdumpから実行されているコードの解釈についても情報を得られた。