デフォルト初期化の変更
デフォルトでは、メモリの初期化は、アプリケーション起動時に実行されます。ILINKは、初期化プロセスを設定し、最適な圧縮方法を選択します。デフォルトの初期化プロセスがアプリケーションに適していないため、初期化プロセスをより正確に制御する必要がある場合、以下の方法を使用できます。
初期化の抑止
圧縮アルゴリズムを選択する
手動で初期化する
コードを初期化する(ROMからRAMにコピーする)
実行された初期化については、ログファイル(コマンドラインオプション--log initialization)を確認してください。
初期化の抑止
一部またはすべてのセクションについて、コピーによる初期化をリンカに設定しない場合は、これらのセクションがinitialize by copyディレクティブのパターンに一致しないようにしてください(または、except句を使用して、一致しないように除外します)。コピーによる初期化をまったく必要としない場合、initialize by copyディレクティブを完全に省略できます。
これは、何らかのメカニズムによって、アプリケーションが起動する前に、アプリケーションまたは変数だけをRAMにロードする場合に役立ちます。
圧縮アルゴリズムの選択
デフォルトの圧縮アルゴリズムをオーバライドするには、たとえば、以下のように記述します。
initialize by copy with packing = lz77 { readwrite };使用可能なその圧縮アルゴリズムの詳細については、 initialize directiveを参照してください。
手動で初期化する
手動で初期化する通常の場合は、initialize by copyディレクティブは、アプリケーション起動時に内容を含むセクションをコピーする(パッキングの有無にかかわらず)ことによる初期化準備をリンカに行わせるために使用します。リンカは、各セクションに対して、そのセクションの内容を保持する初期化セクションを論理的に作成し、元のセクションは内容を持たないセクションに変換することによりこれを行います。初期化セクションの名前は、サフィックス_initを追加した元のセクションの名前です。 例えば、.dataセクションの初期化セクションは.data_initと呼ばれます。続いて、リンカはアプリケーション起動時に初期化が実行されるように、初期化テーブルに テーブルの要素を追加します。
initialize manuallyを使用して、テーブルの要素作成を抑止し、要素がいつどのようにコピーされるかを制御することができます。これはオーバレイのほかに、その他の場合にも便利です。
イニシャライザを持たないセクション(ゼロ初期化されたセクション)の場合、状況は逆になります。do not initializeディレクティブで記述されているセクションを除いて、リンカはアプリケーション起動時にこうしたすべてのセクションのゼロ初期化を行います。
自動ブロックを使用した単純なコピーの例
MYSECTIONに初期化された変数があるとします。リンカ設定ファイルに次のディレクティブを追加します。
initialize manually { section MYSECTION };このソースコードサンプルを使用して、次のセクションを初期化できます。
#pragma section = "MYSECTION"
#pragma section = "MYSECTION_init"
void DoInit()
{
char * from = __section_begin("MYSECTION_init");
char * to = __section_begin("MYSECTION");
memcpy(to, from, __section_size("MYSECTION"));
}このソースコードは、__section_begin(および関連の演算子)をセクション名に使用した場合に、これらのセクションに対して、リンカが生成する自動ブロックを使用しています。
注記
自動ブロックは通常のセクションセレクションプロセスを上書きし、セクション名に合致する全ての要素を強制的に1つのブロックに配置します。
明示的なブロックの例
特定のセクションの変数を手動で初期化しなければならない場合と異なり、特定のライブラリからのすべての初期化済み変数を手動で初期化する場合を考えます。この場合、変数と内容の両方について明示的なブロックを作成する必要があります。以下のようにします。
initialize manually { section .data object mylib.a };
define block MYBLOCK { section .data object mylib.a };
define block MYBLOCK_init { section .data_init object mylib.a };また、2つの新しいブロックをセクション配置ディレクティブを使用して配置する必要があります。MYBLOCKをRAMに、ブロックMYBLOCK_initをROMにそれぞれ配置します。
前述の例と同じソースコードを使用して、セクションを初期化できます。ただし、MYSECTIONの代わりにMYBLOCKを使用します。
注記
初期化を手動で使用しているときは、各copy init バッチを明示的に扱う必要があります。リンカは、ソースブロックまたは配置ディレクティブと移動先ブロックまたは配置ディレクティブのそれぞれの組み合わせに、異なるバッチを作成します。作成されるバッチを確認するには、初期化ログ(--log initialization)を使用します。
リンカによって、ブロックが自動的に作成されることがあります。これは複数のバッチに影響します。fixed orderのあるブロックを使用しているときや、拡張セクションセレクタでfirst、last、または midway 修飾子を使用しているときに発生することがあります。
オーバレイの例
これは、自動ブロック作成を活用した単純なオーバレイの例です。
initialize manually { section MYOVERLAY* };
define overlay MYOVERLAY { section MYOVERLAY1 };
define overlay MYOVERLAY { section MYOVERLAY2 };また、RAMのどこかにoverlay MYOVERLAYを配置する必要があります。コピーは以下のようになります。
#pragma section = "MYOVERLAY"
#pragma section = "MYOVERLAY1_init"
#pragma section = "MYOVERLAY2_init"
void SwitchToOverlay1()
{
char * from = __section_begin("MYOVERLAY1_init");
char * to = __section_begin("MYOVERLAY");
memcpy(to, from, __section_size("MYOVERLAY1_init"));
}
void SwitchToOverlay2()
{
char * from = __section_begin("MYOVERLAY2_init");
char * to = __section_begin("MYOVERLAY");
memcpy(to, from, __section_size("MYOVERLAY2_init"));
}コードを初期化する(ROMからRAMにコピーする)
アプリケーションが、コードの一部をフラッシュROM からRAM にコピーすることがあります。アプリケーションが、コードの一部をフラッシュROM からRAM にコピーすることがあります。アプリケーション起動時にこの処理が自動的に行われるようリンカに指示することも、手動で初期化するの説明に従って後でユーザコードで行うこともできます。
initialize by copyディレクティブでコピーされるコードセクションをリストする必要があります。最も簡単な方法は通常、適切な関数を特定のセクション(RAMCODEなど)に配置して、section RAMCODEをinitialize by copyディレクティブに追加することです。以下に例を示します。
initialize by copy { rw, section RAMCODE };特定の場所にRAMCODE関数を配置する必要がある場合は、配置ディレクティブでその関数を記述しなければなりません。そうしなければ、他のリード/ライトセクションとともに配置されます。
コピーの動作やタイミングを制御しなければならない場合は、代わりにinitialize manuallyディレクティブを使用してください。手動で初期化するを参照してください。
フラッシュ/ROMにアクセスしないで関数を実行する必要がある場合、コンパイル時に__ramfuncキーワードを使用できます。RAMでの実行を参照してください。
すべてのコードをRAMから実行
プログラム起動時にアプリケーション全体をROMからRAMにコピーする場合は、たとえば、initilize by copyディレクティブを使用して、以下のように実現できます。
initialize by copy { readonly, readwrite };readwriteパターンは、静的に初期化されるすべての変数に一致し、これらが起動時に初期化されるように準備します。readonlyパターンは、初期化に必要なコードおよびデータを除くすべてのリードオンリーコードおよびデータに対して同様に機能します。
関数__low_level_initが存在する場合、この関数は初期化の前に呼び出されるため、この関数およびこの関数を必要とするものはすべて、ROMからRAMにコピーされません。特定の状況(たとえば、起動後にROMの内容がプログラムで使用できなくなる場合など)においては、起動中およびコードの残りの部分での同じ関数の使用を避ける必要があります。
コピーされる必要のないものがあれば、except句に入れます。たとえば、割り込みベクタテーブルなどに適用できます。
また、RAMへのコピーからC++動的初期化テーブルを除外することが推奨されます。通常、このテーブルは、1度だけ読み込まれ、再度参照されることはないためです。たとえば、以下のように指定します。
initialize by copy { readonly, readwrite }
except { section .intvec, /* Don’t copy interrupt table */
section .init_array }; /* Don’t copy C++ init table */