91

私は現在、スタックがどのように機能するかを理解しようとしているので、アセンブリ言語を独学することにしました。この本を使用しています:

http://savannah.nongnu.org/projects/pgubook/

私はGasを使用しており、 Linux Mintで開発を行っています。

私は何かに少し混乱しています:

私の知る限り、スタックは単なるデータ構造です。したがって、アセンブリでコーディングしている場合は、自分でスタックを実装する必要があると思いました。ただし、次のようなコマンドがあるため、これは当てはまらないようです

pushl
popl

では、 x86アーキテクチャのアセンブリでコーディングし、Gas 構文を使用する場合: スタックは、既に実装されている単なるデータ構造なのでしょうか? それとも、実際にハードウェア レベルで実装されているのでしょうか。それとも別のものですか?また、他のチップ セットのほとんどのアセンブリ言語には、スタックが既に実装されていますか?

これが少しばかげた質問であることはわかっていますが、実際にはかなり混乱しています。

4

17 に答える 17

4

コンセプト

まず、自分が発明者であるかのように全体を考えてみてください。このような:

最初に配列と、それが低レベルでどのように実装されているかを考えてみてください --> 基本的には、連続したメモリ位置 (互いに隣り合っているメモリ位置) のセットです。頭の中にその精神的なイメージができたので、配列のデータを削除または追加するときに、それらのメモリの場所にアクセスして自由に削除できるという事実を考えてみてください。同じ配列について考えてみますが、任意の場所を削除する代わりに、配列内のデータを削除または追加するときに最後の場所のみを削除することにします。その配列のデータをそのように操作するというあなたの新しいアイデアは、後入れ先出しを意味する LIFO と呼ばれます。配列から何かを削除するたびに並べ替えアルゴリズムを使用しなくても、その配列の内容を簡単に追跡できるため、あなたのアイデアは非常に優れています。また、配列内の最後のオブジェクトのアドレスが何であるかを常に知るには、それを追跡するために Cpu 内の 1 つのレジスタを専用にします。さて、レジスターがそれを追跡する方法は、配列から何かを削除または追加するたびに、配列から削除または追加したオブジェクトの量だけレジスターのアドレスの値をデクリメントまたはインクリメントすることです (それらが占有したアドレス空間の量)。また、そのレジスタをデクリメントまたはインクリメントする量がオブジェクトごとに 1 つの量 (4 つのメモリ ロケーション、つまり 4 バイトなど) に固定されていることを確認して、追跡を容易にし、それを可能にすることも必要です。ループは反復ごとに固定のインクリメントを使用するため、そのレジスタをいくつかのループ構成で使用します (例: ループを使用して配列をループするには、反復ごとにレジスタを 4 ずつインクリメントするループを構築します。これは、配列に異なるサイズのオブジェクトが含まれている場合は不可能です)。最後に、この新しいデータ構造を「スタック」と呼ぶことを選択します。これは、レストランのプレートのスタックを思い起こさせ、そのスタックの一番上にあるプレートを常に削除または追加する場合に使用します。

実装

ご覧のとおり、スタックは、操作方法を決定した連続したメモリ位置の配列にすぎません。そのため、スタックを制御するために特別な命令やレジスタを使用する必要さえないことがわかります。次のように、基本的な mov、add、および sub 命令を使用して、ESP と EBP の代わりに汎用レジスタを使用して、自分で実装できます。

移動edx、0FFFFFFFFh

; -->これはコードとデータから最も離れたスタックの開始アドレスになります。また、先ほど説明したスタック内の最後のオブジェクトを追跡するレジスタとしても機能します。これを「スタック ポインター」と呼ぶので、ESP が通常使用されるレジスタ EDX を選択します。

サブEDX、4

mov [edx]、dword ptr [someVar]

