C 理解gdb格式

C 理解gdb格式,c,debugging,assembly,gdb,stack,C,Debugging,Assembly,Gdb,Stack,我正在尝试熟悉gdb,并根据其格式和显示内容提出了一些问题: ─── Assembly ──── 0x00000000004004ed main+0 push %rbp 0x00000000004004ee main+1 mov %rsp,%rbp !0x00000000004004f1 main+4 movl $0x539,-0x4(%rbp) 左列的内存地址表示什么,为什么每条指令在下一个地址之间的宽度可变? 第二列是什么意思? 寄存器旁边的值是其内存位置,

我正在尝试熟悉gdb,并根据其格式和显示内容提出了一些问题:

─── Assembly ────
 0x00000000004004ed  main+0  push   %rbp
 0x00000000004004ee  main+1  mov    %rsp,%rbp
!0x00000000004004f1  main+4  movl   $0x539,-0x4(%rbp)
左列的内存地址表示什么,为什么每条指令在下一个地址之间的宽度可变? 第二列是什么意思?

寄存器旁边的值是其内存位置,还是注册表中包含的值?

这一行告诉我们什么:堆栈是否从内存地址0x000000000040058c开始,main+47指的是什么? 左列的内存地址表示什么,为什么是 每条指令在下一个地址之间有一个可变的宽度

x86机器代码指令是可变长度的。因此,一些指令使用一个字节,而例如movabs$0x12345678abcdef,%rax使用10。硬限制是15个字节,但只有故意使用冗余前缀填充才能达到15个字节

许多其他体系结构是RISC,具有固定宽度的指令

第二列是什么意思

它告诉您主符号的相对地址。请注意,在编译时不会分配内存中的实际位置

编者注:这不是一个饼图可执行文件,所以绝对地址实际上是在链接时设置的。我们可以知道,因为地址是0x00400。。。在地址空间的低位32位,而不是0x5555

寄存器旁边的值是其内存位置,还是 包含在注册表中

寄存器不存储在内存中,除非在罕见的体系结构中;寄存器没有地址,是与内存分离的空间。它也没有显示恰好持有有效地址的寄存器所指向的值

显示的值是电阻器本身的值。请注意,rbx和rcx都显示0x0

这一行告诉我们什么:堆栈从内存地址开始吗 0x000000000040058c,主+47是指什么

编者按:这部分是错误的,但我不太确定它到底是什么,用其他东西来代替它。但0x40058c绝对不是RSP的合理值。main+47是main内部的某个代码地址,就像GDB symbol+number一样


这是堆栈的位置。您的代码很小,所以main只占用少于48个地址的空间。请注意,内存通常是以块的形式分配的,因此堆栈不会出现在main+7或紧跟movl指令之后的任何位置。

@daShier的回答基本上是正确的,但这部分完全错误:

这一行告诉我们什么:堆栈从内存地址开始吗 0x000000000040058c,主+47是指什么


我认为这是RSP指向的堆栈上的qword值。它可能是main的返回地址,或者可能只是main推送它时RBP中的一个值

但返回地址是合理的:从0x4004ed开始的主地址离0x40058c不远

main+47=0x40051c是main内部的代码地址,对应于main.C第7行的C源代码。主要问题c:7。这个符号+数字是GDB以人类可读的方式打印地址的方式,相对于地址上方最近的符号。i、 他们的职能是什么;我想这就是复制/粘贴此文件时停止的断点。它告诉你现在执行的位置。或者是在拍摄堆栈上的数据快照时

我不知道你是怎么让GDB打印堆栈转储的。它的格式与信息堆栈或回溯略有不同。TUI模式布局reg或任何其他布局不包括堆栈窗格

但无论如何,0x000000000040058c肯定不是堆栈地址;它与main位于相同的4KB虚拟内存页中,因此它位于.text部分。事实上,它只有0x70字节超过main+47。该虚拟页将是可执行且不可写的

RSP堆栈指针值类似于0x7ffff7fd4100,位于虚拟地址空间低48位的顶部附近。x86-64上虚拟地址空间的可用规范部分的用户空间顶部


正如我所说,main+47只是main中的一个代码地址。它与47或48字节的堆栈空间无关。

谢谢-请澄清您的意思:请注意,内存通常是以块的形式分配的,因此堆栈不会出现在main+7或movl指令后面的任何位置。最后,最后一件事。为什么堆栈的内存地址会随着指令的执行而改变堆栈地址会一直向下移动到当前执行的asm指令之后的位置。内存管理器必须跟踪分配的内存和可用的内存。一个字节一个字节地这样做效率极低。因此,内存管理器会分配更大的块,其大小取决于系统,只要您需要比块大小多一个字节,就会得到一个全新的块。对内存的任何其他请求—堆栈、堆或
r任务等在另一个块的开头开始。至于堆栈移动:当你调用时,创建一个动态变量,等等。东西被推到堆栈上,堆栈指针也随之移动。@TagC198:这个答案的最后一部分是错误的;main+47与main可能使用的堆栈空间量无关。Main的机器代码大小至少为48字节,因为Main+47是Main的一部分。还要注意的是,如果GCC打算通过移动RSP来分配main内部的堆栈空间,那么在将0x539存储到RSP下面的内存之前,它可能会使用sub$something,%RSP来分配堆栈空间。x86-64 System V ABI在RSP下定义了一个128字节的红色区域,代码可以安全使用,无需信号处理程序或w/e进行异步碰撞。我认为这是堆栈上的qword值-它是当前帧中的当前$pc,程序在main行上停止。c:7。如果程序在由main调用的函数中停止,那么会有更多的级别。@EmployedRussian:但当前的$pc main+47不是吗?根据我的数学,这是0x40051c,不是0x40058c。您是指当前函数堆栈帧中的当前返回地址吗?反汇编where&main==4004ed和堆栈where&main+47==40058c意味着&main==0x40055d在不同的时间被记录,可能用于不同的程序。你可以看出来,因为反汇编显示!0x0000000000404F1作为由!,而且,在main+4上,也不可能在main+4内有回信地址。@EmployedRussian-oh很好地发现了。那么,这是一个非常令人困惑/误导的问题!所以这可能只是一个回溯。
─── Registers ───────────────────────
rax 0x00000000004004ed         
rbx 0x0000000000000000      
rcx 0x0000000000000000
─── Stack ───────────────────
[0] from 0x000000000040058c in main+47 at main.c:7