「あの人も読んでる」略して「も読」。さまざまな寄稿者が最近気になった情報や話題をシェアする企画です。他のテックな人たちがどんな情報を追っているのか、ちょっと覗いてみませんか?
こんにちは。
前回の記事ではリンカーの概要と『リンカ・ローダ実践開発テクニック』という本について紹介しました。リンカーとはなにか、どんな仕事をしているのかについてなんとなくイメージできたかなと思います。
今回はオブジェクトファイルについて少し詳細を話していきます。
オブジェクトファイルとは
前回の記事では次のように説明しました。
オブジェクトファイルはソースファイル単位で独立してコンパイルすることができ、命令やグローバルな変数、定数といったデータを持っています。
オブジェクトファイルにはフォーマットがあって、OSによって異なっています。 それぞれのフォーマットは次の表に示します。
OS | フォーマット |
---|---|
Unix/Linux | ELF(Executable and Linkable Format) |
macOS | Mach-O(Mach object) |
Windows | COFF(Common Object File Format) |
今日のウェブシステム開発ではコンテナが主流で、ELFはなんとなく知っている方もいるのではないと思うので、今回はELFについて少し掘り下げていきます。
ELF(Executable and Linkable Format)について
ELF
は名前のとおり、実行・リンク可能なフォーマットとなっています。
ファイルが実行可能なのか、リンク可能なのかを判断するにはreadelf
コマンドを使います。
$ readelf -h a.out | grep Type
Type: EXEC (Executable file)
$ readelf -h a.o | grep Type
Type: REL (Relocatable file)
Relocatable file
は再配置(前回記事参照)情報を持ったリンク可能なファイルです。
ELF
は大き分けると次の領域で構成されています。
構成 | 概要 |
---|---|
ヘッダー | ELFファイルのメタデータ、OSのアーキテクチャなどの情報を持つ |
プログラムヘッダー | プログラムを実行する際に必要な情報を持つ |
セクション | ELFファイル内の実際のプログラムデータやコードの情報を持つ |
セクションヘッダー | ELFファイル内の各セクションの位置、サイズ、属性などの情報を持つ |
セクションは更にいくつか種類があります。
代表なものとして.data
や.text
、.symtab
があります。
.text
は命令群(アセンブリ)が配置されていて、objdump
でそれらを確認できます。
$ objdump -d a.out
a.out: file format elf64-littleaarch64
Disassembly of section .text:
0000000000400100 <_start>:
400100: 10080080 adr x0, 410110 <x>
400104: b9400000 ldr w0, [x0]
400108: d2800ba8 mov x8, #0x5d // #93
40010c: d4000001 svc #0x0
生データはこんな感じですね。
$ readelf -x .text a.out
Hex dump of section '.text':
0x00400100 80000810 000040b9 a80b80d2 010000d4 ......@.........
.data
は.text
の命令で使われているデータが配置されます。
$ readelf -x .data a.out
Hex dump of section '.data':
0x00410110 17000073 ...s
.symtab
はシンボル(変数など)のアドレス値や種類などの情報を持っています。
これらは実行時には不要ですが、デバッグ時に使用します。
$ readelf -s a.out
Symbol table '.symtab' contains 8 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 SECTION LOCAL DEFAULT 4
2: 0000000000000000 0 FILE LOCAL DEFAULT ABS sub.c
3: 0000000000410110 0 NOTYPE LOCAL DEFAULT 2 $d
4: 0000000000000000 0 FILE LOCAL DEFAULT ABS main.c
5: 0000000000400100 0 NOTYPE LOCAL DEFAULT 1 $x
6: 0000000000400100 0 NOTYPE GLOBAL DEFAULT 1 _start
7: 0000000000410110 4 OBJECT GLOBAL DEFAULT 2 x
テキストだとあんまり全体像を掴めない方は以下の図を参照してください。大変わかりやすくにまとまっているかなと思います。
corkami「ELF101-64」(CC BY 3.0)
更に細かく知りたい方は『[全部無料]最小限で理解しつつ作るELF parser入門 in Rust』という本がzenn.devで公開されているので、実装しながら理解したい方はぜひこちらをやってみてください。
さいごに
今回はオブジェクトファイルとELFについて少し掘り下げつつ、ELFパーサー実装本について紹介しました。 少し興味を持っていただけたら嬉しいです。
次回は、高速なリンカーmoldについて、少し深堀りしていきます。
ゴリラさんの「も読」過去記事
- リンカ・ローダ実践開発テクニック (5月1日公開)