; -->これらの 2 つの命令は、スタック ポインターを 4 つのメモリ位置だけデクリメントし、[someVar] メモリ位置から始まる 4 バイトを EDX が現在ポイントしているメモリ位置にコピーします。PUSH 命令が ESP をデクリメントするのと同じように、ここでのみ行いました。手動でEDXを使用しました。したがって、PUSH 命令は基本的に、ESP で実際にこれを行う短いオペコードです。

mov eax、dword ptr [edx]

edxを追加、4

; -->ここでは反対のことを行います。まず、EDX が現在ポイントしているメモリ位置から始まる 4 バイトをレジスタ EAX にコピーします (ここで任意に選択し、必要な場所にコピーすることができました)。次に、スタック ポインター EDX を 4 つのメモリ位置だけインクリメントします。これが POP 命令の機能です。

これで、命令 PUSH と POP およびレジスタ ESP と EBP が、上記の「スタック」データ構造の概念を読み書きしやすくするために Intel によって追加されたばかりであることがわかります。PUSH ans POP 命令とスタック操作用の専用レジスタを持たない RISC (Reduced Instruction Set) Cpu がまだいくつかあり、それらの Cpu のアセンブリ プログラムを作成している間、同じように自分でスタックを実装する必要があります。私はあなたに見せました。

于 2016-02-05T22:18:13.870 に答える
3

あなたが探している主な答えはすでに示唆されていると思います。

x86 コンピューターの起動時に、スタックがセットアップされていません。プログラマーは、ブート時に明示的に設定する必要があります。ただし、すでにオペレーティング システムを使用している場合は、この問題は解決されています。以下は、単純なブートストラップ プログラムのコード サンプルです。

最初にデータ レジスタとスタック セグメント レジスタが設定され、次にスタック ポインタがそれを超えた 0x4000 に設定されます。


    movw    $BOOT_SEGMENT, %ax
    movw    %ax, %ds
    movw    %ax, %ss
    movw    $0x4000, %ax
    movw    %ax, %sp

このコードの後、スタックを使用できます。さまざまな方法で実行できると確信していますが、これはアイデアを説明するものだと思います。

于 2009-02-17T13:57:36.230 に答える
1

コールスタックは、x86命令セットとオペレーティングシステムによって実装されます。

プッシュやポップなどの命令は、スタックがスレッドごとに大きくなるにつれてオペレーティングシステムがメモリの割り当てを処理しながら、スタックポインタを調整します。

x86スタックが上位アドレスから下位アドレスに「成長」するという事実により、このアーキテクチャはバッファオーバーフロー攻撃の影響を受けやすくなります。

于 2009-02-17T13:43:31.457 に答える
1

特に Gas アセンブラは見たことがありませんが、一般的にスタックは、スタックの最上位が存在するメモリ内の場所への参照を維持することによって「実装」されます。メモリ位置はレジスタに格納され、アーキテクチャごとに異なる名前が付けられていますが、スタック ポインタ レジスタと考えることができます。

pop コマンドと push コマンドは、マイクロ命令に基づいて構築することにより、ほとんどのアーキテクチャに実装されています。ただし、一部の「教育アーキテクチャ」では、自分で実装する必要があります。機能的には、プッシュは次のように実装されます。

   load the address in the stack pointer register to a gen. purpose register x
   store data y at the location x
   increment stack pointer register by size of y

また、一部のアーキテクチャでは、最後に使用されたメモリ アドレスがスタック ポインタとして保存されます。次の使用可能なアドレスを保存するものもあります。

于 2009-02-17T13:26:10.203 に答える
0

スタックは「単なる」データ構造であるというのは正しいことです。ただし、ここでは、特別な目的で使用されるハードウェア実装スタック、つまり「スタック」を指します。

多くの人が、ハードウェアで実装されたスタックと(ソフトウェア)スタックのデータ構造についてコメントしています。3つの主要なスタック構造タイプがあることを付け加えたいと思います-

  1. コールスタック-これはあなたが求めているものです!関数パラメータや差出人住所などを格納します。その本の第4章(4ページ目、つまり53ページ)の関数を読んでください。良い説明があります。
  2. 特別なことをするためにプログラムで使用する可能性のある汎用スタック...
  3. 汎用ハードウェアスタック
    これについてはよくわかりませんが、一部のアーキテクチャで利用可能な汎用ハードウェア実装スタックがあることをどこかで読んだことを覚えています。これが正しいかどうか誰かが知っているなら、コメントしてください。

