2013-04-05 128 views
15

我有简单的代码如下:上述程序的哪个地址是printf()在c中用%p格式打印的地址?

#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(红帽4.1.2-52)

+2

你的程序调用**未定义的行为**。一个'%p'必须被赋予一个ptr-void,所以你必须在这两个printf中投射到'(void *)'。 – Jens 2013-04-05 12:09:01

+0

@Jens这个参数不会被隐式转换为void *'吗? – 2013-04-05 12:54:38

+3

@VilhelmGray隐式转换在需要类型时发生,但在可变参数函数中没有类型。 – effeffe 2013-04-05 13:45:29

回答

6

地址总是虚拟和由OP描述的行为是Linux应对措施,以避免buffer overflow attacks

只是试试,你可以用

sysctl -w kernel.randomize_va_space=0 

禁用它,然后再次运行程序和观看。

全局之一是在存储器的另一空间不能在一个角度的hackish逐点是有害的。那是因为它每次都没有随机化。

15

这两个地址都是虚拟的。

现代系统使用堆栈随机化,以防止所谓的堆栈溢出攻击,这就是为什么局部变量可以改变每次运行它的位置。然而,全局变量存储在可执行文件中,并且每次都以相同的偏移量加载。

+7

值得注意的是,某些其他操作系统和更安全的Linux发行版都有PIE(独立于位置的可执行文件),并且全局变量的地址也会改变。 – Art 2013-04-05 12:00:06

+0

@Joachim,是的,我同意局部变量存储在堆栈中,但为什么说编译器在编译时给变量指定了一个特定的地址? – BSalunke 2013-04-05 12:01:07

+0

@BSalunke当函数被调用时,局部变量被放置在来自堆栈指针的特定_offset_处。所以,虽然编译器没有给它一个固定的地址,但变量仍然有编译器给出的地址。 – 2013-04-05 12:06:06

3

您的程序将总是只看虚拟地址。

实际地址仅适用于内核模式下的虚拟内存管理器。

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

局部变量总是在堆栈上创建。在一个程序中看到

+1

局部变量也可以是静态的...... :) – unwind 2013-04-05 12:07:29

+0

@unwind:是的,你是正确的。我只是描述OP提供的代码。 – rkosegi 2013-04-05 12:08:17

2

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