1

私が次のことをした場合:

int i, *p = &i;
int **p2p = &p;

(スタック上の) i のアドレスを取得して p に渡し、次に (スタック上の) p のアドレスを取得して p2p に渡します。

私の質問は、の値がiメモリアドレスpなどに保持されていることはわかっていますが、オペレーティングシステムはそのアドレスがどこにあるかをどのように知るのでしょうか? それらのアドレスはスタックに整理されていると思います。宣言された各変数 (識別子) は、スタックの現在の位置からのオフセットのように扱われますか? グローバル変数についてはどうですか。オペレーティング システムやコンパイラは、実行中にこれらのアドレス指定をどのように処理しますか? OS とコンパイラは、メモリを使用せずに各識別子のアドレスを「記憶」するためにどのように機能しますか? すべての変数が順番どおりにスタックに入力 (プッシュ) され、それらの名前がオフセットに置き換えられていますか? もしそうなら、宣言の順序を変更できる条件付きコードはどうですか?

4

5 に答える 5

2

私はアセンブリ言語のプログラマーだったので、使用していた CPU の答えはわかっています。要点は、CPU のレジスタの 1 つが、SP と呼ばれるスタック ポインタとして使用されることです (またはesp、最近の x86 CPU では)。コンパイラは、SP に関連する変数 (この場合は i、p、および p2p) を参照します。つまり、コンパイラは各変数の SP からのオフセットを決定し、それに応じてマシン コードを生成します。

于 2013-04-13T13:31:35.003 に答える
1

オペレーティング システムは、プログラムが使用するアドレスを気にしません。アドレス空間内のバッファを使用する必要があるシステム コールが発行されるたびに、プログラムはバッファのアドレスを提供します。

コンパイラは、関数ごとにスタック フレームを提示します。

push ebp
mov ebp,esp

次に、任意の関数パラメーターまたはローカル変数を、そのスタック フレームのベース アドレスである EBP レジスターの値に対して相対的にアドレス指定できます。これは、コンパイラに固有の参照テーブルを介してコンパイラによって処理されます。

関数を終了すると、コンパイラはスタック フレームを破棄します。

mov esp,ebp
pop ebp

低レベルでは、CPU はリテラルの BYTE/WORD/DWORD/etc の値とアドレス (同じですが、使い方が異なります) でのみ動作します。

必要なメモリアドレスは、コンパイル時にコンパイラが既知のアドレスに置き換える名前付きバッファ (グローバル変数など) に格納されるか、CPU のレジスタに格納されます (非常に単純化されていますが、それでも当てはまります)。

OS 開発に携わっているので、必要に応じて、私が知っていることをより深く説明したいと思いますが、それは SOF の範囲外であるため、興味がある場合は別のチャネルを見つける必要があります.

于 2013-04-13T13:33:11.667 に答える
0

@確率的に説明したように:

コンパイラは、SP に関連する変数 (この場合は i、p、および p2p) を参照します。つまり、コンパイラは各変数の SP からのオフセットを決定し、それに応じてマシン コードを生成します。

多分この例はあなたにそれをさらに説明します。amd64 上にあるため、ポインタのサイズは 8 バイトです。ご覧のとおり、変数はなく、レジスタからのオフセットのみです。

#include <cstdlib>
#include <stdio.h>
using namespace std;

/*
 * 
 */
int main(int argc, char** argv) {

    int i, *p = &i;
    int **p2p = &p;
    printf("address 0f i: %p",p);//0x7fff4d24ae8c
    return 0;
}

分解:

!int main(int argc, char** argv) {
main(int, char**)+0: push   %rbp
main(int, char**)+1: mov    %rsp,%rbp
main(int, char**)+4: sub    $0x30,%rsp
main(int, char**)+8: mov    %edi,-0x24(%rbp)
main(int, char**)+11: mov    %rsi,-0x30(%rbp)
!
!    int i, *p = &i;
main(int, char**)+15: lea    -0x4(%rbp),%rax
main(int, char**)+19: mov    %rax,-0x10(%rbp)  //8(pointer)+4(int)=12=0x10-0x4
!    int **p2p = &p;
main(int, char**)+23: lea    -0x10(%rbp),%rax
main(int, char**)+27: mov    %rax,-0x18(%rbp) //8(pointer)
!    printf("address 0f i: %p",p);//0x7fff4d24ae8c
main(int, char**)+31: mov    -0x10(%rbp),%rax //this is pointer
main(int, char**)+35: mov    %rax,%rsi //get address of variable, value would be %esi
main(int, char**)+38: mov    $0x4006fc,%edi
main(int, char**)+43: mov    $0x0,%eax
main(int, char**)+48: callq  0x4004c0 <printf@plt>
!    return 0;
main(int, char**)+53: mov    $0x0,%eax
!}
main(int, char**)()
main(int, char**)+58: leaveq 
main(int, char**)+59: retq 
于 2013-04-13T13:41:53.173 に答える