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

第二次运行:

&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

您的程序将始终只看到虚拟地址。

实地址仅对内核模式下的虚拟内存管理器可用。

Globals 具有相同的地址(直到您在其前面放置其他变量),因为它是在数据段中创建的。

局部变量总是在堆栈上创建。

于 2013-04-05T11:56:47.020 回答
2

程序看到的所有地址都是虚拟的。然而,局部变量在称为数据段的特殊区域上进行堆栈和全局。虽然变量的相对位置是在编译时决定的,但每次运行时堆栈可能会有所不同。

于 2013-04-05T12:52:55.097 回答