質問

何がスタックの配?なぜですか?で制御することによりコンパイラの設定?

の詳細これらの問題に直面しようとした場合に使用gparted図書館とmsvc、しかしどんだけで"スタックト.

詳細:

  • 時runnig私はmsvc遵守するプログラムへのリンク文字列を取得します。 以下のようなエラー:"コンパイラしなかったわスタック変数です。Libavcodecは てmiscompiled"は、クラッシュavcodec.dll.
  • avcodec.dll ませんでしたデmsvcるだけではできない何が起こっているのか。
  • 実行する場合ffmpeg.exe と同じavcodec.dll もより確かなものになるはずだ。
  • ffmpeg.exe ませんでしたデmsvc、遵守gcc/mingwと同じavcodec.dll)

おかげさ

役に立ちましたか?

解決

メモリ内の変数のアライメント(短い歴史)。

過去のコンピューターでは8ビットのデータバスを持っていました。これは、情報の各クロックサイクル8ビットを処理することができることを、意味します。これはその後、大丈夫だった。

そして、16ビットコンピュータが来ました。下位互換性および他の問題のために、8ビット・バイトを保持し、16ビット・ワードが導入されました。各ワードは2つのバイトでした。各クロックサイクルは16ビットの情報を処理することができます。しかし、これは小さな問題を提起します。

のメモリマップを見てみましょう。

+----+
|0000| 
|0001|
+----+
|0002|
|0003|
+----+
|0004|
|0005|
+----+
| .. |

各アドレスに個別にアクセスすることができるバイトがあります。 しかし、言葉だけでも、アドレスに取り出すことができます。だから私たちは0000で単語を読めば、我々は0000と0001でバイトを読んしかし、我々は位置0001で単語を読みたい場合は、我々は2つの読み取りアクセスを必要とします。 0000,0001まずその後、0002,0003、我々は唯一0001,0002をキープます。

もちろんこれは、いくつかの余分な時間がかかったし、それが認識されていませんでした。彼らは、アライメントを発明だから、なぜです。だから我々は、バイト境界でワード境界でワード変数とバイトの変数を格納ます。

たとえば、私たちはバイトのフィールド(B)とワードフィールド(W)(と非常にナイーブコンパイラ)との構造を持っている場合、我々が得る次:

+----+
|0000| B
|0001| W
+----+
|0002| W
|0003|
+----+

は楽しいではありません。ワードアライメントを使用している場合しかし、我々は見つけます:

+----+
|0000| B
|0001| -
+----+
|0002| W
|0003| W
+----+

ここで、メモリはアクセス速度のために犠牲にされています。

あなたはダブルワード(4バイト)、またはクワッドワード(8バイト)を使用している場合、これはさらに重要であることを想像することができます。最も近代的なコンパイラでは、プログラムのコンパイル中に、使用しているアライメント選ぶことができた理由です。

他のヒント

一部のCPUを必要とするアーキテクチャの特定の配列の各種データ型、例外をスローなければ光栄です。スタンダードモードにおいてx86必要としないこの基礎データの種類できな性能の罰則(チェックインwww.agner.org 低レベルの最適化のヒント).

しかし、 SSE 命令セット(多く使用されてい高性能オーディオ/ビデオの処理は、厳しい配列の要件は、例外をスローしようとすると、利用でunalignedデータを使用しない限り、一部のプロセッサー、遅いunaligned版).

発生した しょう 一つのコンパイラの期待に 呼び出し側 のスタックを揃えて、その他の期待 相手先 を揃えるスタックが必要です。

編集:どうして例外が起こり、通常のDLLだろうというSSE指示一部の臨時スタックのデータを、失敗したので、二つの異なるコンパイラの思い出コンベンションに出かけていく。

変数はバイトの特定の番号に「整列」スタック上に配置されたときに、

IIRC、スタックのアライメントです。あなたは16ビットのスタック・アライメントを使用しているのであれば、スタック上の各変数は、関数内で現在のスタックポインタから2バイトの倍数であるバイトから開始する予定です。

これは、このようなCHAR(1バイト)として<2バイトであり、変数を使用する場合、それは、次の変数の間の未使用の「パディング」の8ビットが存在するであろうことを意味します。これは、変数の位置に基づいて仮定して、特定の最適化を可能にする。

関数を呼び出すとき(レジスタに直接置くとは対照的に)

、次の関数に引数を渡す方法の一つは、スタック上に配置することです。呼び出し元の関数は、オフセットを使用して呼び出し元の関数ではオフに読み取られるように、スタックに変数を置くようアライメントは、ここで使用されているかどうかは、重要です。呼び出し元の関数は、変数を整列し、呼び出された関数は、それらが非整列であることを想定している場合は、呼び出された関数はそれらを見つけることができません。

MSVCコンパイルされたコードは、変数のアライメントについて不同意されているようです。オフにすべて最適化してコンパイルしてみます。

私の知る限りでは、コンパイラは通常、スタック上にある変数を整列しません。ライブラリには、コンパイラでサポートされていないコンパイラオプションのいくつかのセットに応じてすることができます。通常の修正は、静的として整列する必要がある変数を宣言することですが、あなたが他の人のコードでこれをやって行けば、あなたは、問題の彼らは、変数、関数ではなく、中、後に初期化されていることを確認したいでしょう宣言ます。

// Some compilers won't align this as it's on the stack...
int __declspec(align(32)) needsToBe32Aligned = 0;
// Change to
static int __declspec(align(32)) needsToBe32Aligned;
needsToBe32Aligned = 0;

代わりに、スタックに変数を整列コンパイラスイッチを見つけます。もちろん、私がここで使用してきた揃える「__declspec」構文はコンパイラが使用するものではありません。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top