7

(この質問が重複しているか、ここですでに回答されている可能性が高いと思いますが、「スタック割り当て」および関連用語からの干渉のおかげで、回答を探すのは困難です。)

スクリプト言語用に取り組んでいるおもちゃのコンパイラがあります。進行中のスクリプトの実行を一時停止してホスト プログラムに戻ることができるようにするために、スクリプトには独自のスタックがあります。通常の C コード操作を使用してインクリメントされる「スタック ポインター」変数を持つ単純なメモリ ブロックです。そのようなことなどのために。今のところ面白くない。

現時点では、C にコンパイルします。しかし、マシン コードへのコンパイルについても調査したいと考えています。同時に、セカンダリ スタックと、定義済みの制御ポイントでホスト プログラムに戻る機能を維持します。

だから...自分のコード内で従来のスタックレジスタを使用することは問題になる可能性は低いと思います.レジスタに何が起こるかは、それが完了したときにすべてが復元される限り、私自身のビジネスであると思います.この点は間違っています)。しかし...スクリプトコードを他のライブラリコードに呼び出す場合、この「仮想スタック」を使用してプログラムを離れても安全ですか、それともこの目的のために元のスタックを返すことが不可欠ですか?

this oneおよびthis oneのような回答は、スタックが従来のメモリブロックではなく、ページフォールトなどを処理するための特別なシステム固有の動作に依存していることを示しています。

そう:

  • スタックポインタをメモリの他の領域に移動しても安全ですか? スタックメモリは「特別」ではありませんか? スレッドライブラリは、より多くのスタックを作成するため、このようなことをしなければならないと思います...
  • メモリのどの領域もスタック レジスタと命令を使用して安全に操作できると仮定すると、既知の呼び出し深度 (つまり、再帰なし、関数ポインターなし) で関数を呼び出すことが問題になる理由は思い浮かびません。 amount は仮想スタックで利用可能です。右?
  • いずれにせよ、スタック オーバーフローは通常のコードでは明らかに問題ですが、そのようなシステムでオーバーフローが発生すると、さらに悲惨な結果が生じるでしょうか?

ポインタを実際のスタックに戻すだけで完全に機能するため、これは明らかに実際には必要ありません.まったく(少なくとも、明らかに私の深みから外れているため)。しかし、私はまだどちらにしても興味があります。これらの種類のものがどのように機能するか知りたいです。

編集:もちろん申し訳ありませんが、言うべきでした。私は x86 (自分のマシンでは 32 ビット)、Windows、および Ubuntu で作業しています。エキゾチックなものは何もありません。

4

3 に答える 3

4

これらの答えはすべて「一般的なプロセッサアーキテクチャ」に基づいており、アセンブラコードの生成が含まれるため、「ターゲット固有」である必要があります。スタックの処理が奇妙なプロセッサXでこれを行う場合は、以下を参照してください。 [紙の代わりに]書かれている画面の表面には明らかに価値がありません。x86の場合、特に明記されていない限り、以下が当てはまります。

is it safe to move the stack pointers into some other area of memory?

スタックメモリは「特別」ではありませんか?スレッドライブラリはより多くのスタックを作成するので、このようなことをしなければならないと思います...

記憶自体は特別なものではありません。ただし、これは、スタックセグメントがスタックの使用を制限するために使用されるx86アーキテクチャ上にないことを前提としています。それは可能ですが、実装で見られることはかなりまれです。数年前、ノキアには32ビットモードのセグメントを使用する特別なオペレーティングシステムがあったことを私は知っています。私が今考える限り、x86セグメンテーションモードで説明されているように、スタックセグメントを使用するのはこれだけです。

スタックレジスタと命令を使用してメモリの任意の領域を安全に操作できると仮定すると、既知の呼び出し深度(つまり、再帰なし、関数ポインタなし)で関数を呼び出すことが問題になる理由は考えられません。量は仮想スタックで利用可能です。右?

