Cプログラム内でアセンブリ言語を使用する目的は何ですか?コンパイラはすでにアセンブリ言語を生成できます。どのような場合に、Cよりもアセンブリを作成する方が良いでしょうか?パフォーマンスは考慮事項ですか?
6 に答える
誰もが言ったことに加えて、すべてのCPU機能がCに公開されているわけではありません。特にドライバーやオペレーティングシステムのプログラミングでは、他の方法では利用できない特殊レジスターやコマンドを明示的に操作する必要がある場合があります。
また、ベクトル拡張。
これは、コンパイラ組み込み関数が登場する前は特に当てはまりました。これらは、インラインアセンブリの必要性をいくらか軽減します。
インラインアセンブリのもう1つのユースケースは、Cを反映された言語とインターフェースすることと関係があります。具体的には、コンパイル時にプロトタイプが不明なときに関数を呼び出す必要がある場合は、アセンブリがほとんど必要です。言い換えると、その関数の引数の量とデータ型が実行時変数にすぎない場合です。この場合、可変個引数関数と機構は役に立ちません。スタックフレームの解析stdarg
には役立ちますが、ビルドには役立ちません。一方、組み立てでは、それはかなり実行可能です。
これはOS/ドライバーのシナリオではありません。JavaのJNIとCOMAutomationの少なくとも2つのテクノロジーがあり、これは必須です。自動化の場合、COMランタイムがタイプライブラリを使用してデュアルインターフェイスをマーシャリングする方法について話します。
そのためのアセンブリの非常に粗雑なCの代替案を考えることができますが、それは罪として醜いでしょう。
さらに別のユースケース:クラッシュ/ランタイムエラーレポート。事後デバッグの場合、クラッシュの時点で可能な限り多くのプログラム状態(つまり、すべてのCPUレジスター)をキャプチャする必要があります。アセンブリは、Cよりもはるかに優れた手段です。
私は組み立てが必要な場合だけをカバーしてきました。パフォーマンスを手動で最適化する方法については、他の回答で説明しています。
多くはありませんが、CコンパイラがCソースコードから生成したアセンブリ言語よりも、手動で最適化されたアセンブリ言語をより効率的に実行できる場合がいくつかあります。また、アセンブリ言語に慣れている開発者にとっては、アセンブラで記述しやすいものもあります。
このような場合、多くのCコンパイラはインラインアセンブリを許可します。
ただし、Cコンパイラがどんどん良くなり、効率的なコードを生成するにつれて、これはますますまれになります。ほとんどのプラットフォームでは、アセンブラで記述することで最も恩恵を受けるソフトウェアの種類であることが多い低レベルの種類のソフトウェアの一部に制限があります。
一般的に、それはパフォーマンスですが、非常に特殊な種類のパフォーマンスです。たとえば、プロセッサのSIMD並列命令は、コンパイラによって生成されない場合があります。プロセッサ固有のデータ形式を利用してから、プロセッサ固有の並列命令(ARMNEONやIntelSSEなど)を発行することにより、グラフィックスまたは信号処理の問題で非常に高速なパフォーマンスが発生する可能性があります。それでも、一部のコンパイラでは、組み込み関数を使用してこれらをCで表現できます。
アセンブリ言語の挿入を使用して重要な機能を手動で最適化するのが一般的でしたが、当時はほとんど行われていました。最新のコンパイラは非常に優れており、最新のプロセッサには非常に複雑なタイミング要件があるため、手動で最適化されたコードは予想よりも最適ではないことがよくあります。
Cでインラインアセンブリを作成する理由はさまざまです。理由を必要なものと不要なものに簡単に分類できます。
不必要な理由で、おそらく次のようになります。
- プラットフォームの互換性
- パフォーマンスに関するパフォーマンス
- コードの最適化
- 等
上記は、純粋なCを介して破棄または実装できる場合があるため、不要だと思います。たとえば、プラットフォームの互換性など、プラットフォームごとに特定のバージョンを完全に実装できますが、インラインアセンブリを使用すると労力が軽減される場合があります。ここでは、不必要な理由についてあまり話しません。
必要な理由で、それらはおそらく次のようになります。
- 標準ライブラリで何かを行うには不十分でした
- 一部の命令セットはコンパイラでサポートされていませんでした
- 正しく生成されていないオブジェクトコード
- スタックに依存するコードの記述
- 等
これらの理由は、純粋なC言語ではほとんど実行されないため、必要であると考えられます。たとえば、古いDOS
esでは、ソフトウェア割り込みINT21
は再入可能ではありませんでした。コンパイラで完全にサポートされている仮想ディレクトリを作成したい場合INT21
、それは不可能でした。INT21
この状況では、オリジナルをフックして、再入可能にする必要があります。ただし、コンパイルされたコードは、すべての呼び出しをprolog/epilogでラップします。したがって、制限されているものを壊すことはできません。または、コードをクラッシュさせただけです。ライブラリでCの純粋な言語を使用することにより、任意のトリックを試すことができます。しかし、あなたがうまくトリックを見つけることができたとしても、それはあなたが特定の注文を見つけたことを意味しますコンパイラがマシンコードを生成すること。これは、コンパイラにコードを正確にマシンコードにコンパイルさせようとしたことを意味します。では、インラインアセンブリを直接記述してみませんか?
この例では、上記以外の必要な理由をすべて説明しinstruction set not supported
ましたが、それは簡単に考えられたと思います。実際、インラインアセンブリを作成する理由は他にもありますが、これでいくつかのアイデアが得られます。
好奇心と同じように、ここでは、アセンブリでしか実行できないそれほど低レベルではないものの具体的な例を追加します。これは、C / C ++の固有の制限と、アセンブリでそれを克服する方法を示すために使用された大学時代のアセンブリブックで読みました。
問題は、パラメーターの正確な数が実行時にのみわかっている場合、どのように関数を呼び出すかです。実際、C / C ++では、のような可変数の引数を取る関数を簡単に定義できますprintf
。しかし、その関数を呼び出す場合、コンパイラーは、渡される必要のあるパラメーターの数を正確に知りたいと考えています。必要以上に多くのパラメーターを渡すことができますが、害はありません。しかし、数が予期せずに100または1000パラメーターに増加し、配列から選択する必要がある場合はどうなるでしょうか。もちろん、解決策はアセンブリを使用することです。ここでは、適切なサイズのスタックフレームを動的に作成し、スタック上のパラメーターをコピーし、関数を呼び出し、最後にスタックをリセットできます。
実際には、これが制限になることはほとんどありません(使用しているライブラリが本当に設計が悪い場合を除く)。Cでアセンブリを使用する人は、他の人が回答で指摘しているように、そうする理由がはるかにあります。それでも、知っておくと面白い事実かもしれないと思います。
私はむしろ、特定のプラットフォーム用の非常に特定のコードを書く方法としてそれを考えたいと思います。最適化は、今でも一般的ですが、最近ではあまり使用されていません。Cでのアセンブリの知識と使用法も、オールカラーの帽子で実践されています。