static int arr [10]メモリアドレスは常に060で終わる


17

私はこのようなACプログラムを持っています

main.c

#include <stdio.h>
#define SOME_VAR 10

static int heap[SOME_VAR];


int main(void) {
    printf("%p", heap);
    return 0;
}

コンパイルしたプログラムを数回実行すると、これが出力されます

0x58aa7c49060
0x56555644060
0x2f8d1f8e060
0x92f58280060
0x59551c53060
0xd474ed6e060
0x767c4561060
0xf515aeda060
0xbe62367e060

なぜそれが常に060で終わるのですか?そして、配列はヒープに格納されていますか?

編集:私はLinuxを使用していて、ASLRをオンにしています。gccを使用してプログラムをコンパイルしました


2
どのオペレーティングシステム?どのコンパイラー?
Andrew Henle

2
変数がヒープ内にありません。プログラムのアドレス空間のデータまたはbssセクションにあります。en.wikipedia.org/ wiki / Static_variableを参照してください。私の推測では、プログラムは常に特定の境界、たとえば0x1000で割り切れるメモリアドレスに配置され、変数はコンパイラによってプログラムのアドレス空間の固定オフセットに配置されます。
Bodo

回答:


15

ASLR(アドレススペースレイアウトのランダム化)により、アドレスが異なります。これを使用して、バイナリを仮想アドレス空間のさまざまな場所にマッピングできます。

変数heapは、その名前とは対照的に、ヒープではなくにありbssます。したがって、アドレス空間のオフセットは一定です。

ページは、多くのプラットフォームで4096バイト(16進数:0x1000)のページ単位でマッピングされます。これが、アドレスの最後の3桁の16進数が同じである理由です。

スタック変数で同じことを行った場合、スタックは他の場所にマップされるだけでなく、起動時にランダムなオフセットも受け取るため、一部のプラットフォーム(つまり、最近のカーネルのLinux)では、アドレスの最後の桁が異なる場合さえあります。


ASLRは、覚えているようにロードのベースをランダム化します。セクションアドレスはそのアドレスに基づいています。
アフシン

私は、Axel-Thobias Schreinerによるオブジェクト指向のANSI-Cプログラミングに関する本を使用しています。この本は1993年のようなもので書かれています。当時のメモリレイアウトが異なっていたかどうかをご存知ですか。そうでない場合、なぜheapヒープにないときに変数に名前を付けたのでしょうか?
linuxlmao

4096は何らかの方法で060に変換されますか、それとも0x1000は060に変換されますか?それ以外の場合、エンディングの理由が何を意味するのか理解できませんか?配列のサイズが、たとえば10進数から16進数で060に変換されるものである可能性があると考えました。たとえば、10進数
linuxlmao

2
@linuxlmaoオフセットはたとえば14060なので、ページサイズ(0x1000)の倍数を追加しても、最後の3桁が残り060ます。
Ctx

4

Windowsを使用している場合、理由はPE構造です。

あなたのheap変数を中に格納され.dataたファイルのセクションとそのアドレスは、このセクションの先頭に基づいて計算されます。各セクションは個別にアドレスにロードされますが、その開始アドレスはページサイズの倍数です。他に変数がないため、そのアドレスはおそらく.dataセクションの先頭であり、そのアドレスはチャンクサイズの倍数になります。

たとえば、これは、コンパイルされたWindowsバージョンのコードの表です セクション.textセクションは、コンパイルされたコードであり.dataheap変数が含まれています。PEがメモリに読み込まれると、セクションは異なるアドレスに読み込まれVirtualAlloc()、ページサイズの倍数で返されます。ただし、各変数のアドレスは、ページサイズになっているセクションの開始を基準にしています。したがって、常に下の桁に固定数が表示されます。heapセクションの先頭からの相対アドレスはコンパイラ、コンパイルオプションなどに基づいているため、同じコードから異なる番号が表示されますが、コンパイラは異なりますが、出力される内容は常に修正されます。

コードをコンパイルすると、セクションの開始後heap0x8B0バイトに配置されていることに気付きました.data。したがって、このコードを実行するたびに、私のアドレスはで終わり0x8B0ます。


私は、Axel-Thobias Schreinerによるオブジェクト指向のANSI-Cプログラミングに関する本を使用しています。この本は1993年のようなもので書かれています。当時のメモリレイアウトが異なっていたかどうかご存知ですか。そうでない場合、なぜ彼は変数に名前を付けたのでしょうかheapヒープにないときににでしょうか?
linuxlmao

2
@linuxlmao違っていたかもしれません。1993年、Windowsは16ビットのオペレーティングシステムであり、メモリのセグメンテーションとあらゆる種類の混乱を招きました。現在の32ビットのフラットメモリアーキテクチャではありませんでした。しかし、これらのタイプのことは、メモリ内のプログラムバイナリのレイアウトについての一般的な質問に答えることが役に立たない理由です。C言語標準があなたに一般的に保証するものを理解し、そしてそれがあなたが知る必要があるすべてです。特定の問題をデバッグする場合は、実際のレイアウトのみを考慮してから、デバッガーを使用してください
Cody Gray

いいえ、変数はmallocで割り当てられておらず、静的なストレージ期間があるため、古いシステムでもヒープに作成しないでください
phuclv

@Afshin上記のOPのコメントに対応しています
phuclv

@phuclv申し訳ありません、あなたは彼に言及されなかったので、私があなたに話していると思いました。:)
アフシン

4

heapおそらく、コンパイラーが最初の0x60バイトに他の何か(mainルーチンを開始するコードで使用されるデータなど)があるため、コンパイラーはたまたまデータセグメントのオフセット0x60バイトに配置しました。そのため、「060」が表示されます。それはたまたまそれがあった場所であり、それに大きな意味はありません。

アドレス空間レイアウトのランダム化は、プログラムメモリのさまざまな部分に使用されるベースアドレスを変更しますが、常に0x1000バイト単位で変更します(これにより、配置やその他の問題の発生を回避できるため)。したがって、アドレスは0x1000の倍数で変動しますが、最後の3桁は変化しません。

定義でstatic int heap[SOME_VAR];heap、静的ストレージ期間を定義します。一般的なCの実装では、ヒープではなく、一般的なデータセクションに格納します。「ヒープ」は、動的割り当てに使用されるメモリの誤称です。(malloc実装はヒープに限らず、さまざまなデータ構造とアルゴリズムを使用する可能性があるため、これは誤称です。1つの実装で複数のメソッドを使用することさえあります。)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.