正しい。元のスタックに戻らずに他の機能に戻れるとは思わない限り。スタックが十分に深い限り、制限されたレベルの再帰も許容されます[再帰なしで解決するのが確実に難しい特定のタイプの問題があります-たとえば、二分木検索]。

とにかく、スタックオーバーフローは明らかに通常のコードの問題ですが、そのようなシステムのオーバーフローにさらに悲惨な結果が生じるでしょうか?

確かに、あなたが少し運が悪ければ、それをクラックするのは難しいバグでしょう。

VirtualProtect()(Windows)または(Linuxなど)の呼び出しを使用してmprotect()、「スタックの終わり」を読み取り不可および書き込み不可としてマークすることをお勧めします。これにより、コードが誤ってスタックから外れた場合に、他のより微妙なものではなく、適切にクラッシュします。未定義の動作[すぐ下のメモリ(下位アドレス)が使用できないことが保証されていないため、スタックから外れた場合に他の便利なものを上書きする可能性があり、バグのデバッグが非常に困難になります]。

スタックの深さをときどきチェックするコードを少し追加します(スタックの開始位置と終了位置がわかっているので、特定のスタック値が「範囲外」であるかどうかを確認するのは難しいことではありません。スタックの一番上とあなたが保護した「私たちは死んでいる」ゾーンの間のスペース」-クラッシュした車の場合に呼ばれる「クラッシャブルゾーン」]。スタック全体を認識可能なパターンであり、そのどれだけが「手つかず」であるかを確認します。

于 2013-03-03T23:24:28.187 に答える
2

通常、x86では、次の条件が満たされている限り、既存のスタックを問題なく使用できます。

  • あなたはそれをオーバーフローしません
  • コードで始まるものを超えてスタックポインタレジスタ(popまたはadd esp, positive_value/ sub esp, negative_value)をインクリメントしないでください(そうすると、割り込みまたは非同期コールバック(シグナル)またはスタックを使用するその他のアクティビティによってその内容が破棄されます)
  • CPU例外を発生させません(発生した場合、例外処理コードは、例外を処理できる最も近いポイントにスタックを巻き戻すことができない場合があります)

esp同じことが、一時スタックに別のメモリブロックを使用し、その終わりを指す場合にも当てはまります。

例外処理とスタックの巻き戻しの問題は、コンパイルされたCおよびC ++コードにeip、それぞれの例外ハンドラーへのリンクを持つ範囲などの例外処理関連のデータ構造が含まれているという事実に関係しています(これにより、最も近い例外ハンドラーがどこにあるかがわかります)はすべてのコード用です)、呼び出し元の関数の識別に関連する情報(つまり、リターンアドレスがスタック上にある場所など)もあるので、例外をバブルアップできます。生のマシンコードをこの「フレームワーク」にプラグインするだけでは、これらの例外処理データ構造を適切に拡張してカバーすることはできません。問題が発生すると、非常に問題が発生する可能性があります(プロセス全体がクラッシュするか、生成されたコードの周りに例外ハンドラーがあるにもかかわらず、破損します)。

だから、ええ、あなたが注意すれば、あなたはスタックで遊ぶことができます。

于 2013-03-03T23:52:30.713 に答える
2

You can use any region you like for the processor's stack (modulo the memory protections).

Essentially, you simply load the ESP register ("MOV ESP, ...") with a pointer to the new area, however you managed to allocate it.

You have to have enough for your program, and whatever it might call (e.g., a Windows OS API), and whatever funny behaviours the OS has. You might be able to figure out how much space your code needs; a good compiler can easily do that. Figuring how much is needed by Windows is harder; you can always allocate "way too much" which is what Windows programs tend to do.

If you decide to manage this space tightly, you'll probably have to switch stacks to call Windows functions. That won't be enough; you'll likely get burned by various Windows surprises. I describe one of them here Windows: avoid pushing full x86 context on stack. I have mediocre solutions, but not good solutions for this.

于 2013-03-04T00:14:26.133 に答える