コンピュータ・システム　オブジェクト・ファイル 3つの形式

# オブジェクト・ファイル

オブジェクト・ファイル、特にリンカに渡されるオブジェクト・ファイルには3つの形式があります。

- 再配置可能オブジェクト・ファイル
- 実行可能オブジェクト・ファイル
- 共有オブジェクト・ファイル

## 再配置可能オブジェクト・ファイル

コンパイラとアセンブラによって生成される。

コンパイル時に他の再配置可能オブジェクト・ファイルと統合し実行可能オブジェクト・ファイルを生成可能な形のバイナリのコードおよびデータを含む。

### ELF[^elf]における典型的な再配置可能オブジェクト・ファイルの形式

[^elf]: Executable and Linkable Format (ELF) コンパイラが生成するオブジェクト、および、ライブラリとリンクされた実行ファイルのファイルフォーマットである。a.outフォーマット、COFFの後継として広く採用されている。セクション数の制限が緩く、メモリ上で連続していないファイルや、ロードされる場所と実行される場所が違う箇所を含む場合にも対応が可能な柔軟な設計となっている。Linux等で使用されている。[Executable and Linkable Format - Wikipedia](https://ja.wikipedia.org/wiki/Executable_and_Linkable_Format)

| セクション | 説明 |
| - | - |
| ELFヘッダ | 最初の16バイトの列: このファイルを生成したシステムのワード・サイズおよびバイト・オーダを示す。<br>残り: リンカがオブジェクト・ファイルを解析し解釈できるようにするための情報 |
| .text | コンパイル済プログラムのマシン・コード |
| .rodata | printf文のフォーマット文字列のような読み込み専用データおよびswitch文のジャンプ・テーブル |
| .data | 初期化済のCのグローバル変数および静的変数。**Cのローカル変数は実行時にスタックに置かれるため、.dataや.bssセクションには現れない。** |
| .bss | 未初期化のCのグローバル変数、静的変数、0に初期化されているグローバル変数および静的変数。このセクションはオブジェクト・ファイル内に実領域が確保されない単なるプレースぽるだである。オブジェクト・ファイル形式は空間効率のために初期化済変数と未初期化変数を区別している。未初期化変数はオブジェクト・ファイル内でディスク領域を消費する必要がない。これらの変数は実行時に0を初期値としてメモリ上に割り当てられる。 |
| .symtab | プログラムが定義・参照している関数およびグローバル変数に関する情報を収めた**シンボル・テーブル**。コンパイラ内部のシンボル・テーブルとは異なり、ローカル変数のエントリは含まれない。 |
| .rel.text | リンカがこのオブジェクト・ファイルを他と統合する際に修正が必要になる.textセクション内の位置のリスト。一般に外部関数を呼び出したり、グローバル変数を参照する目入れはすべて修正が必要になる。一方で、局所関数を呼び出す命令は修正不要である。 |
| .rel.data | このモジュールで参照もしくは定義されるグローバル変数の再配置情報。一般に、グローバル変数や外部関数のアドレスで初期化されるグローバル変数は修正が必要になる。 |
| .debug | このプログラムで定義されているローカル変数及び型のエントリを含むデバグ用シンボル・テーブル及び元のCソース・ファイル。-gオプションでコンパイルされたときのみに存在する。 |
| .line | 元のCソース・プログラムの行番号と.textセクション内のマシン・コード命令との対応関係。-gオプションでコンパイルされたときのみ存在する。 |
| .strtab | .stmtab及び.debugセクション内のシンボル・テーブル及びセクション・ヘッダ内のセクション名用の文字列テーブル。 |
| セクション・ヘッダ・テーブル | オブジェクト・ファイル内の各セクション情報 |


## 実行可能オブジェクト・ファイル

リンカによって生成される。

直接メモリにコピーし、実行可能な形のバイナリのコードおよびデータを含む。

### 典型的なELF実行可能オブジェクト・ファイル

|  |  |
| - | :-: |
| ELFヘッダ | 読み込み専用メモリ・セグメント(コード・セグメント) |
| セグメント・ヘッダ・テーブル | 〃 |
| .init | 〃 |
| .text | 〃 |
| .rodata | 〃 |
| .data | 読み書き可能メモリ・セグメント(データ・セグメント) |
| .bss | 〃 |
| .symtab | シンボル・テーブル及びデバグ情報はメモリにロードされない |
| .debug | 〃 |
| .line | 〃 |
| .strtab | 〃 |
| セクション・ヘッダ・テーブル | 〃 |

- セグメント・ヘッダ・テーブル
    - ファイル内の連続するセクションをメモリ・セグメントに対応づける
- セクション・ヘッダ・テーブル
    - オブジェクト・ファイル内のセクション情報
- ELFヘッダ
    - ファイルの全体形式を記述している。
- .init
    - プログラムの初期化コードから呼び出される_initと呼ばれる小さい関数を定義している
- .text, .rodate及び.dataセクションはこれらのセクションが最終的な実行時メモリ・アドレスに再配置されていることを除き、再配置可能オブジェクトファイルと同様。

## 共有オブジェクト・ファイル (共有ライブラリ)

コンパイラとアセンブラによって生成される。

**特殊な再配置可能オブジェクト・ファイル**であり、ロード時もしくは実行時にメモリに読み込み動的にリンク可能である。

共有ライブラリは、静的ライブラリの欠点を解決するために作られた。共有ライブラリはオブジェクト・モジュールであり、実行時、もしくはロード時に任意のメモリ・アドレスに読み込み、メモリ上のプログラムとリンクすることができる。この過程は動的リンクと呼ばれており、動的リンカと呼ばれるプログラムによって行われる。

| 種類 | 説明 |
| - | - |
| 静的ライブラリ | ライブラリの内容がそれを参照する実行可能ファイルにコピーされ埋め込まれる。 |
| 共有ライブラリ | オブジェクト・モジュールがロード時に任意のメモリアドレスに読み込まれる。<br>ライブラリを参照するすべての実行可能オブジェクト・ファイルで共有される。 |

## オブジェクト・ファイルを操作するツール

| コマンド | 説明 |
| - | - |
| ar | 静的ライブラリを作成し、メンバを挿入、消去、列挙、抽出する。 |
| strings | オブジェクト・ファイルに含まれる印刷可能な文字列を列挙する。 |
| strip | オブジェクト・ファイルからシンボル・テーブル情報を消去する。 |
| nm | オブジェクト・ファイル内のセクションの名前とサイズを列挙する。 |
| readelf | ELFヘッダにエンコードされた情報を含む、オブジェクト・ファイルの完全な構造を表示する。sizeとnmの機能を含む。 |
| objdump | すべてのバイナリ・ツールの母体・オブジェクト・ファイルのすべての情報を表示できる。もっとも有用なのは.textセクション内のバイナリ命令をディスアセンブルする機能である。 |
| ldd | 実行可能ファイルが実行時に必要な共有ライブラリを列挙する。 |

objdump等は以下でインストールできます。

```sh
brew install binutils
```

## elfをMacで見たかったら

リナックス向けにコンパイルします。

```sh
clang --target=aarch64-unknown-linux-gnu -c file.c
```

ファイルコマンドで確認できます。

```sh
$ file file.o
file.o: ELF 64-bit LSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
```

readelfコマンドも使えます

```
$ readelf -h file.o
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:                              REL (Relocatable file)
  Machine:                           AArch64
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          504 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           64 (bytes)
  Number of section headers:         9
  Section header string table index: 1

```

## 参考

[コンピュータ・システム](https://amzn.to/3mlYzwZ): 7章
[clang - How to build ELF on MacOS using LLVM? - Stack Overflow](https://stackoverflow.com/questions/60362329/how-to-build-elf-on-macos-using-llvm)