問題タブ [linker-scripts]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
linker - GNU リンカ スクリプトのロケーション カウンタについて
私は Atmel SAM7S256 マイクロコントローラー用のソフトウェアをゼロから作成している大学のプロジェクトに取り組んでいます。今回はリンカー スクリプトとアセンブリ言語の知識が必要なため、以前に使用した他の MCU よりも詳細です。
SAM7/ARM プロジェクトをゼロから開始する方法を完全に理解するために、SAM7S チップのサンプル プロジェクトを精査してきました。注目すべき例は、Miro Samek の「Building Bare-Metal ARM Systems with GNU」チュートリアル(この質問のコードの出典) です。また、sourceware.org からリンカとアセンブラのドキュメントを読むのにも多くの時間を費やしました。
次のリンカ スクリプトの大部分を理解できて、とてもうれしく思います。ロケーション カウンターに関して、私には理解できないことが 1 つだけあります。以下は、上記のチュートリアルで提供されるリンカー スクリプトです。
例全体 (.ramvect、.fastcode、および .stack セクションなど) には、 などのシンボル定義があります__ram_start = .;
。これらのアドレスは、MCU の RAM 内の正しい位置を初期化するために、スタートアップ アセンブリ コードと初期化 C コードによって使用されます。
私が理解に問題を抱えているのは、これらのシンボル定義がどのようにして正しい値が割り当てられるかということです。これは起こります。スクリプトは正しいですが、方法がわかりません。
私が理解しているように、セクション内でロケーション カウンターを使用すると、セクション自体の仮想メモリ アドレス (VMA) からの相対オフセットのみが含まれます。
したがって、たとえば、行__ram_start = .;
では、__ram_start に 0x0 の値が割り当てられると予想されます。これは、.ramvect セクションの最初に位置カウンターの値が割り当てられているためです。ただし、初期化コードが正しく機能するためには (実際に機能します)、__ram_start を 0x00200000 (RAM の開始アドレス) として割り当てる必要があります。
行が代わりに__ram_start = ABSOLUTE(.);
または__ram_start = ADDR(.ramvect);
.
__fastcode_start
と についても同様__stack_start__
です。それらをすべてアドレス 0x0 として定義することはできません。そうしないと、プログラムが機能しません。しかし、ここにリンクされているドキュメントは、それが起こっていることを示唆しているようです。ドキュメントからの引用は次のとおりです。
ノート: 。実際には、現在含まれているオブジェクトの先頭からのバイト オフセットを参照します。通常、これは SECTIONS ステートメントであり、その開始アドレスは 0 であるため、. 絶対アドレスとして使用できます。もしも 。ただし、セクション記述内で使用される場合は、絶対アドレスではなく、そのセクションの先頭からのバイト オフセットを参照します。
したがって、これらのシンボル割り当て中のロケーション カウンター値は、対応するセクション VMA からのオフセットである必要があります。したがって、これらの「_start」シンボルはすべて0x0 に設定されているはずです。これはプログラムを壊します。
だから明らかに私は何かが欠けています。ロケーション カウンター値を (セクション内の) シンボルに割り当てると、デフォルトで ABSOLUTE() が使用されるという単純な結果になると思います。しかし、これを確認する明確な説明をどこにも見つけることができませんでした。
誰かがこれを解決できる場合は、事前に感謝します。
linker - スタックの開始アドレスを移動できるリンカー スクリプト ディレクティブはありますか?
x86_64 でリンカー スクリプトを使用して、スタックの開始位置を変更しようとしています。これを使用して、実行可能な開始アドレスを移動できました。
グローバルを次のように変更しました。
スタック領域を移動するために以下を使用しようとしました:
しかし、それは私をどこにも連れて行きませんでした。
スタックの場所をテストするために使用するテスト プログラムは次のとおりです。
これは、gcc のデフォルト リンカー スクリプトからの出力です (変更なし)。
私のリンカースクリプトからの出力は次のとおりです。
nmが新しい場所を出力するので、私は本当に混乱しています:
stack_start と stack_end が x86_64 で有効かどうかさえわかりませんが、arm のリンカ スクリプト チュートリアルからその部分をオンラインで取得したためです。リンカー スクリプトでエラーや警告が表示されないため、何が起こっているのかわかりません。
なぜ誰かがこれを行うのか疑問に思っている場合は、セキュリティ研究に影響があります。
リンカー スクリプトを使用してやりたいことを実行する方法はありますか? .text、.bss、および .data セクションは移動できるが、スタックは移動できないとは信じられません。
更新: http://www.lurklurk.org/linkers/linkers.html#osから取られた説明は、これがリンカで実行できない理由です:
「これまでのオブジェクト ファイルとリンカーに関するすべての説明は、グローバル変数についてのみ説明していることに気付いたかもしれません。前述のローカル変数と動的に割り当てられたメモリについては言及されていません。これらのデータには、リンカーの関与は必要ありません。なぜなら、それらの寿命は、プログラムが実行されているとき、つまりリンカーが業務を終了してからずっと後にしか発生しないからです。」
c - リンカー スクリプトでのアーカイブ ファイルの抽出
次のような問題に対処しようとしています。
以下から作成されたライブラリ libxyz.a があるとします。
以下を使用してコンパイルおよびアーカイブ:
abc.o を期待される場所に正確に配置するには、リンカー スクリプトをどのように作成する必要がありますか?
私はそのような方法でそれを処理しようとしていました:
しかし、実行後:
私は得る:
フォーラムのリンカー ファイルでアーカイブを抽出する例は見つかりませんでした。私が見つけた唯一のものは、構造に関する情報のみを含むリンカのドキュメントでしたarchive:file
。
c++ - 関数ポインタによる「main」の定義
C++ では、main を関数ポインタで定義することは可能ですか? 例えば:
このコードは正しくコンパイルおよびリンクされますが、実行時にセグメンテーション エラーが発生します。関数ポインタの値をコードとして実行しようとしているからだと思います。
さらに、プレーンな C++ では不可能な場合は、gcc の非標準機能によって実現できます (おそらく、エクスポートされたシンボルの型を何らかの方法で変更します)。
最後に、gcc ディレクティブで実現できない場合、カスタム リンカー スクリプトで実現できますか?
cortex-m3 - 2 つのファームウェアが同じリンカー スクリプトでリンクされている場合、リセット ベクターのアドレスが異なるのはなぜですか?
Cortex-M3 チップがあり、eCos を使用するブートローダーを実行しています。ブートローダーは、ファームウェアの更新などを確認した後、実際のアプリケーションが存在する ROM 上の別の場所 (BASE_ADDRESS_OF_APP + 0x19) にジャンプします (これも eCos でコンパイルされています)。
ここで、通常のファームウェアを実行する代わりに、Cortex-M3 ターゲット用にコンパイルされた CppUTests を実行したいと考えています。そのため、実際のオペレーティング システムではなく、ecos glibc を使用してターゲット プラットフォーム用にテストをコンパイルおよびリンクできます。しかし、JTAG を使用してボードにロードすると、実行されません。
arm-eabi-objdump を使用して調査した結果、CppUTest ファームウェアのリセット ベクターが、通常のファームウェアのオフセット 0x18 とは対照的に、オフセット 0x490 にあることがわかりました。私の疑いは、これがテストが実行されない理由であるということです。これは正しいです?
2 つのファームウェアを同じリンカー スクリプトでリンクしているときに、これらのファームウェアの開始アドレスが異なる可能性があるのはなぜですか?
テスト プログラムの開始点がアプリケーションの開始点と同じであることを確認するにはどうすればよいですか?
c - 暗黙的なリンカ スクリプトがセクションの LMA を変更するのを防ぐ方法
私は、通常の X86 (Linux) マシンだけでなく、ARM 組み込みターゲットでも動作するソフトウェア用のモジュラー ビルド システムを使用しています。私はGNUツールチェーンでコンパイルしているので、ld
.
モジュールの 1 つは、リンカー スクリプトのトリックを使用して、「登録済み」オブジェクトの配列をアセンブルします。オブジェクトは、次のようなマクロで作成されます。
このモジュールは、次のような暗黙的なリンカー スクリプトもリンク ステップに追加します。
regobj_table_start
とのregobj_table_end
記号は、登録されたオブジェクトを検索するためにコードで使用されます。このソリューションは、ネイティブ (Linux) でコンパイルされたターゲットに対してうまく機能します。
ただし、これは ARM ターゲットでは機能しません。その理由は、.data
セクションのロード メモリ アドレスを定義する、ターゲット (OS なしで実行される小さなマイクロコントローラー) 用のカスタムの既定のリンカー スクリプトがあるためです。これは、セクションがフラッシュ メモリに格納されているためですが、マイクロコントローラが起動すると RAM にコピーされます。リンカー スクリプトの関連部分は次のようになります。
これにより、セクションの VMA が.data
0x4000000 の範囲のどこかに設定され、LMA が 0x00000000 の範囲に設定されます。
問題は、暗黙のリンカ スクリプトが のコマンド ラインに追加されるとld
、LMA を忘れて、再び VMA と同じになることです。ld
暗黙のリンカ スクリプトをロードするときに LMA に触れないように指示する方法を必死に探しています。
c - サンプル コードをコンパイルしてリンクし、バイナリを取得するにはどうすればよいですか?
私は TI Stellaris LM3S1968 を使用しています。この MCU には ARM Cortex-M3 が搭載されています。
Windows 7 を搭載したラップトップに VM をインストールし、そこにGNU Tools for ARM Embedded Processorsをインストールしました。次に、Stellaris Flash Programmer、GUI、およびコマンド ラインをインストールしました。Stellaris FTDI Driversもインストールしました。
最後に、EK-LM3S1968 Firmware Development Packageをダウンロードして解凍しました。
解凍したフォルダには、いくつかの例があります。それらの1つは点滅です。/StellarisWare/board/ek-lm3s1968/blinky/gcc/ に移動すると、blinky.bin というファイルがあります。Stellaris Flash Programmer を使用して、コンピューターに接続してフラッシュするだけで動作します。さまざまな例で試してみましたが、すべてうまくいきました。
ここでの目標は、/StellarisWare/board/ek-lm3s1968/blinky/ で提供されているサンプル コードをコンパイルし、フラッシュすることです。しかし、私は C やプログラミング マイクロコントローラーの経験があまりないので、あまり運がありませんでした。
LM3S1968 ライブラリを StellarisWare フォルダからコンパイラの include フォルダにコピーしました。次に、オンラインで見つけたいくつかの例に従いましたが、成功しませんでした。これは私が試したものです:
この .bin ファイルをフラッシュしても何もせず、LED は点灯したままです。
プログラムを実行する前にMCUの起動を処理するstartup_gcc.cファイルがあるためだと思います。しかし、私はそれをバンドルする方法がわかりません。
さまざまな IDE 用のファイルがたくさんありますが、フリーではないため、GNU ツールを使用したいと考えています。
ここで StackOverflow とググって検索してみましたが、答えが見つかりませんでした。
gcc - __libc_init_arrayを理解する
http://newlib.sourcearchive.com/documentation/1.18.0/init_8c-source.htmlから__libc_init_arrayのソースコードを表示しました。
しかし、私はこの関数が何をするのかよくわかりません。
私はこれらのシンボルが
リンカスクリプトで定義されています。
リンカスクリプトの一部は次のようになります。
次に、ELF-v1.1、gcc 4.7.2、ld、およびcodesourcery(codesourcery g ++ liteを使用しています)のドキュメントでキー「init_array」を使用して検索したところ、何も得られませんでした。
これらの記号の仕様はどこにありますか?
ld - 巨大なバイナリを生成するldリンカースクリプト
私はを使用してbinutils-2.21.53.0.1-6.fc16.x86_64
います。
hello.o
すべてのセクションにコンテンツを含めるのに十分な「もの」を含む小さなオブジェクトファイルがあります。
リンカースクリプトを使用し、リンカースクリプトを使用-pie
しない場合、結果は期待どおりです。
ただし、何らかのリンカースクリプトを含めると、出力サイズが爆発します。
ご覧のとおり、このファイルは巨大になりました。
.text
これは、セクションがファイルのオフセット0x200000から開始することを要求しているために発生するように見えることに注意してください。
これは、リンカースクリプトの内容に関係なく発生しています。何が起こっているのかアイデアはありますか?
gcc - gcc libs .data を特定のセクションに入れますか?
組み込みシステム用に GNU GCC コンパイラに切り替えようとしていますが、チップのメモリ レイアウトが分割されているため、プロジェクトのリンクに問題があります。
プロジェクトのデータはセクション 1 に収まりますが、gcc ライブラリからリンクされたデータは収まりません。マップ ファイルの抽出:
libs の .data セクションを 2 番目のセクションに入れることはできますか? 成功せずに別のことを試しました...リンカースクリプトの抽出: