【问题标题】:How to calculate the stack frame in assembly within gdb?如何在gdb中计算汇编中的堆栈帧?
【发布时间】:2023-03-12 05:06:01
【问题描述】:

我正在尝试探索汇编代码(x86、32 位、C 源代码)的调试。

我想了解如何在使用 gdb 时计算我的汇编代码中特定函数的堆栈帧的实际大小。

在弹出所有内容之前,框架的大小是%esp%ebp 之间的绝对差值与影响%esp 的每个值相加吗?

pushl   %ebp
movl    %esp, %ebp
subl    $24, %esp
subl    $48, 8(%ebp)

软件:GNU gdb (Debian 7.12-6) 7.12.0.20161007-git

gcc -m32 -fno-asynchronous-unwind-tables -fno-pic -S main.c
gcc -c -m32 main.s -o main.out
gcc -g -m32 main.s -o main.out
gcc -m32 -g -o main main.s
as -a main.s

如果有人可以帮助我,我将不胜感激。

【问题讨论】:

  • ebp 几乎无关紧要(优化的代码甚至不使用它)。这是入口时的esp 与其在函数中的最小值之间的差异。

标签: c assembly gdb


【解决方案1】:

在理想情况下,局部变量的位置与 EBP 有一个恒定的偏移量,因此您可以计算出堆栈帧的大小。但是,编译器和优化太重要了,其中一种情况可能是 EBP 用作 GPR (Trying to understand gcc option -fomit-frame-pointer)。静态分析可能是一个不错的解决方案吗?

【讨论】:

    【解决方案2】:

    不,你不能。

    由于任何操作或指令,堆栈帧从第一个参数被压入堆栈的点一直延伸到堆栈的最后修改。 IE。使用alloca() 或压入寄存器为动态变量分配空间,或者只是将寄存器存储在预分配的堆栈位置。

    实际的编译器技术非常先进,即使是标准函数的序言和尾声也可以进行修改以进行最激进的优化,从而使帧展开更加复杂。

    仅作用于基本帧,在 32 位 X86 代码的情况下,对应于存储在 %ebp 寄存器中的值是不够的。

    最近的演变,正如@Jester 所说,表明即使是%ebp 也不需要异常堆栈展开,并且编译器中的积极优化开关,如 GCC 中的 -fomit-frame-pointer,不再将其保存在堆栈中(见下文libunwind)。

    要访问前一帧,从%ebp中的基帧地址开始,您需要相关函数的堆栈帧的堆栈宽度,包括所有堆栈操作。

    此信息通常存储在可执行文件的特定部分中,通常使用有关堆栈操作的记录列表。这些部分是:

    1. .pdata 用于 Microsoft PE 可执行文件
    2. .eh_frame.eh_frame_hdr 用于 ELF 格式 (Linux)。

    根据您要使用的操作系统,您可以从https://www-user.tu-chemnitz.de/~heha/viewchm.php/hs/Win32SEH.chm/Win32SEH.htm 开始获取有关 Microsoft 可执行文件的更多信息。

    对于基于 Linux 的系统,您可以开始查看这里 https://gnu.wildebeest.org/blog/mjw/2007/08/23/stack-unwinding/ 并最终深入阅读 DWARF 调试器 http://wiki.dwarfstd.org/index.php?title=Special:SpecialPageshttps://www.nongnu.org/libunwind/ 以获得技术细节的沉浸感。

    【讨论】:

      猜你喜欢
      • 2015-11-07
      • 2013-11-05
      • 1970-01-01
      • 2011-02-15
      • 2012-04-06
      • 2012-10-26
      • 2013-05-17
      • 1970-01-01
      • 2014-06-28
      相关资源
      最近更新 更多