バイナリは異なるCPUアーキテクチャ間で移植可能ですか?

バイナリは異なるCPUアーキテクチャ間で移植可能ですか?

私の目標は、組み込みLinux用に開発することです。私はARMを使用したベアメタル組み込みシステムの経験があります。

さまざまなCPUターゲットの開発に関するいくつかの一般的な質問があります。私の質問は次のとおりです。

  1. 「のようにコンパイルされたアプリケーションがある場合x86ターゲット、Linuxオペレーティングシステムのバージョンxyz「他のシステムで同じコンパイルされたバイナリを実行できます」ARMターゲット、Linuxオペレーティングシステムバージョンxyz'?

  2. 上記が真でない場合の唯一の方法は、関連するツールチェーン「arm-linux-gnueabi」を使用してアプリケーションソースコードを再構築/再コンパイルすることです。

  3. 同様に、私にx86ターゲット、Linuxオペレーティングシステムのバージョンxyz「他のシステムで同じコンパイルされた.koをロード/使用できます。」ARMターゲット、Linuxオペレーティングシステムバージョンxyz'?

  4. 上記が真でない場合、唯一の方法は、関連するツールチェーン「例:arm-linux-gnueabi」を使用してドライバソースコードを再構築/再コンパイルすることです。

答え1

カント。バイナリはターゲットアーキテクチャに対して(再)コンパイルする必要があり、Linuxは同様の機能を提供しません。太ったバイナリ箱の外。その理由は、コードが特定のアーキテクチャ用の機械語コードにコンパイルされ、機械語コードがほとんどのプロセッサフ​​ァミリで非常に異なるためです(例:ARMとx86は非常に異なります)。

編集:一部のアーキテクチャは、64ビットCPUで以前のバージョンとの互換性レベル(まれに他のアーキテクチャとの互換性)を提供することに注意する価値があります。 32ビットバージョンと以前のバージョンとの互換性が一般的です(ただし、覚えておいてください:依存ライブラリ)C標準ライブラリを含む32ビットでなければなりません。静的リンク)。また言及する価値があります。アイテニアム、x86コード(32ビットのみ)を実行できますが、x86コードの実行速度が遅いことが少なくとも市場で成功しなかった理由の1つです。

互換モードでも、以前のCPUでは最新の命令でコンパイルされたバイナリは使用できません(32ビットバイナリではAVXを使用できません)。ネハレムx86プロセッサ; CPUはこれをサポートしていません。

カーネルモジュールは、関連するアーキテクチャに合わせてコンパイルする必要があります。さらに、32ビットカーネルモジュールは64ビットカーネルで実行できず、その逆も同様です。

クロスコンパイルバイナリに関する情報(ターゲットARMデバイスにツールチェーンは必要ありません)については、以下のgrochmalの包括的な答えを参照してください。

答え2

Elizabeth Myersの言葉は正しいです。各アーキテクチャには、そのアーキテクチャに合わせてコンパイルされたバイナリが必要です。システムが実行されているものとは異なるアーキテクチャ用のバイナリを構築するにはcross-compiler


ほとんどの場合、クロスコンパイラでコンパイルする必要があります。私はそれについて経験があるだけですgcc(しかし、他のコンパイラにも同様のパラメータがあると思いますllvm)。gccクロスコンパイラは、設定に以下を追加することで実装できます。--target

./configure --build=i686-arch-linux-gnu --target=arm-none-linux-gnueabi

gccこれらのパラメータとglibcbinutilsおよびターゲットマシンのカーネルのカーネルヘッダを提供する)を使用してコンパイルする必要があります。

実際、これははるかに複雑で、さまざまなシステムでさまざまなビルドエラーが発生します。

GNUツールチェーンをコンパイルする方法に関するいくつかのガイドがありますが、私は次のことをお勧めします。最初からLinux、これは継続的に維持され、提供されたコマンドの機能の良い説明を提供します。

別のオプションは、クロスコンパイラを使用したブートストラップコンパイルです。クロスコンパイラを別のアーキテクチャにコンパイルするのに苦労してくれてありがとうcrosstool-ng生成されます。クロスコンパイラを構築するために必要なツールチェーンのブートストラップを提供します。

crosstool-ng複数のサポート目標三重項他のアーキテクチャでは、基本的にクロスコンパイラツールチェーンのコンパイル中に発生する問題を解決するために時間を費やすブートストラップです。


一部のディストリビューションでは、クロスコンパイラをパッケージとして提供しています。

つまり、クロスコンパイラの観点から、ディストリビューションが何を使用できるかを確認します。ディストリビューションに要件を満たすクロスコンパイラがない場合は、いつでも直接コンパイルできます。

引用:


カーネルモジュールのコメント

クロスコンパイラを手動でコンパイルすると、カーネルモジュールをコンパイルするために必要なものがすべて揃っています。をコンパイルするにはカーネルヘッダが必要ですglibc

ただし、ディストリビューションが提供するクロスコンパイラを使用する場合は、ターゲットコンピュータで実行されているカーネルのカーネルヘッダファイルが必要です。

答え3

