Eclipse + CDT + yagarto (gnu ツールチェーン) + OpenOCD を使用して ARM をプログラムしようとしています。いくつかのサンプル プロジェクト (yagarto サイトなど) で、多くのリンク情報が (セクション定義と共に) 指定されているリンカー スクリプト (*.ld) を見つけました。実際、私は以前にこのファイルに直面したことがなく (IAR はそれらを必要としません)、一見しただけでは理解しにくいと思います。私の質問は、すべてのプロジェクトでターゲット プロセッサ (STR710FZ2T6) 用のスクリプト ファイルを 1 つ使用できるか、またはこのスクリプトの作成に慣れてプロジェクトごとに作成する必要があるかということです。特定のターゲット プロセッサのすべてのプロジェクトで 1 つのファイルを使用できる場合は、そのようなユニバーサル ファイルをどこで見つけることができるかアドバイスをください。
2 に答える
私の推測では、3 人に 1 人が異なるスクリプトまたはソリューションを持っていると思います。解決しなければならない問題は数多くありますが、さまざまなリンカがさまざまな方法でそれらを解決しようとしています。黒魔術ではないにしても、GNU はそれを難しくしすぎていると思います。
組み込みシステムの場合、多くの場合、フラッシュまたは eeprom またはその他の形式の読み取り専用メモリを使用して起動します。他のプロセッサと同様に、ARMにはベクトルテーブルがあり、基本的にリセットコードや割り込みなどがどこにあるかを伝えます. .
私が使用するのが好きなスクリプトの1つは次のとおりです。
MEMORY
{
bob (RX) : ORIGIN = 0x0000000, LENGTH = 32K
joe (WAIL) : ORIGIN = 0x2000000, LENGTH = 256K
}
SECTIONS
{
JANE : { startup.o } >bob
}
私は通常、bob と joe の代わりに ram と rom を名前として使用しますが、名前が何であるかは問題ではないことをここで示しています。
テーマの別のバリエーション:
MEMORY
{
rom(RX) : ORIGIN = 0x00000000, LENGTH = 0x8000
ram(WAIL) : ORIGIN = 0x20000000, LENGTH = 0x2000
}
SECTIONS
{
.text : { *(.text*) } > rom
}
最初のものでは、リンカ コマンド ラインに任意の順序でファイルを配置できますが、startup.o ファイルにベクタ テーブルを含める必要があります。後者では、任意のファイル名を使用できますが、リンカー スクリプトの最初のファイルにはベクター テーブルが必要です。
arm-thumb-elf-gcc -Wall $(COPS) vectors.o putget.o blinker2.c -T memmap -o blinker2.elf
または ld で直接
arm-thumb-elf-ld vectors.o putget.o blinker2.o -T memmap -o blinker2.elf
RX はリンカに、そのメモリ セクションに読み込みと実行を行うように指示し、WAIL は基本的にそれ以外のすべてです。たとえば、RAM が 1 つしかない場合は、すべてのフラグ RXWAIL を RAM の場所を示す行に置くことができます。その場合のローダーに応じて、開始する分岐先をローダーに伝えるelfファイルに依存するか、単にエントリポイントをバイナリの先頭にすると、ローダーがより単純になります。アーム (cortex-m3 ではない) には、リセット ベクトルの最初のベクトルとして分岐命令があるため、とにかく RAM ソリューション用にベクトル テーブルを構築するふりをするだけで機能します。
このソリューションには、たまたま気にならない多くの問題があります。宣言時ではなく、コード内で変数を初期化します。
これ
int rx;
int main ( void )
{
rx = 7;
それ以外の
int rx=7;
int main ( void )
{
また、コードの開始時に変数がゼロであると想定することは決してありません。開始する前に常に何かに初期化します。スタートアップ コードとリンカー スクリプトをチームとして連携させると、bss コードのリセットと、起動時に rom から ram へのゼロ以外の初期化データのコピーを簡単に自動化できます。(上記の int rx=7; には、値 7 を rom のどこかからコピーし、それを変数 rx に割り当てられた ram のメモリ位置に書き込むコードが必要です。
この方法の結果として、私のブート コードも非常に単純です。
.globl _start
_start:
b reset
b hang
b hang
b hang
b hang
b hang
b hang
b hang
b hang
b hang
b hang
b hang
b hang
b hang
b hang
hang : b hang
reset:
ldr sp,=0x10004000
bl main
b hang
起動コードとリンカー スクリプトを連携させて、スタック ポインターやヒープ スペースなどをハードコードする必要がないようにするソリューションについて見たり読んだりします。ここでも、複雑な起動コードとリンカーに多くの作業を加えることができます。スクリプトを使用して自動化を行い、おそらく作業を節約できますが、そうでない場合もあります。自動化は、人為的エラーを減らすことができ、またそれができる場合、それは良いことです。また、頻繁にチップを切り替えたり、チップのファミリーで動作するコードを1ビット書き込もうとしている場合も、この自動化が必要になる場合があります。 .
私の結論は、すべての ARM 作業に対して 1 つのリンカ スクリプトだけで生活できるということです。ただし、そのスクリプトに合わせて作業を調整する必要があります。全員のサンプル コードで機能するスクリプトはおそらく 1 つも見つかりません。スクリプトが複雑になればなるほど、借りるのが難しくなります。はい、上記のスクリプトは ld コマンド ラインで実行できる可能性がありますが、以前 (gcc 2.95) にそれを機能させることができなかったので、上記の最小限のスクリプトを開発し、それ以来使用しています。何らかの理由で 2 番目のスクリプトに変更する必要がありましたが、4.xx では、確かに 4.4.x のいずれかを使用できます。
ユニバーサルリンカースクリプトはありません。これらのスクリプトは、メモリ(RAMまたはROM)のどこにさまざまなデータおよびプログラムセクションを配置するかを定義するため、非常に重要です。IARコンパイラには同等のものがあります(正しく覚えていればxclファイル)。これまでは、明らかにデフォルトのものしか使用していません。
「STR7xx相互開発のためのオープンソースツールの使用」と呼ばれるSTR7xxに関する素晴らしいドキュメントがあります。yagartoのホームページにリンクがあります。それを見て、リンカーファイルがどのように機能するかを理解することをお勧めします。理解しておく必要のある他の構成ファイルもいくつかあります。