ARM アーキテクチャ/アセンブリの学習を終えたところです。SP レジスタがデータを格納する次のメモリ位置のアドレスを保持している場合、ヒープのアドレスを保持しているのは何ですか? たとえば、C++ でヒープ上にオブジェクトを宣言すると (例: MyObj example = new MyObj();
)、アセンブリはどのように見えるでしょうexample
か。
4 に答える
SP レジスタは通常、スタック内の現在の位置を追跡するために使用されます。これは、常にスタックを指す必要があることを意味します。
ヒープについても同じことは言えません。変数にアクセスする必要がある場合、その変数のアドレスは、ポインターまたはアプリからの他のメモリ参照に格納されます。そのアドレスが必要なときは、レジスタを使用して参照を行うことができます。しかし、どのレジスターの詳細は、コンパイラーに依存するだけでなく、コードが同じコンパイラーから最適化された後にどのレジスターが使用可能になるかにも依存する可能性があります。
このコンテキストでのスタックは、OS/EABI によって提供される下位レベルの構造です。そのため、そのための従来のレジスタがあります。ただし、ヒープは OS によって提供される上位レベルの構造です。そのため、それを管理して遊ぶことは、アプリと OS との契約に依存します。アセンブリ用語では、レジスタを介していくつかのアドレスを逆参照してそのヒープを使用します。
プロセッサ ハードウェアはコードを実行せずに SP を直接変更しなければならない場合があるため (割り込みまたは例外)、プロセッサにはスタック ポインタ用の特別なレジスタが必要です。これはヒープには必要ないため、特別なレジスタを使用してヒープを指す必要はありません。実行時に、OS はコードの特定のチャンクがヒープ上のどこに格納できるかを決定し、任意のレジスタを使用してそのアドレスを保持できます。
ARM の EABI では、R13 (SP) は完全な降順スタックで最後にプッシュされたデータを指します。ただし、常にそれを指している必要はありません。そのようなコードは合法である可能性があります。
r0 が、プログラムによってアクセス可能な有効なメモリ位置を指していると考えてください。
stmfd r0!, {r1-r12, sp, lr}
ldr r1, [r0]
mov r2, lr
sub lr, sp, #4
str sp, [r4]
add sp, lr, #4
ldmfd r0!, {r1-r12, sp, pc}
もちろん意味はありませんが、sp、lr、および他のすべての呼び出し先の保存されたレジスタを安全にリロードできる場合は、呼び出し元に戻る前にそれらの値を復元することを忘れずに、必要なだけそれらをスクラッチできるということだけがポイントです。 .
別のポイント、スタックとヒープは必ずしも同じではない場合があります。ヒープは malloc/free 型構造のより高いレベルの抽象であり、スタックは 4 つのレジスタだけでは不十分な場合、または関数の引数、データ構造、および想像できることはすべてですが、領域をポインターに割り当てて、完了後に解放するだけでなく、すべてのデータを自分で追跡する必要があるため、スタックは管理が少し難しくなります。
通常、プログラムと環境に応じて、いくつかの非スクラッチレジスタを故意に破損してそれを回避するなど、最適化のためにさまざまなハックやものを使用できますが、呼び出し元関数でそれを管理する必要があり、レジスタを認識する必要がありますそれは後続の関数呼び出しでスクラッチされるため、EABI は別のプログラムに制御を移すか引き継ぐ場合にのみ意味をなす可能性があります。CPU で自分の時間に好きなことを行うことができます。その場に入った。