You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GDB中x(examine memory)查看64位程序栈内存问题咨询

关于GDB x命令的64位格式说明符

x/10xg中的g本身就是GDB定义的64位(8字节,quadword)值格式说明符,不存在“无64位展示格式”的问题。认为输出拆成两个32位值属于视觉误判:

  • 输出每行开头的地址间隔为0x10(16字节),默认每行并排展示2个内存单元值,每个值都是16位十六进制数(对应64位二进制长度),比如第一行的0x0000000000000000、0x00007ffff7dd80b3都是完整64位值,没有做32位拆分。
  • 如果要取消并排排版、每行只显示1个64位值,直接用命令x/10xgz $rsp即可,末尾加的z参数会强制每个值独占一行,不会再有拆分的错觉。
当前断点位置的栈实际状态

断在<main+8>即mov eax,0x0处时,对栈内容的判断存在两个认知偏差,先梳理已执行的指令流:
命中该断点时,函数前序的push rbp、mov rbp,rsp两条指令已经执行完毕,后续的call <func>指令还未执行,因此call指令需要压入的返回地址(0x555555555182,即call指令的下一条指令地址)尚未入栈,自然不可能在当前rsp附近找到main函数内部的指令地址。
此时rsp值为0x7fffffffdd30,栈从低地址到高地址(栈向低地址增长,低地址方向为新入栈内容)的对应关系为:

  • 0x7fffffffdd30(rsp当前指向位置):存储刚执行push rbp时压入的旧rbp值,对应输出第一个值0x0000000000000000
  • 0x7fffffffdd38(rsp+8偏移位置):存储__libc_start_main调用main函数时压入的返回地址,即main执行ret指令后要跳转回的libc代码段地址,对应输出中的0x00007ffff7dd80b3,这是Linux用户态程序启动后的标准栈布局,不属于main函数内部压入的值
  • 更高地址位置的内容是libc启动阶段残留在栈上的环境变量、命令行参数、栈帧链数据,其中出现的0x0000555555555170是main函数入口地址,属于启动传参残留值,和当前执行流的压栈操作无关。

另外注意:rip寄存器存储当前待执行指令地址,正常执行流中只有call指令会将下一条指令地址压栈,其余时间栈上不会自动存储当前/下一条指令地址,不要把rsp的功能和rip混淆。

构建完整程序栈布局的实操方法

要梳理全执行流程的栈变化,不要只在main入口打单个断点,按以下步骤操作即可:

  • 用si命令做单指令步进,每执行一条指令就查看rsp值和对应栈内容
  • 遇到push、call这类会修改rsp、执行压栈操作的指令时,提前记录当前rsp值,指令执行后对比rsp偏移和新入栈的值
  • 遇到pop、ret这类出栈指令时,观察rsp的自增幅度和值的流向
  • 随时用info registers rsp rbp rip确认三个核心寄存器的当前值,避免把栈上残留的旧值、环境数据和当前函数栈帧的有效内容混淆
  • 64位环境下栈固定按8字节对齐,每个栈单元长度为8字节,计算栈偏移时按8的倍数递推即可,不会出现错位。

内容的提问来源于stack exchange,提问作者user13675319

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.31 11:01:41