这是我的代码:
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
'递减'寄存器sp 4个字节..但是当我输入
时info stack
我仍然在hello.asm看到print():19
我的问题是,什么是信息堆栈显示我,什么是信息寄存器sp显示我?堆栈寄存器和信息堆栈之间有什么关系?
答案 0 :(得分:2)
esp寄存器将指针保存到堆栈中。堆栈是特殊的内存区域,由c和c ++编写的应用程序用于保存函数的返回地址和局部变量。 当调试器想要确定函数调用链时,这会导致当前的proccess指令 - 它通过查看位于堆栈中的返回地址链来实现。这可能会导致您的困惑。所以,当前指令!=堆栈。 基本上每次执行“调用”指令时,下一条指令的地址都会被放入堆栈并且堆栈指针会减少,这样当调用“返回”指令时 - 处理器就知道返回的位置。
答案 1 :(得分:1)
info stack
是backtrace
的别名 - 它会向您显示您所处的功能,只要它可以确定它。
堆栈和esp
寄存器与查找堆栈跟踪中最深的位置无关 - 您当前正在执行的功能。要找到它,您需要检查eip
- 指向要执行的下一条指令的指针。只有在此之后,您才能分析堆栈以找到您所在的其他功能的返回地址。
答案 2 :(得分:1)
调用新函数时,会设置新的堆栈帧。每个堆栈帧代表一个功能。 在该堆栈帧中,当您将变量推入堆栈时,堆栈指针会随着堆栈的增长而发生变化。 print()hello.asm:19是gdb,使用指令指针显示源执行的位置。你在print()函数第19行,这是" push%ebx" 执行callq调用另一个函数后,bt将显示当前堆栈帧已更改。
C-x a C-x 2 CRL-2
gdb中的会将您的终端拆分为3.底部的命令,中间窗格中的反汇编以及顶部窗格中的注册。通过这种方式,您可以逐步了解您所处的位置以及寄存器状态的变化以及何时更改 - 这非常有用。
<咆哮> 直到它崩溃,因为gdb的ncurses接口(aka tui)被破坏,gdb看门人不关心,不接受修复这些崩溃的补丁。如果你得到太多,你需要使用gdb前端,例如eclipse或insight,它可以显示相同的信息,并且可能不会因为愚蠢的ncurses代码而崩溃< / rant>
答案 3 :(得分:1)
“堆栈”是应用程序使用的运行时数据结构,主要有两个用途:
您的CPU有一个特殊的寄存器,其唯一目的是将堆栈顶部的地址保存在内存中。这是“堆栈指针”,或sp
。每次“推送”将使sp
递减4(在32位模式下),并将值存储在堆栈顶部,在sp
指示的地址处。每个“pop”将执行相反的操作,检索堆栈顶部的值,并将{4}添加到sp
。
每次调用另一个函数时,附加信息都会存储在堆栈中,包括返回地址(#1)和局部变量值(#2)。每个函数调用的信息称为“框架”。
info stack
是GDB命令。它将“走”堆栈,寻找这些“堆栈帧”的边界。从框架中,它将显示与其相关联的功能等信息。足够智能,不一定关心函数内的个别推送和弹出;其目的是向您展示调用函数的顺序的更高级别信息。
GDB中的step
命令在源代码行级别工作。通常,这是一行C代码。但是,由于您正在使用汇编源代码,因此每行对应一条指令。
此外,由于您正在使用汇编源代码,因此函数和堆栈帧的概念可能不适用!使用-g
进行编译会在二进制文件中嵌入其他信息,以帮助GDB将汇编指令与C函数匹配,以及有关局部变量的信息等。
我建议你先编写一个简单的C程序来调用函数并做一些有趣的事情。用-g
编译它,然后在GDB中逐步完成它。一旦熟悉了这一点,就可以更容易地调试汇编代码。