2

C プログラムのメモリ レイアウトについて質問があります。

テキスト セグメント

これが私の最初の質問です:

テキスト セグメント (またはコード セグメント) を検索すると、「テキスト セグメントには実行可能な命令が含まれています」と表示されました。関数の実行可能な命令とは何ですか? いくつかの異なる例を挙げていただけますか?

また、「テキスト セグメントは共有可能であるため、テキスト エディタや C コンパイラなど、頻繁に実行されるプログラムのメモリ内にコピーを 1 つだけ配置すればよい」という記事も読みましたが、C プログラムと「テキストエディタ」。

この声明から何を理解すべきですか?

初期化されたデータ セグメント

「初期化されたデータセグメント」にはグローバル変数と静的変数が含まれていると言われていますconst char* string = "hello world"が、文字列リテラル「hello world」を初期化された読み取り専用領域に格納し、文字ポインター変数文字列を初期化された読み取りに格納することも読みました-エリアを書き込みます。char* string読み取り専用領域または読み書き可能領域が格納されていますか? 両方ともここに書かれているので、私は少し混乱しています。

スタック

私が理解していることから、スタックにはローカル変数が含まれています。これは正しいですか?

4

4 に答える 4

3

テキスト セグメントには、プログラムの実際のコード、つまりコンパイラによって生成されたマシン コードが含まれます。最後のステートメントの考え方は、C プログラムと、たとえばテキスト エディターはまったく同じものであるということです。メモリから実行される機械語命令にすぎません。

たとえば、次のコードと、x86 アセンブリを思い出せないために今思いついた架空のアーキテクチャを取り上げます。

while(i != 10)
{
    x -= 5;
    i++;
}

これは、次の指示に変換されます

LOOP_START:
CMP eax, 10    # EAX contains i. Is it 10?
JZ  LOOP_END   # If it's 10, exit the loop
SUB ebx, 5     # Otherwise, subtract 5 from EBX (x)
ADD eax, 1     # And add 1 to i
JMP LOOP_START # And then go to the top of the loop.

LOOP_END:
# Do something else

これらは、プロセッサが理解できる低レベルの操作です。これらはバイナリ マシン コードに変換され、メモリに格納されます。保存されている実際のデータは、たとえば、5、2、7、6、4、9 である可能性があります。たとえば、私が考えた操作とオペコードの間のマッピングが与えられます。これが実際にどのように行われるかについて詳しくは、アセンブラーとマシン コードの関係を調べてください。

-- Ninja-edit - 上記の RBK のコメントを参考にすると、objdump または同様の逆アセンブラーを使用して、アプリケーションを構成する実際の命令を表示できます。Visual Studio のどこかにあるか、Windows で OllyDbg または IDA を使用できます。

プログラムの実際の命令は読み取り専用である必要があるため、テキスト セグメントは常に同じであるため、プログラムを複数回実行するために複製する必要はありません。

データセグメントに関する質問については、初期化子がないため、char* string実際にはセグメントに格納されます。.bssこれは、プログラムが実行される前に (crt0 または同等のものによって) クリアされるメモリ領域です。セグメントは.bss読み書き可能です。

はい、スタック セグメントにはローカル変数が含まれています。実際には、「スタック フレーム」と呼ばれるものが格納されます。これらの 1 つは、呼び出す関数ごとに作成され、互いに積み重ねられます。あなたが言ったように、ローカル変数のようなものと、関数が呼び出されたアドレスのような他の有用なビットと、関数が終了したときに以前の状態を復元できるようにするための他の有用なデータが含まれています。スタック フレームに実際に含まれているものについては、アーキテクチャの ABI (Application Binary Interface) を詳しく調べる必要があります。

于 2013-05-29T13:45:12.043 に答える
1

テキスト セグメントは「コード」とも呼ばれることがよくあります (「テキスト」は Unix/Linux の名前である傾向があり、他の OS では必ずしもその名前を使用するとは限りません)。

また、C コンパイラを実行する 2 つのプロセスを実行する場合、または 2 つの異なるウィンドウでテキスト エディタを開く場合、両方が同じ「テキスト」セクションを共有するという意味で共有可能です。コードの実行 (自己変更コードはテキスト セグメントでは許可されていません)。

初期化された文字列値は、コンパイラに応じて「ro-data」または「text」に格納されます。はい、書き込み可能ではありません。

がグローバル変数の場合string、最終的に「初期化されたデータ」になり、「hello world」メッセージのアドレスが の値に保持されますstring。このconst部分は、ポインターが指す内容が一定であるという事実に言及しているためstring = "foo bar";、コードの後半でポインターを実際に変更できます。

実際、スタックはローカル変数に使用され、通常はコール スタック (現在の関数の終了後にコードが戻る場所) に使用されます。

于 2013-05-29T13:53:43.227 に答える
1

ただし、プログラムのメモリ内イメージの実際のレイアウトは、オペレーティング システムに完全に任されており、多くの場合、プログラム自体にも任されています。しかし、概念的には、実行中のプログラムに対して 2 つのメモリ セグメントを考えることができます [1]。

  1. テキストまたはコード セグメント - コンパイルされたプログラム コードが含まれます。
  2. データ セグメント - 初期化されたデータと初期化されていないデータ (グローバル、静的、およびローカル) が含まれます。

    2.1 初期化されたデータ セグメント
    2.2 初期化されていないデータ セグメント2.3
    スタック セグメント
    2.4 ヒープ セグメント

    初期化されたデータ セグメントには、事前に初期化されたすべてのグローバル、静的、定数、および外部変数 (extern キーワードで宣言) が格納されます。

    初期化されていないデータ セグメントまたは .bss セグメントには、初期化されていないすべてのグローバル、静的、および外部変数 (extern キーワードで宣言) が格納されます。

    スタック セグメントは、すべてのローカル変数を格納するために使用され、関数呼び出しが終了した後に実行される命令の戻りアドレスと共に引数を関数に渡すために使用されます。

    ヒープ セグメントは、動的に割り当てられた変数が格納される RAM の一部でもあります。

    最初の質問に来ます-関数ポインターを知っている場合、関数名が関数のアドレスを返すことを知っています(これはその関数のエントリポイントです)。これらの命令はアセンブリでコーディングされています。命令セットは、アーキテクチャごとに異なる場合があります。

テキストまたはコード セクションは共有可能 - 複数の実行中のプロセスが同じプログラムに属している場合、共通のコンパイル済みコードを個別にメモリにロードする必要はありません。たとえば、2 つの .doc ドキュメントを開いた場合、2 つのプロセスが存在しますが、両方のプロセスで共通のコードが使用されていることは間違いありません。

于 2013-12-27T12:23:37.140 に答える
0

スタックセグメントは、ローカル変数が格納される領域です。ローカル変数とは、C プログラムの main( ) を含むすべての関数で宣言されているすべての変数を意味します。

関数を呼び出すと、スタック フレームが作成され、関数が戻ると、スタック フレームはその特定の関数のすべてのローカル変数を含めて破棄されます。

スタック フレームには、戻りアドレス、渡された引数、ローカル変数、および呼び出された関数に必要なその他の情報などのデータが含まれています。

「スタック ポインター (SP)」は、スタック ポインターを次または前のアドレスに調整することで、プッシュ アンド ポップ操作ごとにスタックを追跡します。

実用的な情報については、このリンクを参照できます:- http://www.firmcodes.com/memory-layout-c-program-2/

于 2015-02-11T14:02:08.230 に答える