最後の手段として(つまり、ソースコードがない場合)qemu。一部のエミュレータは、Linux以外のシステムをエミュレートするように設計されています(たとえば、MS-DOSプログラムを実行するように設計されており、広く使用されているゲームコンソール用のエミュレータがたくさんあります)。エミュレーションにはかなりのパフォーマンスオーバーヘッドがあります。エミュレーションプログラムは、基本プログラムより2〜10倍遅く実行されます。dosboxexageardosbox

デフォルト以外のCPUでカーネルモジュールを実行する必要がある場合は、同じアーキテクチャのカーネルを含むオペレーティングシステム全体をエミュレートする必要があります。 AFAIK Linuxカーネル内では外部コードを実行できません。

答え4

いつも目標を立てなければならないプラットフォーム。最も簡単な場合、ターゲットCPUはバイナリでコンパイルされたコードを直接実行します(これはおおよそMS DOSのCOM実行可能ファイルに対応します)。私が発明した2つのプラットフォーム、ArmisticeとIntellioを考えてみましょう。どちらの場合も、画面に42を印刷する単純なhello worldプログラムがあります。また、プラットフォームに依存しない方法でマルチプラットフォーム言語を使用すると仮定するため、両方の言語のソースコードは同じです。

Print(42)

Armisticeには数字の印刷を担当する簡単なデバイスドライバがあるので、ポートに出力するだけです。移植可能なアセンブリ言語では、次のようになります。

out 1234h, 42

ただし、Intellioシステムにはそのような機能がないため、別の層を通過する必要があります。

mov a, 10h
mov c, 42
int 13h

一体機械コードに到達する前に、両者の間にはすでに大きな違いがあります!これは、ほぼLinuxとMS DOS、IBM PCとX-Box(どちらも同じCPUを使用しても)の違いに対応します。

しかし、それがまさにオペレーティングシステムの存在理由です。さまざまなハードウェア構成がアプリケーション層で同じように処理されることを保証するHALがあるとします。基本的には、ArmisticeでもIntellioアプローチを使用し、「移植可能なアセンブリ」コードは最終的に同じになります。これは、最新のUnixシリーズシステムとWindowsで使用され、組み込みシナリオでもよく使用されます。素晴らしいです。 ArmisticeとIntellioで同じ移植可能なアセンブリコードを持つことができます。しかし、バイナリはどうですか?

仮定したように、CPUはバイナリを直接実行する必要があります。mov a, 10hIntellioの最初のコード行を見てみましょう。

20 10

ああ。mov a, constant独自のガイドラインとオペコードがあるほど人気が​​高いことが証明されています。休戦協定はこの問題にどのように対処しましたか?

36 01 00 10

よく。 opcodemov.reg.immなので、割り当てるレジスタを選択するには別のパラメータが必要です。定数はビッグエンディアン表記法では常に2バイトの単語です。これは停電が設計された方法であり、実際に停電のすべてのコマンドは例外なく4バイトの長さです。

さて、ArmisticeでIntellioのバイナリを実行すると想像してください。 CPUは命令デコードを開始し、opcodeを見つけます20h。休戦協定では、これはand.imm.reg指示に対応します。 2バイトのワード定数(読み取り10XX、すでに問題があります)を読み、次にレジスタ番号(もう1つXX)を読み取ろうとします。誤ったパラメータで誤ったコマンドを実行します。さらに悪いことは、私たちが実際に他の命令をデータだと思って食べたので、次の命令は完全に偽になるということです。

アプリケーションを実行する機会がなく、すぐにクラッシュしたりハングしたりする可能性があります。

これは、実行可能ファイルが常にIntellioまたはArmisticeで実行されているとマークする必要があるわけではありません。 CPUに依存しないプラットフォーム(bashUnixなど)またはCPUとオペレーティングシステムに依存しないプラットフォーム(Javaまたは.NET、JavaScriptなど)を定義するだけです。この場合、アプリケーションは他のすべてのCPUとオペレーティングシステムに対して1つの実行可能ファイルを使用できますが、コードにはプラットフォームに依存しないターゲットシステム(正しいCPUおよび/またはオペレーティングシステムを直接ターゲットとする)にいくつかのアプリケーションまたはサービスがあります。 CPUが実際に実行できるように変換されます。これは、パフォーマンス、コスト、または機能に影響を与える場合もあれば、そうでない場合もあります。

CPUは通常シリアルで提供されます。たとえば、x86ファミリのすべてのCPUにはまったく同じ方法でエンコードされた共通命令セットがあるため、すべてのx86 CPUは拡張(浮動小数点演算など)を使用しない限り、すべてのx86プログラムを実行できます。またはベクトル算術)。 x86では、今日の最も一般的な例はもちろん、IntelとAMDです。 Atmelは、組み込みデバイスで非常に広く使用されているARMシリーズCPUを設計するよく知られた会社です。たとえば、Appleには独自のARM CPUもあります。

ただし、ARMはx86と完全に互換性がありません。設計要件は非常に異なり、共通点もほとんどありません。これらの命令は完全に異なるオペコードを持ち、別々にデコードされ、メモリアドレスが異なるように処理されます...いくつかの安全な操作を使用してx86 CPUとARM CPUの両方で実行されるバイナリを作成することができます。まったく異なる命令セットですが、これはまだ両方のバージョンが別々の命令を持ち、1つのブートストラップだけが実行時に正しい命令セットを選択することを意味します。

関連情報