2026-01-03 (更新: 2026-05-20)
オブジェクトファイル解説|.oファイルの内部構造とセクション・シンボルテーブルの仕組み
シリーズ この記事は「コンパイル・リンク・ビルド(組み込み基礎)」の一部です。 シリーズ目次を見る
(2026年5月時点)C/C++ のビルドで生成される オブジェクトファイル(.o) の見取り図として、代表的なセクション、シンボルテーブル、再配置情報を整理します。ツールチェーンや OS により細部は違うので、readelf / nm / objdump の出力は 自分の環境で当たり確認しながら読む前提です。
- 症状→読む順(先にこれ):リンクで落ちる → nm の 未定義(U) と objdump -r の再配置 → セクションは readelf -S。配置・サイズは .map。
- .o を疑う目安:あるシンボルがどの .o にも定義が無い/常に U のままで、ライブラリ指定の前に翻訳単位の取り込み漏れを疑うとき。
オブジェクトファイルの位置づけとは?
オブジェクトファイルは、コンパイルとアセンブルを経て生成される中間バイナリファイルです。機械語に変換済みですが、外部シンボルのアドレスが未解決のため、単体では実行できません。ソースファイル1つにつき1つのオブジェクトファイルが生成されます(main.c → main.o)。
ビルドプロセスにおけるオブジェクトファイルの位置
セクション構造(.text / .data / .bss)とは?
オブジェクトファイルの内部は、役割ごとに「セクション」に分割されています。これはプログラムの異なるデータ種別を分類して管理するための仕組みです。
オブジェクトファイルの内部構造
各セクションの役割
セクションの役割
- .text:コンパイルされた機械語命令(関数の実行コード)。組み込み MCU などではフラッシュ側に載せて実行することが多い(配置はプラットフォーム依存)
- .data:初期値を持つグローバル変数・static変数が格納される。初期値分のサイズが実行ファイルに含まれる
- .bss:未初期化(または0初期化)のグローバル変数・static変数。サイズ情報のみ記録し、実行ファイルのサイズを圧迫しない
- .rodata:読み取り専用データ(文字列リテラル、const変数)が格納される
// セクションへの配置例
int initialized_var = 42; // → .data
int uninitialized_var; // → .bss
const char *msg = "Hello"; // ポインタ → .data, 文字列 → .rodata
void my_function(void) { // → .text
int local_var = 10; // スタック上(セクションには含まれない)
} 💡
組み込みでよくある質問:「変数を初期化しないと値が不定なのはなぜ?」→ .bssセクションの変数は起動時に0クリアされますが、ローカル変数はスタック上にあるため、以前の関数呼び出しで使われた値が残っています。
シンボルテーブルは何のためにある?
シンボルテーブルは、そのオブジェクトファイルが定義・参照している関数名や変数名の一覧です。リンカはこのテーブルを基にシンボル解決を行います。
シンボル解決の仕組み
- 定義シンボル:このオブジェクトに実体がある関数・変数(nm で T/D/B/t/d/b のように種別が付く。表示記号はツールチェーンで異なることがある。)
- 未定義シンボル:他の翻訳単位にある前提の参照(GNU nm では一例として U)
# シンボルテーブルの確認(一例: GNU nm)
nm main.o
# 出力例(省略・環境により表示は異なる):
# ... 再配置情報(Relocation)とは?
オブジェクトファイル内の関数呼び出し命令には、呼び出し先のアドレスがまだ仮の値(0やプレースホルダ)で書き込まれています。再配置情報は「コードのどの位置に、どのシンボルのアドレスを書き込むべきか」を記録したメタデータです。リンカがシンボル解決後にこの情報を使って最終アドレスを埋め込みます。
# 再配置情報の確認(アーキテクチャによって型名が変わる)
objdump -r main.o ELF フォーマットの概要とは?
Linux 環境ではオブジェクトファイルと実行ファイルに ELF がよく使われます。 参考:ELF 仕様(gABI)
# ELFヘッダの確認
readelf -h main.o
# セクション一覧の確認
readelf -S main.o
# 全情報の表示(長いのでパイプ推奨)
readelf -a main.o まとめ:.o を読むときの確認手順は?
- .o は 機械語はあるが最終アドレスは未完 で、未定義参照と再配置情報を持ちがち
- .text/.data/.bss/.rodata は「何がどこに置かれる発想」を掴むためのラベル
- nm でシンボル一覧、objdump -r で再配置、readelf でレイアウト確認、という流れが汎用的