【问题标题】:What is the difference between stack and stack frame?堆栈和堆栈帧有什么区别?
【发布时间】:2015-01-10 10:37:27
【问题描述】:

这是我的代码:

17 mov      ebx,msg
18 mov      edx,5   
19 push     ebx

我正在使用 gdb 进行调试,这是我的输出:

Breakpoint 1, print () at hello.asm:17
(gdb) info register sp 
sp: 0xbffff37c
(gdb) info stack
#0  print () at hello.asm:17

(gdb) step
(gdb) info register sp
sp: 0xbffff37c
(gdb) info stack
#0  print () at hello.asm:18

(gdb) step
(gdb) info register sp
sp: 0xbffff378
(gdb) info stack
#0  print () at hello.asm:19

很明显

push ebx

'递减' register sp 4 个字节。但是当我键入时

info stack

我仍然在 hello.asm:19 看到 print()

我的问题是,什么是 info stack 显示给我,什么是 info register sp 显示给我?堆栈寄存器和信息堆栈之间有什么关系?

【问题讨论】:

  • 您是否设置了赏金来奖励其中一个答案,或者您错过了信息?我的意思是,你已经得到了 2 个正确答案,还是没有?否则你需要说明你仍然不明白的地方。
  • @Blechdose 我不明白当前的答案。
  • 我认为你的问题有一个问题,标题是“堆栈和堆栈框架有什么区别?”在问题中,您实际上提出了一些不同的问题。你问软件gdb“info stack”和“info register esp”的两个命令有什么区别。
  • 也许这有助于理解什么是栈帧:stackoverflow.com/a/3700219/4394435

标签: assembly stack


【解决方案1】:

“堆栈”是您的应用程序使用的运行时数据结构,主要有两个用途:

  1. 记录有关被调用函数的信息,以便您可以调用子例程,并从它们返回到调用它们的位置。
  2. 将临时局部变量存储在特定于声明它们的函数的上下文中。

您的 CPU 有一个特殊寄存器,其唯一目的是在内存中维护堆栈顶部的地址。这是“堆栈指针”,或sp。每次“推送”都会将 sp 减 4(在 32 位模式下),并将一个值存储在堆栈顶部,地址为 sp。每个“pop”都会做相反的事情,检索堆栈顶部的值,并将 4 添加到sp。

每次调用另一个函数时,堆栈中都会存储额外的信息,包括返回地址 (#1) 和局部变量的值 (#2)。每个函数调用的信息价值称为“框架”。


info stack 是一个 GDB 命令。它将“遍历”堆栈以寻找这些“堆栈帧”的边界。从框架中,它将显示与其关联的功能等信息。 smart 足够了,不必关心函数中的单个推送和弹出;其目的是向您展示函数调用顺序的高级信息。


GDB 中的step 命令在源代码行级别工作。通常,这是一行 C 代码。但是,由于您使用的是汇编源代码,因此每一行对应一条指令。

此外,由于您使用的是汇编源代码,因此函数和堆栈框架的概念可能不适用!使用-g 编译会将附加信息嵌入到二进制文件中,以帮助 GDB 将汇编指令与 C 函数以及有关局部变量的信息等相匹配。

我建议你首先编写一个简单的 C 程序来调用函数并做一些有趣的事情。使用-g 编译它,然后在 GDB 中逐步调试它。一旦熟悉了这一点,调试汇编代码可能会更容易。

【讨论】:

    【解决方案2】:

    当调用一个新函数时,会建立一个新的堆栈帧。每个堆栈帧代表一个函数。 在该堆栈帧中,当您将变量压入堆栈时,堆栈指针会随着堆栈因压入而增长而变化。 print() hello.asm:19 是 gdb,它使用指令指针向您显示源代码执行的位置。您在 print() 函数中,第 19 行,即“push %ebx” 在你执行一个 callq 调用另一个函数后,bt 会告诉你当前的栈帧已经改变了。

    C-x a C-x 2 crl-2

    在 gdb 中会将您的终端分成 3 个。底部痛苦中的命令,中间窗格中的反汇编和顶部窗格中的寄存器。通过这种方式,您可以逐步了解自己在做什么,以及寄存器状态发生了什么变化以及何时发生变化——这真的很有用。

    直到它因为 gdb 的 ncurses 接口(又名 tui)被破坏而崩溃,gdb 看门人才不管,不接受修复这些崩溃的补丁。如果它对您来说太多,您需要使用 gdb 前端,例如 eclipse 或洞察力,它可以向您显示相同的信息并且可能不会由于愚蠢的 ncurses 代码而崩溃

    【讨论】:

      【解决方案3】:

      esp 寄存器保存指向堆栈的指针。堆栈是内存的特殊区域,用 c 和 c++ 编写的应用程序使用它来保存函数的返回地址和局部变量。 当调试器想要确定导致当前进程指令的函数调用链时 - 它通过查看位于堆栈中的返回地址链来实现。这可能导致你的困惑。所以,当前指令!=堆栈。 基本上每次执行“调用”指令时,都会将下一条指令的地址放入堆栈并减少堆栈指针,这样当调用“返回”指令时 - 处理器就知道返回到哪里。

      【讨论】:

        【解决方案4】:

        info stack 是backtrace 的别名 - 它会尽可能地向您显示您所使用的功能。

        堆栈和esp 寄存器与查找堆栈跟踪的最深位置无关 - 您当前正在执行的函数。要找到它,您需要检查eip - 指向要执行的下一条指令的指针。只有在那之后,您才能分析堆栈以找到您所在的其他函数的返回地址。

        【讨论】:

        • 它显示了esp寄存器的内容——栈顶地址。
        猜你喜欢
        • 2021-05-10
        • 2016-01-19
        • 2016-08-18
        • 2015-01-15
        • 2011-11-20
        • 2020-10-24
        • 2014-07-13
        • 2016-10-12
        • 2021-12-12
        相关资源
        最近更新 更多