16

私は次のような簡単なコードを持っています:

#include<stdio.h>

int glob;

int main(void)
{
   int a;
   printf("&a is : %p \n", &a);
   printf("glob is : %p \n", &glob);
   return 0;
}

上記のプログラムの出力は次のとおりです。

&a is : 0x7fff70de91ec
glob is : 0x6008f4

2 回目の実行:

&a is : 0x7fff38c4c7ac
glob is : 0x6008f4

仮想アドレスと物理アドレスについて勉強しています。次の質問があります。

  1. 変数「a」の出力アドレス(物理/仮想)はどれ?
  2. 仮想の場合、同じプログラムの実行ごとにどのように変化しますか? 私が理解しているように、コンパイラはコンパイル時に変数に仮想アドレスを提供しますか?
  3. プログラムの実行ごとにグローバル変数のアドレスが一定なのはなぜですか?

Linux でこのプログラムを実行した場合: 2.6.18-308.el5 x86_64 GNU/Linux

使用してコンパイル: gcc バージョン 4.1.2 20080704 (Red Hat 4.1.2-52)

4

4 に答える 4

16

どちらのアドレスも仮想です。

最新のシステムは、スタックのランダム化を使用して、いわゆるスタック破壊攻撃を防ぎます。これが、ローカル変数が実行ごとにその場所を変更できる理由です。ただし、グローバル変数は実行可能ファイルに格納され、毎回同じオフセットでロードされます。

于 2013-04-05T11:56:15.787 に答える
7

プログラムで見られるアドレスは常に仮想であり、OP によって記述された動作は、バッファ オーバーフロー攻撃を回避するための Linux の対策です。

試してみると、無効にすることができます

sysctl -w kernel.randomize_va_space=0

次に、プログラムを再度実行して監視します。

グローバルなものは、ハック的な観点から害を及ぼすことのない別のメモリ空間にあります。これは、毎回ランダム化されていないためです。

于 2013-04-05T12:01:08.573 に答える
3

プログラムは常に仮想アドレスのみを認識します。

実アドレスは、カーネル モードの仮想メモリ マネージャーでのみ使用できます。

グローバルは、データ セグメントで作成されるため、同じアドレスを持ちます (その前に他の変数を配置するまで)。

ローカル変数は常にスタック上に作成されます。

于 2013-04-05T11:56:47.020 に答える
2

プログラムから見えるアドレスはすべて仮想アドレスです。ただし、ローカル変数はスタックに配置され、データ セグメントと呼ばれる特別な領域でグローバルに配置されます。変数の相対位置はコンパイル時に決定されますが、スタックは実行ごとに異なる場合があります。

于 2013-04-05T12:52:55.097 に答える