【问题标题】:How can I look into the memory addresses of automatic variables in GDB?如何查看 GDB 中自动变量的内存地址?
【发布时间】:2011-10-02 02:28:49
【问题描述】:

跟进

嗯,我不确定我是否做对了。 感谢迄今为止提供的所有帮助

我之前的帖子: Is this really the address

我正在制作新线程,因为这确实是一个单独的问题,也是核心问题。

请多多包涵,谢谢。


让我重申我的目标:

我希望能够查看每个变量的内存地址(我们知道程序的入口地址,并且我们知道在读取汇编代码时预留了多少字节)。假设我们得到以下源代码:

源代码

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

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

使用 gdb layout 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 或设置断点或观察器。

所以 print $ebp 将不起作用,因为没有活动寄存器(请记住程序终止 - 没有断点!)。因此,诸如 info locals、info registers 之类的命令不可用。

我一整天都在试图弄清楚发生了什么。我非常感谢所有的帮助,我期待得到更多帮助。谢谢。

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

非常感谢。


不是真正的家庭作业,而是课堂讨论。

【问题讨论】:

    标签: c++ gdb


    【解决方案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),将有十一个y 实例,每个实例都有不同的值并驻留在不同的内存地址。

    如果您不使用断点,则所有意图和用途的变量都不存在。它们仅在程序运行时分配存储,并且当前堆栈包含来自它们所在函数的帧。您无法在事后获取它们(除了核心转储,这实际上是一种断点形式)。

    总结:如果您在程序运行时不分析程序,无论是通过中断调试器还是通过添加一些将打印/保留值的代码,您都无法检查堆栈变量。这些是堆栈变量。如果你必须让它们成为单实例,你应该通过将它们移到函数范围之外来使它们成为堆分配的全局变量。

    【讨论】:

    • 感谢您的输入。我的天啊。是的。你说得很对。但是通过反汇编代码,我们知道了程序的入口地址。我们不能只减少 4 个字节吗?如果我们仍在运行程序,它应该是第一个局部变量 int a 的地址。还请更正我的术语:当我们谈论 $ebp - 0x4 时,我们仍然可以使用“地址”作为“位置”的别名,对吧?
    • @JohnWong 程序的入口地址是main函数的地址。这与main 的堆栈帧所在的位置无关。 code 位于内存中的一个位置,而它使用的 data 位于另一个位置(在本例中,位于堆栈顶部)。特定函数并非总是将其堆栈帧放在同一位置。如果这是真的,递归函数就不可能存在。堆栈变量的实例不在构成函数的指令所在的位置附近。
    • @JohnWong 想象一本食谱书——main 是饼干的食谱。 abc 是成分。您不会将用于饼干的鸡蛋存放在食谱书中。每次你想制作食谱时,你都会把它们从冰箱里拿出来,放在柜台上的一个新鲜空间里。入口点是食谱书中的书签。计数器空间是堆栈。完成烹饪和清理工作后,柜台是空的,食谱书中仍然有相同的东西 - 但没有鸡蛋!
    • 非常感谢您的帮助。但是在运行时,我们通过 esp 的负偏移量(此时 ebp 也指向 esp)来获取变量的位置是正确的。我将不得不再次给我的教授发电子邮件。我会回来告诉你他后来说的话。谢谢。我真的很感激你到目前为止所说的话。非常真实。而且你不知道你帮助我对我意味着什么。
    • @JohnWong “在运行时”。 程序运行时,您绝对可以找到变量所在的位置(在堆栈上)。但是,该位置在不同的运行中可能不一致 - 事实上,在现代机器上,它是有目的地随机化的,作为一种安全措施。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-02
    • 1970-01-01
    • 1970-01-01
    • 2017-03-12
    • 2019-04-04
    相关资源
    最近更新 更多