連載
.NETの動作原理を基礎から理解する!

第3回 .NETアプリケーションが実行される仕組み

―― CLRローダーの働き ――

デジタルアドバンテージ 一色 政彦
2005/10/26
Page1 Page2


Back Issue
1
.NETアプリケーションを動かす土台
2 .NETアプリケーションが起動する仕組み

 前回は、Windows OS上で.NETアプリケーションが起動する仕組みとして、.NETアプリケーションがWin32アプリケーションとして動作している部分の処理の流れを説明した。そしてそのWin32の世界から.NETの世界への入り口として、最終的にmscoree.dllの_CorExeMain関数が呼び出されることが分かった。

 今回はこの_CorExeMain関数から、どのようにして.NETアプリケーションが、その実行環境である(.NET Frameworkの)CLR(Common Language Runtime:共通言語ランタイム)上で動作し始めるのか、その仕組みを解説する。具体的には、

  • 「mscoree.dllの_CorExeMain関数」から

  • 「.NETアプリケーションの次のMainメソッドのコード(C#)」まで
    static void Main()
    {
       Application.Run(new Form1());
    }

の実行ステップを明らかにする。

 本稿では前回と同じ、次のようなシンプルなWindowsアプリケーション(WindowsApplication1.exe)をサンプルとして使用する。この.NETアプリケーションが、CLR上で起動する際の処理の流れをつぶさに追いかける。

本稿で使用するサンプル・アプリケーション
本稿では、「WindowsApplication1.exe」というシンプルなWindowsアプリケーションをサンプルとして使用する。この.NETアプリケーションが、CLR上で起動するときの処理の流れを解説する。
  エクスプローラに表示されている「WindowsApplication1.exe」をダブルクリックする。
  Windows OSのデスクトップ画面上に、「Form1」というタイトルでアプリケーション・ウィンドウが表示される。

 それでは_CorExeMain関数以降の実行処理の流れに入っていきたいが、その前提知識としてあらかじめ.NETプログラムの内部構造について知っておいた方が理解が早い。そこで本稿では、まずこの.NETプログラムの構造について概説しておくことにしよう。

 なお本稿で提示されている図版などは簡略化しており、内部構造のすべてを詳細かつ正確に明記しているわけではないことをあらかじめお断りしておく。

.NETプログラムの構造(箱と本体)

 .NETプログラムはWindows上の「ファイル」に格納されており、そのファイルはWindows OS(Win32システム)が認識可能な「PE(Portable Execute)フォーマット」である、と前回説明した。

 当然ながら.NETプログラムの実体となるコードも、このPEフォーマットにのっとってファイル内部に格納されているはずだ。それではその内部構造はどのようになっているのだろうか。

●.NETプログラムにおけるPEフォーマットの構造

 そこで、その内部構造を(簡略化して)示したものが次の図と表である。

(.NETプログラムにおける)PEフォーマットの構造
項目 説明
PEヘッダ <Win32プログラム>のエントリ・ポイントへのアドレスなどが格納されている。前回で解説済み
Win32プログラム・コード <.NETプログラム>のエントリ・ポイントへのジャンプ命令が格納されている。具体的なジャンプ先は、mscoree.dllの_CorExeMain関数か、もしくは_CorDllMain関数である。これについても前回で解説済み
CLRヘッダ 「CLI(Common Language Infrastructure)ヘッダ」とも呼ばれる。CLRデータに関するヘッダ情報として「 マニフェスト」が格納されている
CLRデータ 「CLIデータ」とも呼ばれる。.NETプログラムの実体として「 型メタデータ」「 ILコード」「 マネージ・リソース」が格納されている
ここで示した内部構造は分かりやすくするために簡略化して表したものなので、厳密な構造(および位置関係、順序)ではないことに注意すること。なおについては後述する。

 上記の図表で「.NET用」と記述されているCLRヘッダとCLRデータを組み合わせたものが、「.NETプログラムの本体」だと見なすことができる。従って.NETの世界から見ると、PEフォーマットは.NETプログラム本体を収納するための「箱(=ケース、入れ物)」でしかない。

 .NETの世界では、この箱と.NETプログラムの本体を含む物理的なファイル(もしくは、それをメモリ上にロードした後のデータ)のことを「マネージ・モジュール」(Managed Module。以降、モジュール)と呼んでいる。また、.NETプログラム本体のことは「アセンブリ」(Assembly)と呼んでいる(ちなみに.NETにおけるアセンブリは、Windows XPのサイド・バイ・サイド機能で使われる「Win32アセンブリ」という用語と区別するために、「.NETアセンブリ」と表記されることがある)。

 実はアセンブリは、「個々のファイル」という物理的な単位ではなく、「1つ以上のモジュール(=ファイル)の集合体」という論理的な単位で(.NETによって)とらえられる。つまり、Windows世界のアプリケーションの最小単位がモジュール(=個々のファイル)であるのに対し、.NET世界のアプリケーションの最小単位はアセンブリ(=1つのファイルで構成されるときと複数のファイルで構成されるときがある)なのだ。

 このため.NETでは、複数のモジュール(=ファイル)を寄せ集めて1つのアセンブリを構築できる。このようなアセンブリは「マルチ・モジュール・アセンブリ」(Multi-Module Assembly。もしくは「マルチ・ファイル・アセンブリ:Multi-File Assembly」。以降、MMA)と呼ばれる。ただし、このMMAはVisual Studioのデフォルト機能では作成できないため、実際にMMAのアプリケーションを構築することはそれほど多くないようだ。

 ほとんどの.NETプログラムは、「1モジュール=1アセンブリ」の「シングル・モジュール・アセンブリ」(Single-Module Assembly。もしくは「シングル・ファイル・アセンブリ:Single-File Assembly」。以降、SMA)である。

 そこで本稿では、このSMAについてのみ解説していく。MMAについての詳細は、「MSDN:アセンブリの内容」を参照していただきたい。

●.NETプログラム本体の構造

 次の図と表は、.NETプログラム本体(=SMA)の内部構造を示したものである。以降の解説で基礎知識として必要になるので、表内の説明もざっと一読してほしい。

.NETプログラム本体の構造
項目 説明
マニフェスト 「アセンブリ・メタデータ」とも呼ばれる。メタデータとは、一般的には「データのためのデータ」のことである。つまりここには、データであるアセンブリ(=.NETプログラム本体)に関するデータ(情報)が格納されている。ここで管理される情報には、例えば

・ランタイム・バージョン(runtime version)
  
 ……実行するCLRのバージョン
・メタデータ(MetaData)のアドレスとサイズ
  
 ……型メタデータの場所
・フラグ(flags)
  
 ……(不必要なネイティブ・コードが含まれない)純粋なILコードであるかどうか(=COMIMAGE_FLAGS_ILONLY)や厳密名(=電子署名)があるかないか(=COMIMAGE_FLAGS_STRONGNAMESIGNED)などの情報
・エントリ・ポイント・トークン(entry point token)
  
 ……型メタデータのテーブル上にあるエントリ・ポイント(Mainメソッド)のキー番号
・リソース(Resources)のアドレスとサイズ
  
 ……マネージ・リソースの場所
・厳密名シグネチャ(StrongNameSignature)のアドレスとサイズ
  
 ……厳密名の場所


などがある(「……」の後ろに書かれているのは、その情報から分かること)
型メタデータ 単に「メタデータ」と呼ぶ場合はこれを指す。ここには主に、「アセンブリ内で<定義>されている、型(クラスなど)とそのメンバに関する情報」と「アセンブリ内で<参照>している、型とメンバに関する情報」という2種類の型メタデータ・テーブルが格納されている
ILコード 「マネージ・コード」とも呼ばれる。ここには実際の.NET用のプログラム・コードが格納されている。このコードは、特定のCPUやプラットフォームに依存しない抽象化された中間コードなので、IL(Intermediate Language:中間言語)コードと命名されている。なおILコードには、汎用フォーマットの「CIL」(Common Intermediate Language)とマイクロソフトが提供する拡張フォーマットの「MSIL」(Microsoft Intermediate Language)の2種類がある。Visual Studioや.NET Framework付属のコンパイラで生成したプログラムはMSILである
マネージ・リソース マネージ・リソース(Managed resources)には、ビットマップや文字列などの(.NETにより管理された)リソースが格納されている

 以上、.NETプログラムの構造として「箱であるモジュールの構造」と「本体であるアセンブリの構造」を説明した。それでは、本題である.NETプログラムの実行処理の流れを順に追っていくことにしよう。


 INDEX
  .NETの動作原理を基礎から理解する!
  第3回 .NETアプリケーションが実行される仕組み
  1..NETプログラムの構造(箱と本体)
    2..NETプログラム実行の処理の流れ
 
インデックス・ページヘ  「.NETの動作原理を基礎から理解する!」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間