青木峰郎『ふつうのコンパイラをつくろう』の目次がやばいのでサイン会@RubyKaigiのお知らせ
(7/22追記:ふつパイラのサポートページができていました。下記よりもサポートページの方が確実かと思うので、そちらをどうぞ。)
青木峰郎先生が3年の歳月を費やしてついに完成させた労作『ふつうのコンパイラをつくろう』、RubyKaigi2009で先行発売されているのはみなさんご存知というか、もちろん来場されたみなさんはすでに購入済みかと思うのですが、買いそびれてしまった方のために、とある信頼できる情報筋から目次のデータをゲットいたしました。以下に転載いたします。
中身についてはあえて多くは語りませんが、構文解析からアセンブラ生成と最適化を終えて、その後に「第4部 リンクとロード」があるのが注目だそうです。ELFの話から位置独立コードの話まで、「そこまでやるか」もきっちりフォローするのが青木先生の「ふつう」の「ふつう」たるところと言えましょう。読んでないけど。
そして明日は12:00からRubykaigi2009会場にて、青木先生と江渡先生の合同サイン会も開催されますので、RubyKaigiに参加されているラッキーな方は、ぜひ購入して、ついでにサインもゲットされることをおすすめします。
ちなみに同じく明日のRubyKaigiでは、15:30からまつもとゆきひろ先生とyhara先生の合同サイン会も開催されます。こちらもぜひご参加ください。
『ふつうのコンパイラを作ろう』目次 ふつうのまえがき ---- iii 前提となる知識 ---- v 前提としない知識 ---- v 本書の構成 ---- vi 謝辞 ---- vii 第 1 章 コンパイラ作りを始めよう 1 1.1 本書の概要 ---- 2 本書のテーマ ---- 2 本書で作成するコンパイラ ---- 2 コンパイルの例 ---- 3 実行可能ファイルとは ---- 4 コンパイルとは ---- 5 プログラム実行環境 ---- 8 1.2 コンパイルの過程 ---- 11 コンパイルの4 つの段階 ---- 11 構文解析 ---- 11 意味解析 ---- 12 中間表現の生成 ---- 13 コード生成 ---- 14 最適化 ---- 14 まとめ ---- 15 1.3 C♭コンパイラによるコンパイル ---- 16 C♭コンパイラの必要環境 ---- 16 C♭コンパイラのインストール ---- 17 C♭によるHello, World! ---- 17 第 2 章 C♭とcbc 19 2.1 C♭言語の概要 ---- 20 C♭でのHello, World! ---- 20 C♭で削除された機能 ---- 21 import 宣言の仕様 ---- 22 インポートファイルの仕様 ---- 23 2.2 C♭コンパイラcbc の構成 ---- 25 cbc のソースツリー ---- 25 cbc のパッケージ ---- 26 compiler パッケージのクラス群 ---- 27 main メソッドの実装 ---- 27 commandMain メソッドの実装 ---- 28 Java 5 のgenerics ---- 29 build メソッドの実装 ---- 29 Java 5 のforeach 文 ---- 30 compile メソッドの実装 ---- 31 第1 部 ソースコードの解析 第 3 章 構文解析の概要 35 3.1 構文解析の手法 ---- 36 ソースコード解析の問題点 ---- 36 ソースコード解析の定石 ---- 36 字句解析、構文解析、意味解析 ---- 37 スキャナの働き ---- 38 単語の種類と意味値 ---- 39 トークン ---- 40 抽象構文木とノード ---- 41 3.2 パーサジェネレータ ---- 43 パーサジェネレータとは ---- 43 パーサジェネレータの種類 ---- 43 パーサジェネレータの選択 ---- 44 3.3 JavaCC の概要 ---- 47 JavaCC とは ---- 47 文法記述ファイル ---- 47 文法記述ファイルの例 ---- 48 JavaCC の実行 ---- 50 JavaCC で生成したパーサの起動 ---- 51 日本語の処理 ---- 53 第 4 章 字句解析 55 4.1 JavaCC によるスキャナの記述 ---- 56 この章の目的 ---- 56 JavaCC の正規表現 ---- 56 固定文字列 ---- 57 連接 ---- 57 文字クラス ---- 58 否定文字クラス ---- 58 1 回以上の繰り返し ---- 59 0 回以上の繰り返し ---- 59 n 回からm 回の繰り返し ---- 60 ちょうどn 回の繰り返し ---- 60 省略可能 ---- 61 選択 ---- 61 4.2 構造のない単語のスキャン ---- 63 TOKEN 命令 ---- 63 識別子と予約語のスキャン ---- 63 マッチする規則の選択 ---- 65 数値のスキャン ---- 66 4.3 トークンを生成しない単語のスキャン ---- 68 SKIP 命令とSPECIAL_TOKEN 命令 ---- 68 空白の読み捨て ---- 69 行コメントの読み捨て ---- 69 4.4 構造を持つ単語のスキャン ---- 71 最長一致の原則とその問題 ---- 71 状態遷移を使ったスキャン ---- 72 MORE 命令 ---- 73 ブロックコメントの読み捨て ---- 75 文字列リテラルのスキャン ---- 76 文字リテラルのスキャン ---- 76 第 5 章 JavaCC によるパーサの記述 79 5.1 EBNF による文法の記述 ---- 80 この章の目的 ---- 80 JavaCC での文法の記述 ---- 81 終端記号と非終端記号 ---- 82 JavaCC のEBNF 記法 ---- 83 連接 ---- 84 0 回以上の繰り返し ---- 84 1 回以上の繰り返し ---- 85 選択 ---- 86 省略可能 ---- 86 5.2 曖昧な文法とトークンの先読み ---- 87 曖昧な文法 ---- 87 JavaCC の制限 ---- 89 左端共通部分のくくり出し ---- 89 トークンの先読み ---- 90 省略可能な規則と衝突 ---- 92 繰り返しと衝突 ---- 93 より柔軟なトークンの先読み ---- 94 先読みに関する注意 ---- 95 第 6 章 構文解析 97 6.1 定義の解析 ---- 98 プログラム全体を表す記号 ---- 98 構文の単位 ---- 99 import 宣言の構文 ---- 100 さまざまな定義の構文 ---- 101 変数定義の構文 ---- 103 関数定義の構文 ---- 104 構造体定義と共用体定義の構文 ---- 106 構造体メンバと共用体メンバの構文 ---- 107 typedef 文の構文 ---- 108 型の構文 ---- 108 C 言語とC♭の変数定義の違い ---- 109 基本型の構文 ---- 110 6.2 文の解析 ---- 113 文の構文 ---- 113 if 文の構文 ---- 114 if 文と中括弧の省略 ---- 115 while 文の構文 ---- 116 for 文の構文 ---- 116 さまざまなジャンプ文の構文 ---- 117 6.3 式の解析 ---- 118 式の全体構造 ---- 118 expr の規則 ---- 119 条件式 ---- 120 二項演算子 ---- 121 6.4 項の解析 ---- 125 項の規則 ---- 125 前置演算子の規則 ---- 125 後置演算子の規則 ---- 126 リテラルの規則 ---- 127 第2 部 抽象構文木と中間表現 第 7 章 JavaCC のアクションと抽象構文木 131 7.1 JavaCC のアクション ---- 132 この章の目的 ---- 132 簡単なアクション ---- 132 アクションの実行されるタイミング ---- 133 意味値を返すアクション ---- 135 終端記号の意味値の取り出し ---- 136 Token クラスのフィールド ---- 137 非終端記号の意味値の取り出し ---- 139 構文木の構築 ---- 140 選択とアクション ---- 141 繰り返しとアクション ---- 143 この節のまとめ ---- 145 7.2 抽象構文木とノード ---- 147 Node クラス群 ---- 147 Node クラスの定義 ---- 149 抽象構文木の表示 ---- 150 ノードによる式の表現の例 ---- 152 第 8 章 抽象構文木の作成 157 8.1 式の抽象構文木 ---- 158 リテラルの抽象構文木 ---- 158 型の表現 ---- 160 TypeRef クラスが必要な理由 ---- 161 単項演算の抽象構文木 ---- 162 二項演算の抽象構文木 ---- 164 条件式の抽象構文木 ---- 166 代入式の抽象構文木 ---- 167 8.2 文の抽象構文木 ---- 171 if 文の抽象構文木 ---- 171 while 文の抽象構文木 ---- 172 複文の抽象構文木 ---- 174 8.3 宣言の抽象構文木 ---- 176 変数宣言リストの抽象構文木 ---- 176 関数定義の抽象構文木 ---- 178 宣言リストを表す抽象構文木 ---- 179 プログラム全体を表す抽象構文木 ---- 180 外部シンボルのインポート ---- 181 まとめ ---- 182 8.4 cbc パーサの起動 ---- 185 Parser オブジェクトの生成 ---- 185 ファイルのパース ---- 186 パーサの起動 ---- 188 第 9 章 意味解析(1)参照の解決 189 9.1 意味解析の概要 ---- 190 この章の目的 ---- 190 抽象構文木のトラバース ---- 191 Visitor パターンを使わない抽象構文木の処理 ---- 192 Visitor パターンによる抽象構文木の処理 ---- 194 Visitor パターンの一般化 ---- 196 cbc におけるVisitor パターンの実装 ---- 198 意味解析に関わるcbc のクラス ---- 199 9.2 変数参照の解決 ---- 201 問題の概要 ---- 201 実装の概要 ---- 201 Scope ツリーの構造 ---- 203 LocalResolver クラスのフィールド ---- 204 LocalResolver クラスの起動 ---- 205 変数定義の登録 ---- 206 関数定義の処理 ---- 207 pushScope メソッド ---- 208 currentScope メソッド ---- 209 popScope メソッド ---- 209 ローカルスコープの追加 ---- 210 VariableNode と変数定義の対応付け ---- 211 スコープツリーからの変数定義の取得 ---- 212 9.3 型名の解決 ---- 214 問題の概要 ---- 214 実装の概要 ---- 214 TypeResolver クラスのフィールド ---- 214 TypeResolver クラスの起動 ---- 215 型の宣言 ---- 216 型と抽象構文木のトラバース ---- 217 変数定義の型の解決 ---- 218 関数定義の型の解決 ---- 219 第 10 章 意味解析(2)静的型チェック 221 10.1 型定義のチェック ---- 222 問題の概要 ---- 222 実装の概要 ---- 223 有向グラフのループを検出するアルゴリズム ---- 225 構造体・共用体の循環定義チェック ---- 226 10.2 式の妥当性のチェック ---- 229 問題の概要 ---- 229 実装の概要 ---- 230 DereferenceChecker クラスの起動 ---- 231 例外SemanticError の捕捉 ---- 232 左辺値でない式のアドレス取得のチェック ---- 233 ポインタでない値のデリファレンスのチェック ---- 234 暗黙のポインタ生成 ---- 235 10.3 静的型チェック ---- 237 問題の概要 ---- 237 実装の概要 ---- 238 C♭における演算の型 ---- 238 暗黙の型変換 ---- 240 TypeChecker クラスの起動 ---- 241 二項演算式の型チェック ---- 242 暗黙の型変換の実装 ---- 244 第 11 章 中間表現への変換 249 11.1 cbc の中間表現 ---- 250 中間表現の表示 ---- 250 中間表現を構成するクラス ---- 252 中間表現ノードのフィールド ---- 253 中間表現の演算子と型 ---- 254 さまざまな中間表現 ---- 255 中間表現の目的 ---- 256 11.2 IRGenerator クラスの概要 ---- 258 抽象構文木のトラバースと返り値 ---- 258 IRGenerator クラスの起動 ---- 258 関数本体の変換 ---- 259 文である式の判別 ---- 260 11.3 制御構造の変換 ---- 263 if 文の変換(1)概要 ---- 263 if 文の変換(2)else 節がない場合 ---- 264 if 文の変換(3)else 節がある場合 ---- 265 while 文の変換 ---- 266 break 文の変換(1)問題の定義 ---- 268 break 文の変換(2)実装の方針 ---- 269 break 文の変換(3)実装 ---- 270 11.4 副作用のない式の変換 ---- 273 UnaryOpNode オブジェクトの変換 ---- 273 BinaryOpNode オブジェクトの変換 ---- 274 ポインタに対する加減算の変換 ---- 276 11.5 左辺値の変換 ---- 279 左辺と右辺 ---- 279 左辺値と右辺値 ---- 279 cbc での左辺値の表現 ---- 280 構造体メンバのオフセット ---- 282 メンバ参照(expr.memb)の変換 ---- 283 左辺値変換の例外:配列と関数 ---- 285 メンバ参照式(ptr->memb)の変換 ---- 286 11.6 副作用を持つ式の変換 ---- 288 式の副作用とは ---- 288 副作用を持つ式の変換方針 ---- 289 単純な代入式の変換(1)文である場合 ---- 290 テンポラリ変数の導入 ---- 291 単純な代入式の変換(2)式である場合 ---- 293 後置インクリメントの変換 ---- 295 第3 部 アセンブリコードの生成 第 12 章 x86 アーキテクチャの概要 301 12.1 コンピュータの仕組み ---- 302 CPU とメモリ ---- 302 レジスタ ---- 303 アドレス ---- 303 物理アドレスと仮想アドレス ---- 304 さまざまなデバイス ---- 306 キャッシュメモリ ---- 308 12.2 x86 系CPU の歴史 ---- 311 x86 系CPU とは ---- 311 32 ビットCPU とは ---- 312 インストラクションセットとは ---- 313 IA-32 の変遷 ---- 314 IA-32 の64 ビット拡張 〜 AMD64 〜 ---- 315 12.3 IA-32 の概要 ---- 317 IA-32 のレジスタ ---- 317 汎用レジスタ ---- 319 マシンスタックとは ---- 320 マシンスタックの操作 ---- 321 マシンスタックの用途 ---- 323 スタックフレームとは ---- 324 インストラクションポインタ ---- 325 フラグレジスタ ---- 326 12.4 データの表現と配置 ---- 328 符号なし整数の表現 ---- 328 符号付き整数の表現 ---- 328 負の整数の表現と2 の補数 ---- 329 エンディアン ---- 330 アラインメント ---- 331 構造体の表現 ---- 332 第 13 章 x86 アセンブラプログラミング 335 13.1 GNU アセンブラによるプログラミング ---- 336 GNU アセンブラ ---- 336 アセンブリ言語によるHello, World! ---- 336 GNU アセンブラによるアセンブル ---- 337 13.2 GNU アセンブラの文法 ---- 340 アセンブリ版Hello, World! ---- 340 インストラクション ---- 341 ディレクティブ ---- 341 ラベル ---- 342 コメント ---- 343 ニモニックサフィックス ---- 343 さまざまなオペランド ---- 344 間接メモリ参照 ---- 345 x86 インストラクションセットの概要 ---- 348 13.3 転送命令 ---- 350 mov 命令 ---- 350 push 命令とpop 命令 ---- 352 lea 命令 ---- 353 movsx 命令とmovzx 命令 ---- 354 符号拡張とゼロ拡張 ---- 355 13.4 算術演算命令 ---- 357 add 命令 ---- 357 キャリーフラグ ---- 358 sub 命令 ---- 358 imul 命令 ---- 359 idiv 命令とdiv 命令 ---- 360 inc 命令 ---- 362 dec 命令 ---- 362 neg 命令 ---- 362 13.5 ビット演算命令 ---- 364 and 命令 ---- 364 or 命令 ---- 365 xor 命令 ---- 365 not 命令 ---- 366 sal 命令 ---- 366 sar 命令 ---- 367 shr 命令 ---- 367 13.6 演算の制御 ---- 369 jmp 命令 ---- 369 条件付きジャンプ命令(jz、jnz、je、jne、……) ---- 370 cmp 命令 ---- 372 test 命令 ---- 372 フラグを取り出す命令(SETcc) ---- 373 call 命令 ---- 374 ret 命令 ---- 375 第 14 章 関数呼び出しと変数 377 14.1 手続き呼び出し規約 ---- 378 手続き呼び出し規約とは ---- 378 Linux/x86 の手続き呼び出し規約 ---- 379 14.2 Linux/x86 での関数呼び出し ---- 381 呼び出し完了まで ---- 381 関数本体の実行開始まで ---- 382 呼び出し元への復帰まで ---- 384 後始末完了まで ---- 385 関数呼び出しのまとめ ---- 385 14.3 Linux/x86 での関数呼び出しの詳細 ---- 389 レジスタの保存と復帰 ---- 389 caller-save レジスタとcallee-save レジスタ ---- 390 caller-save レジスタとcallee-save レジスタの活用 ---- 391 大きな値と浮動小数点数の返しかた ---- 392 他のプラットフォームでの手続き呼び出し規約 ---- 394 第 15 章 式と文のコンパイル 395 15.1 コンパイル結果の調査 ---- 396 cbc での調査方法 ---- 396 gcc での調査方法 ---- 398 15.2 x86 アセンブリのオブジェクト表現とDSL ---- 399 アセンブリを表現するクラス ---- 399 アセンブリオブジェクトの表示 ---- 401 15.3 cbc のx86 アセンブリDSL ---- 403 DSL によるアセンブリオブジェクトの生成 ---- 403 レジスタの表現 ---- 404 即値とメモリ参照の表現 ---- 406 インストラクションの表現 ---- 406 ディレクティブ、ラベル、コメントの表現 ---- 407 15.4 CodeGenerator クラスの概要 ---- 409 CodeGenerator クラスのフィールド ---- 409 CodeGenerator クラスの処理の概要 ---- 410 compileStmts メソッドの実装 ---- 411 cbc のコンパイル戦略 ---- 412 15.5 単純な式のコンパイル ---- 415 Int ノードのコンパイル ---- 415 Str ノードのコンパイル ---- 415 Uni ノードのコンパイル(1)ビット否定 ---- 417 Uni ノードのコンパイル(2)論理否定 ---- 419 15.6 二項演算のコンパイル ---- 421 Bin ノードのコンパイル ---- 421 compileBinaryOp メソッドの実装 ---- 422 除算と剰余の実装 ---- 423 比較演算の実装 ---- 424 15.7 変数の参照と代入 ---- 426 Var ノードのコンパイル ---- 426 Addr ノードのコンパイル ---- 428 Mem ノードのコンパイル ---- 429 Assign ノードのコンパイル ---- 429 15.8 ジャンプ文のコンパイル ---- 432 LabelStmt ノードのコンパイル ---- 432 Jump ノードのコンパイル ---- 432 CJump ノードのコンパイル ---- 433 Call ノードのコンパイル ---- 434 Return ノードのコンパイル ---- 435 第 16 章 スタックフレームの割り当て 437 16.1 マシンスタックの操作 ---- 438 cbc のスタックフレーム ---- 438 スタックポインタ操作の方針 ---- 439 関数本体のコンパイル手順 ---- 440 16.2 引数とローカル変数へのメモリ参照割り当て ---- 442 この節の概要 ---- 442 引数へのメモリ参照割り当て ---- 442 ローカル変数へのメモリ参照割り当て:方針 ---- 444 ローカル変数へのメモリ参照割り当て ---- 446 スコープ内のローカル変数の処理 ---- 447 アラインメントの計算 ---- 448 子スコープの変数への割り当て ---- 449 16.3 仮想スタックによるテンポラリ変数の割り当て ---- 451 仮想スタックの目的 ---- 451 仮想スタックのインターフェイス ---- 452 仮想スタックの構造 ---- 453 virtulPush メソッドの実装 ---- 454 VirtualStack#extend メソッドの実装 ---- 454 VirtualStack#top メソッドの実装 ---- 455 virtulPop メソッドの実装 ---- 455 VirtualStack#rewind メソッドの実装 ---- 456 仮想スタックの動作 ---- 456 16.4 マシンスタックアクセスのオフセット調整 ---- 457 この節の概要 ---- 457 StackFrameInfo クラス ---- 458 使われているcallee-save レジスタの算出 ---- 459 テンポラリ変数領域のサイズの算出 ---- 460 ローカル変数のオフセット調整 ---- 460 テンポラリ変数のオフセット調整 ---- 461 16.5 プロローグ・エピローグの生成 ---- 462 この節の概要 ---- 462 プロローグの生成 ---- 463 エピローグの生成 ---- 464 16.6 alloca の実装 ---- 466 alloca 関数とは ---- 466 実装の方針 ---- 467 alloca 関数の影響 ---- 467 alloca 関数の実装 ---- 468 第 17 章 最適化の手法 471 17.1 最適化とは ---- 472 いろいろな最適化 ---- 472 最適化の例 ---- 472 定数の畳み込み ---- 473 式の単純化 ---- 473 演算強度の低減 ---- 473 共通部分式の削除 ---- 474 不要命令の削除 ---- 474 関数インライン展開 ---- 475 17.2 最適化の分類 ---- 476 手法による最適化の分類 ---- 476 対象範囲による最適化の分類 ---- 477 適用段階による最適化の分類 ---- 478 17.3 cbc での最適化 ---- 479 cbc における最適化の方針 ---- 479 cbc で実装した最適化 ---- 479 cbc での最適化の実装 ---- 480 17.4 より強力な最適化 ---- 481 パターンマッチによる命令選択 ---- 481 レジスタ割り当て ---- 482 コントロールフロー解析 ---- 483 大規模なデータフロー解析とSSA 形式 ---- 483 まとめ ---- 484 第4 部 リンクとロード 第 18 章 オブジェクトファイルの生成 487 18.1 ELF ファイルの構造 ---- 488 ELF の目的 ---- 488 ELF のセクションとセグメント ---- 489 オブジェクトファイルの主要なELF セクション ---- 491 readelf コマンドによるセクションヘッダの表示 ---- 492 readelf コマンドによるプログラムヘッダの表示 ---- 493 readelf コマンドによるシンボルテーブルの表示 ---- 495 readelf コマンドのオプション ---- 496 DWARF フォーマットとは ---- 497 18.2 グローバル変数のELF ファイルでの表現 ---- 498 任意のELF セクションへの割り当て ---- 498 一般的なELF セクションへの割り当て ---- 499 .bss セクションの確保 ---- 499 コモンシンボル ---- 500 グローバル変数に対応するシンボルの登録 ---- 502 シンボルの付帯情報の登録 ---- 503 コモンシンボルの付帯情報の登録 ---- 504 まとめ ---- 505 18.3 グローバル変数のコンパイル ---- 507 generate メソッドの実装 ---- 507 generateAssemblyCode メソッドの実装 ---- 507 グローバル変数のコンパイル ---- 509 即値のコンパイル ---- 510 コモンシンボルのコンパイル ---- 512 文字列リテラルのコンパイル ---- 513 関数ヘッダの生成 ---- 514 関数のコードサイズの計算 ---- 515 まとめ ---- 516 18.4 オブジェクトファイルの生成 ---- 517 as コマンド呼び出しの概要 ---- 517 GNUAssembler クラスの呼び出し ---- 517 as コマンドの呼び出し ---- 518 第 19 章 リンクとライブラリ 521 19.1 リンクの概要 ---- 522 リンクの実行例 ---- 522 gcc とGNU ld ---- 524 リンカが扱うファイル ---- 526 よく使われるライブラリ ---- 528 リンカの入力と出力 ---- 528 19.2 リンクとは ---- 530 リンクで行われる処理 ---- 530 セクションのマージとは ---- 530 再配置とは ---- 531 シンボルの解決とは ---- 533 19.3 ダイナミックリンクとスタティックリンク ---- 535 2 つのリンク手法 ---- 535 ダイナミックリンクの利点 ---- 536 ダイナミックリンクの欠点 ---- 536 ダイナミックリンクの実行例 ---- 537 スタティックリンクの実行例 ---- 538 ライブラリの検索規則 ---- 539 19.4 ライブラリの作成 ---- 541 静的ライブラリの作成 ---- 541 Linux での共有ライブラリの管理 ---- 542 共有ライブラリの作成 ---- 543 作成した共有ライブラリとのリンク ---- 545 第 20 章 プログラムのロード 547 20.1 ELF セグメントのロード ---- 548 mmap システムコールによるファイルのマップ ---- 548 プロセスのメモリイメージ ---- 549 メモリ領域の属性 ---- 551 ELF セグメントとメモリ領域の対応 ---- 551 ELF ファイルと対応しないメモリ領域 ---- 554 ELF ファイルのロードの実装 ---- 555 20.2 ダイナミックリンクの過程 ---- 557 ダイナミックリンカローダとは ---- 557 プログラムの起動から終了までの概要 ---- 558 ld.so の起動 ---- 559 カーネルから渡される情報 ---- 560 AUX ベクタ ---- 561 共有ライブラリの読み込み ---- 562 シンボルの解決と再配置 ---- 564 初期化コードの実行 ---- 565 メインプログラムの開始 ---- 566 終了処理の実行 ---- 567 ld.so が解釈する環境変数 ---- 568 20.3 動的ロード ---- 570 動的ロードとは ---- 570 Linux での動的ロード ---- 570 動的ロードの仕組み ---- 571 20.4 GNU ld によるリンク ---- 573 cbc 用ld オプションの構築 ---- 573 C ランタイム ---- 574 実行可能ファイルの作成 ---- 575 共有ライブラリの生成 ---- 576 第 21 章 位置独立コードの生成 579 21.1 位置独立コードとは ---- 580 位置独立コードとは ---- 580 グローバルオフセットテーブル(GOT) ---- 582 GOT のアドレス取得 ---- 582 GOT を使ったグローバル変数アクセス ---- 584 GOT を使ったファイル内グローバル変数へのアクセス ---- 585 手続きリンクテーブル(PLT) ---- 585 PLT エントリの呼び出し ---- 588 位置独立な実行可能ファイル:PIE ---- 588 21.2 グローバル変数参照の実装 ---- 591 GOT アドレスの取得 ---- 591 PICThunk メソッドの実装 ---- 592 重複した関数の削除と非可視属性 ---- 593 GOT アドレスのロード ---- 594 locateSymbols メソッドの実装 ---- 595 グローバル変数の参照 ---- 596 グローバル変数へのアクセス:位置独立コードの場合 ---- 597 関数のシンボル ---- 598 文字列定数の参照 ---- 600 21.3 リンカ呼び出しの実装 ---- 602 実行可能ファイルの生成 ---- 602 generateSharedLibrary メソッド ---- 604 21.4 プログラムの解析から実行まで ---- 606 ビルドとロードの過程 ---- 606 字句解析 ---- 607 構文解析 ---- 608 中間表現の生成 ---- 609 コード生成 ---- 610 アセンブル ---- 611 共有ライブラリの生成 ---- 612 実行可能ファイルの生成 ---- 613 ロード ---- 613 第 22 章 本書を読み終えたあとに 615 22.1 書籍紹介 ---- 616 コンパイラ全体について ---- 616 構文解析について ---- 617 アセンブリ言語について ---- 618 22.2 リンク・ロードについて ---- 619 22.3 さまざまな言語機能 ---- 620 例外の実装に関する書籍 ---- 620 ガーべージコレクションとは ---- 621 ガーベージコレクションに関する書籍 ---- 621 オブジェクト指向言語の実装 ---- 622 関数型言語 ---- 623 付録 625 A.1 参考文献 ---- 626 A.2 オンラインドキュメント ---- 629 A.3 ソースコード ---- 630 索引 ---- 631