2011-10-02 189 views
1

后续行动如何查看GDB中自动变量的内存地址?

嗯我不知道我是否做正确的事情。 感谢所有帮助到目前为止

我以前的主题: Is this really the address

我想提出新的线程,因为这确实是一个单独的问题,核心问题。

请耐心等待,谢谢。


让我重申我的目标:

我希望能够寻找到每一个变量的内存地址(我们知道程序的入口地址,我们知道多少字节预留从阅读汇编代码)。假设我们给出了下面的源代码:

源代码

int main() 
{ 
    int a = 15; 
    int b; 
    int c; 
    b = c; 
    c = c+1; 
return 0; 
} 

我们应该能够找出变量a和c的地址,并在这些内存地址的值。

用gdb布局ASM我得到这个

│0x80483f4 <main()>  push %ebp            │ 
    │0x80483f5 <main()+1> mov %esp,%ebp           │ 
    │0x80483f7 <main()+3> sub $0x10,%esp          │ 
    │0x80483fa <main()+6> movl $0xf,-0x4(%ebp)         │ 
    │0x8048401 <main()+13> mov -0x8(%ebp),%eax         │ 
    │0x8048404 <main()+16> mov %eax,-0xc(%ebp)         │ 
    │0x8048407 <main()+19> addl $0x1,-0x8(%ebp)         │ 
    │0x804840b <main()+23> mov $0x0,%eax           │ 
    │0x8048410 <main()+28> leave             │ 
    │0x8048411 <main()+29> ret              │ 
    │0x8048412    nop  


// the statement int a = 15 is in the address 0x80483fa 
// I want to get the value 15 
x/w 0x80483fd  <== this will print 15 

不过,这并不因为我记得道理给我,变量应该是在EBP - 0X10吧?

// the starting address of the program is 0x80483f4 
// minus 0x10 we get 0x80483E4 
x/w 0x80483E4 <== will print a big number 

// Since b = c, I should be able to get that as I decrement, but no luck 

我不认为我知道我在做什么......?一方面,只要程序终止,自动变量就被销毁...

PS:我真的不能在调试时使用cout或printf或设置断点或监视器。

因此,打印$ ebp不会工作,因为没有活动的寄存器(记住程序终止 - 没有断点!)。所以像info locals,info寄存器这样的命令不可用。

我花了整整一天的时间试图弄清楚发生了什么事情。我非常感谢所有的帮助,我期待着获得更多。谢谢。

我该怎么办?我需要看看变量a,b,c的值。如何才能做到这一点?

非常感谢。


不是真的是功课,而是课堂讨论。

回答

1

这些变量没有一个特定的内存位置。他们是堆栈变量。因此,在程序终止后,您不能依赖它们在内存中,因为它们在创建它们的函数返回后会被视为超出范围,从而允许它们驻留的地址被重新用于存储其他内容。

假设你有它的来源是这样一个功能:

int foo(int x) { 
    int y = x; 
    if (y == 0) { 
     return 0; 
    } 
    return foo(x-1)+1; 
} 

如果调用foo(1),变量y将在两个不同的内存地址,每一个两个创建的两个堆栈帧的存在嵌套调用foofoo(1)foo(0))。如果您拨打foo(10),将会有11个实例y,每个实例都拥有不同的值并位于不同的内存地址。

如果您不使用断点,则所有意图和目的的变量都不存在。它们只有在程序运行时才分配存储空间,当前栈中包含它们驻留的函数的一个框架。你不能抓取他们postmortem(除了核心转储,这是一种形式的断点)。总结:如果在程序运行时不分析程序,可以通过中断调试程序或添加一些代码来打印/设置值,但不能检查堆栈变量。这些是堆栈变量。如果你必须让它们成为单实例,你应该通过将它们移到函数作用域之外来让它们堆分配全局变量。

+0

感谢您的意见。我的天啊。是。你非常正确。但是从解密代码中,我们知道程序的入口地址。我们不能只减少4个字节吗?如果我们仍在运行程序,它应该是第一个局部变量的地址,int a。请更正我的术语:当我们谈论$ ebp - 0x4时,我们仍然可以使用“地址”作为“位置”的别名,对吧? – CppLearner

+1

@JohnWong程序的入口地址是'main'函数的地址。这与'main'的堆栈帧的位置无关。 *代码*在内存中的一个地方,它使用的* data *在另一个地方(在这种情况下,在堆栈顶部)。事实并非如此,特定的函数总是将其堆栈帧放置在同一个点上;如果这是真的,则递归函数不可能存在。堆栈变量的实例不在构成函数的指令所在的位置附近。 – Borealid

+1

@JohnWong想象一下食谱书 - “main”是饼干的食谱。 'a','b'和'c'是成分。你不会把蛋糕存放在**食谱书中。每次想要制作食谱时,都可以将它们从冰箱中取出并放在柜台上的新空间中。入口点是食谱书中的书签。计数器空间是堆栈。完成烹饪和清理后,柜台是空的,食谱书中仍然有相同的东西 - 但没有鸡蛋! – Borealid