Using iobjmanip to process object files
テクニカル・ノート 200128
アーキテクチャ:
ARM, RH850, RL78, RX, RISCV, STM8
コンポーネント:
linker
更新日:
2020/10/13 16:29
はじめに
10.6.5.1221より前のバージョンの iobjmanip がオブジェクトファイルの操作に使用された場合、生成されるアプリケーションの起動時に変数が正しく初期化されないことがあります。
影響を受けるIAR Embedded Workbench バージョン:
IAR Embedded Workbench for Arm: All versions between 7.60 and (not including) 8.50
IAR Embedded Workbench for RH850: All versions between 1.40 and (including) 2.10
IAR Embedded Workbench for RL78: All versions between 2.21 and (including) 4.20
IAR Embedded Workbench for RX: All versions between 2.90 and (including) 4.13
IAR Embedded Workbench for RISC-V: All versions up to (but not including) 1.20
IAR Embedded Workbench for STM8: All versions between 3.10 and (including) 3.11.2
上記リストより新しいバージョンを使用して作成されたアプリケーションには、この問題はありません。
解説
__no_init コンパイラ キーワード
コンパイラは、C拡張キーワード:__no_initをサポートします。 __no_init属性を持つ変数は、起動時に初期化されません。
do not initialize リンカ ディレクティブ
The IAR ILINK linker can use the directive , that disables implicit zero initialization.
IAR ILINKリンカは、do not initializeディレクティブを使用し、暗黙的なゼロ初期化を無効にすることができます。
サンプルプロジェクトからの抜粋:
=== t.c
int a; // a implicitly initialized to zero
__no_init int b; // b not initialized.
#pragma location="c-section"
int c; // c *implicitly* initialized to zero
#pragma location="d-section"
int d=0; // d *explicitly* initialized to zero
=== t.icf
include "generic_cortex.icf";
do not initialize { section c-section object t.o, section d-section object t.o};
// c will *not* be initialized
// d *will* be initialized
.iar.noinitinfo section
ELF セクション .iar.noinitinfo は、初期化されるべきではないセクションをトラッキングするために使用されます。
iobjmanip tool
iobjmanip は、再配置可能なELFファイルを操作するために使用されるIARツールです。
問題点
iobjmanip を使用してオブジェクトファイルからセクションを削除すると、後続のすべてのセクションの番号が1つ減り、.iar.noinitinfoセクションの情報が不正確になる可能性があります。 オブジェクトファイルを誤った .iar.noinitinfoセクションにリンクすると、誤った初期化処理が行われる可能性があります。
起こりえる問題は?
問題1. 起動時に変数が正しく初期化されない可能性があり、これはシリアスな問題になる可能性があります。
以下の条件の場合に問題が起こる可能性があります。
- ファイルに:
- m > 0 の __no_init セクションが存在する。 例えば NOI_SEC_1, NOI_SEC_2, ..., NOI_SEC_m
- n > 0 の initialized セクションが存在する。例えば I_SEC_1, I_SEC_2, ..., I_SEC_n
- セクション削除にiobjmanip が使用された。
- initialized セクション、 例えばI_SEC_v が新しい番号を取得し、その番号が__no_init セクション NOI_SEC_uets の古い番号と同じである。
Note: このようにセクションが一致することは、ほとんどありませんが、発生する可能性もあります。
問題2. __no_init の内容が、起動時にゼロに初期化される可能性があります。値がリセット/再起動 直後に正常に機能する必要がある場合にシリアスな問題になる可能性があります。他の理由(コードサイズや起動速度など)で __no_init である場合は、シリアスな問題ではない可能性もあります。
以下の条件の場合に問題が起こる可能性があります。
- ファイルに:
- m > 0 の __no_init セクションが存在する。 例えば NOI_SEC_1, NOI_SEC_2, ..., NOI_SEC_m
- セクション削除にiobjmanip が使用された。
- 1つ以上の NOI_SEC_u セクションが.iar.noinitinfo から参照されていない新しい番号を取得した。
Note: If the old number for a NOI_SEC_u セクションの古い番号がI_SEC_v の新しい番号を参照している場合にも、上記1の問題が起こる可能性があります。
ユーザプロジェクトが該当するかの判断は?
iobjmanipを使用しない場合、コードは影響を受けません。
__no_init を使用しない場合、コードは影響を受けません。
Note: ライブラリ (例えばボードサポートライブラリ) を使用している場合、ユーザコードに問題がない場合でも、この問題が発生する可能性があります。
リンカ設定ファイルにdo not initializeディレクティブが含まれ、これがすでに正しい.iar.noinitinfoを持たないセクションと一致する 場合、セクションは初期化されません。これが発生した場合は、誤った.iar.noinitinfoセクションは問題2にはつながりません。問題1が引き続き適用される可能性があることに注意してください。
インストールフォルダ下の bin フォルダにあるielfdump ツールを使用してオブジェクトファイルを検査できます。
ielfdump<CpuName> object_file.o を実行してください。
これにより、オブジェクトファイル内のセクションのリストが出力されます。
ielfdump<CpuName> object_file.o -s .iar.noinitinfo を実行してください。
これにより、.iar.noinitinfo セクションの内容がダンプされます。以下のように確認できます:
Section #10 .iar.noinitinfo:
#6 .noinit
ここでの情報は、セクション番号6が.noinitであり初期化されないセクションであるということです。
次にセクションのリストを確認します:
6: .noinit nobits 0x1d5 0x320 0x4 0x3 WA
セクション番号6 は nobits (ELFセクションはpbitsまたはnobitsであり、通常はゼロ初期化RAMであるnobitsセクションのみが__no_initである可能性がありますELF sections can be pbits or nobits, and only nobits sections–which typically are zero-initialized RAM– can be __no_init)であり、ファイルに問題はありません。
代わりに次のような情報の場合:
Section #9 .iar.noinitinfo:
#6 .iar_vfe_header
セクションのリスト:
6: .iar_vfe_header pbits 0x18e 0x4 0x4
セクション番号6 は pbits (pbitsセクションは __no_init にはなりません) であり、このファイルには問題がありまります。.iar.noinitinfo section is obviously incorrect.は、正しくありません。
この手動の検査では、ファイルに問題があるかどうかを確認できますが、ファイルにいくつかのnobitsセクションがある場合、問題の検出に失敗する可能性があります。元のファイルが1つのnobitsセクションを参照し、変更されたファイルは別のnobitsセクションを参照していることを検出する確実な方法はありません。
ファイルに問題がある場合の対処法は?
更新されたバージョンのiobjmanip が利用できます (以下参照)。
古いバージョンのiobjmanipで処理される前の元のファイルがある場合は、更新されたiobjmanipを使用して再度処理できます。 これにより、問題のないファイルが作成されます。
元のファイルにアクセスできない場合は、ファイルの提供元に連絡してください。 作成者は、更新されたiobjmanipを使用して、問題のないファイルを作成できます。
元のファイルが使用できない場合は、リンカ設定ファイルでdo not initializeディレクティブを使用することにより、問題2を回避できます。
問題1も回避するには、更新されたiobjmanipを使用して、すべての.iar.noinitinfoセクションを削除してください。
例:
// the section .noinit is not initialized
do not initialize { section .noinit };
// sections named .mysec from the object file myFile.o is not initialized
do not initialize { section .mysec object myFile.o };
空の .iar.noinitinfo sections / さらに複雑な問題
影響を受けるすべてのEmbedded Workbenchバージョンのiobjmanip(およびEWARM 8.42.1、EWARM 8.42.2、EWRISCV 1.20.1のiobjmanip)には、さらに問題が発生する可能性があります:
処理されたファイルにnobitsプロパティのELFセクションが含まれている場合、追加の.iar.noinitinfoセクションが追加されます。この追加されたセクションは常に空であり、情報は含まれいません。最近までこれは影響がなく、追加のセクションはリンクに影響しませんでした。
IAR Embedded Workbench for Arm 8.42 および IAR Embedded Workbench for RISC-V 1.20:
- .iar.noinitinfoは新しい形式になり、削除されたセクションが原因で発生するセクションの再番号付けによって破損することはありません。
- 最大で一つの .iar.noinitinfo セクションがILINKとiarchiveの各オブジェクトファイル に含まれることをチェックし、
- ILINK 致命的なエラーで終了します
- iarchive は終了します
- 含まれるiobjmanip は、誤って、空の .iar.noinitinfo セクションを追加します。
そのため iobjmanip がセクションを削除した後、.iar.noinitinfo セクションの内容が正しいにも関わらず、 ILINK もiarchive もこれらのファイルを受け入れません。
Iobjmanip 10.6.5.1221
このバージョンの Iobjmanip は、ここからダウンロードできます: <iobjmanip.exe>
これ以降のバージョンの iobjmanip は、ここで議論されている問題を解決しています:
• 出力に.iar.noinitinfoセクションを追加しません。
• 両方のタイプの.iar.noinitinfoセクションを持つファイルを破損することなく操作できます。
• .iar.noinitinfoセクションをチェックし、セクションが正しくないと思われる場合に警告します。
破損の検出と検証
.iar.noinitinfoセクションがが section contains the information that a section, for example NOI_SEC_u, is __no_init, but NOI_SEC_u is not nobits, the .iar.noinitinfo section is corrupt, and iobjmanip will warn and remove the corrupt section from the output (the original object file is not changed).
.iar.noinitinfoセクションに、例えばNOI_SEC_uセクションが__no_initであるが、NOI_SEC_uがnobitsではないという情報が含まれている場合、.iar.noinitinfoセクションは破損しており、iobjmanipは警告を出力し、破損したセクションを出力から削除します(元のオブジェクトファイルは変更されません)。
すべてのセクションNOI_SEC_uがnobitsである場合、.iar.noinitinfoセクションが破損しているという証拠はなく、出力は通常どおり作成されます(.iar.noinitinfoセクションがあり、警告はありません)。
他のケースの破損
上記の問題1で説明したように、入力ファイルに複数のnobitsセクションが含まれている場合、次のようになります:
- zero-initialized セクションは noinit になります
- noinit セクション は zero-initialized になります
残念ながらiobjmanip がこれを検出する方法はありません。
まとめ
iobjmanip 10.6.5.1221 は、本問題を持つ IAR Embedded Workbench のどのバージョンに対してでも動作します。
古いバージョンのiobjmanipでまだ処理されていないファイルをiobjmanip 10.6.5.1221を使用して処理する場合、生成されたELFファイルにはこれらの問題はありません。
古いバージョンのiobjmanipが.iar.noinitinfoの内容を破損している場合、iobjmanip 10.6.5.1221がこれを検出できる可能性があります。
場合によっては、誤った.iar.noinitinfoセクションを削除して、初期化されたコンテンツが__no_initとして扱われないようにすることができますが、そのような情報が破損している場合は、__ no_initコンテンツの.iar.noinitinfoセクションを修正できません。
ILINK & iarchive
iarchive 10.6.5.1221 以降のILINKリリースは、複数の.iar.noinitinfoセクションが検出されたときに、そのようなセクションに実際に情報が含まれている場合にのみ、致命的なエラーで終了します。 余分なセクションに情報が含まれていない場合、それらは無視されます。