最初に知っておくべきことは、あなたがプログラミングしているアーキテクチャであり、それは本が説明しています(私はちょうどそれを調べました--link)。物事を本当に理解するために、x86のメモリ、アドレス指定、レジスタ、およびアーキテクチャについて学ぶことをお勧めします(本から学んでいることだと思います)。

于 2009-02-17T13:42:04.910 に答える
0

LIFO方式でローカル状態を保存および復元する必要がある関数の呼び出し(一般化されたコルーチンアプローチとは対照的に)は、アセンブリ言語とCPUアーキテクチャが基本的にこの機能を組み込むという非常に一般的なニーズであることがわかります。同じおそらく、スレッド化、メモリ保護、セキュリティレベルなどの概念について言えます。理論的には、独自のスタック、呼び出し規則などを実装できますが、一部のopcodeとほとんどの既存のランタイムは、このネイティブの「スタック」の概念に依存していると思います。 。

于 2011-10-21T04:59:26.227 に答える
0

stack記憶の一部です。forinputoutputof を使用しfunctionsます。また、関数の戻り値を記憶するために使用します。

espregister はスタックアドレスを覚えています。

stackespハードウェアによって実装されます。また、自分で実装することもできます。プログラムが非常に遅くなります。

例:

いいえ// esp= 0012ffc4

プッシュ 0 // esp= 0012ffc0 ,Dword[0012ffc0]=00000000

call proc01 // esp= 0012ffbc ,Dword[0012ffbc] = eip, eip= adrr[proc01]

pop eax// eax= Dword[ esp], esp= esp+ 4

于 2015-07-21T20:47:57.870 に答える
0

スタックとは?スタックはデータ構造の一種で、コンピュータに情報を格納する手段です。新しいオブジェクトがスタックに入力されると、以前に入力されたすべてのオブジェクトの上に配置されます。つまり、スタック データ構造は、カード、紙、クレジット カードの郵便物、または考えられるその他の現実世界のオブジェクトのスタックのようなものです。スタックからオブジェクトを削除すると、一番上のオブジェクトが最初に削除されます。この方法は、LIFO (後入れ先出し) と呼ばれます。

「スタック」という用語は、ネットワーク プロトコル スタックの略語である場合もあります。ネットワークでは、コンピューター間の接続は、一連の小さな接続を通じて行われます。これらの接続、またはレイヤーは、同じ方法で構築および破棄されるという点で、スタック データ構造のように機能します。

于 2012-12-10T09:16:35.430 に答える
0

関数の観点からスタックがどのように機能するかを調べていたところ、このブログが素晴らしく、スタックの概念を最初から説明し、スタックがスタックに値を格納する方法を説明していました。

今あなたの答えに。Pythonで説明しますが、どの言語でもスタックがどのように機能するかをよく理解できます.

ここに画像の説明を入力

そのプログラム:

def hello(x):
    if x==1:
        return "op"
    else:
        u=1
        e=12
        s=hello(x-1)
        e+=1
        print(s)
        print(x)
        u+=1
    return e

hello(3)

ここに画像の説明を入力

ここに画像の説明を入力

出典:クリプトロイ

ブログで取り上げるトピックの一部:

How Function work ?
Calling a Function
 Functions In a Stack
 What is Return Address
 Stack
Stack Frame
Call Stack
Frame Pointer (FP) or Base Pointer (BP)
Stack Pointer (SP)
Allocation stack and deallocation of stack
StackoverFlow
What is Heap?

しかし、それはPython言語で説明されているので、必要に応じて見ることができます.

于 2016-10-18T09:57:57.503 に答える