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

汇编新手求助:如何在GDB中解读栈内存

嘿,刚接触汇编和GDB的话,栈内存这块确实容易懵,我来给你拆解清楚~

拆解GDB的x命令输出:栈内存解读指南

先搞懂x/10x的输出结构

当你执行x/10x(没指定地址的话,默认从当前栈指针$esp开始),输出的每一行结构其实很简单:

0xffffdabc:  0x12345678 0xabcdef12 ...
  • 第一列的0xffffdabc是内存地址,不是栈层级或栈帧编号哦。栈是一块连续的内存区域,而且是从高地址往低地址增长的,所以你会看到后续输出的地址越来越小。
  • 后面的32位十六进制值(比如0x12345678)是该地址上存储的4字节数据——因为你用了x格式(十六进制显示),32位系统下默认每次读取4字节,所以每个值都是32位的。

结合bt和info frame串起栈帧逻辑

你已经会用bt和info frame,这俩是解读x输出的关键钥匙:

  • bt给你的是函数调用链:#0是当前正在执行的函数(你的例子里是zzz),#1是调用它的上层函数(yyy),以此类推。每个编号对应一个独立的栈帧,也就是栈里的一块专属内存区域。
  • info frame会告诉你当前栈帧的核心细节:比如栈帧的起始(栈底,$ebp指向的位置)和结束(栈顶,$esp指向的位置)地址,还有返回地址存在哪里、哪些寄存器被存在栈里等。

拿你提供的bt信息举例:

(gdb) bt
#0 zzz () at zzz.c:96
#1 0xf7d39cba in yyy (arg=arg@entry=0x0) at yyy.c:542
#2 0xf7d3a4f6...

当你在#0栈帧(也就是zzz函数里)执行x/10x $esp,输出里肯定能找到0xf7d39cba这个值——这就是zzz函数的返回地址,也就是它执行完后要跳回yyy函数的位置,正好和bt里#1行的地址对应上。

再比如,info frame可能会显示类似“Saved registers: ebp at 0xffffdac8, eip at 0xffffdacc”的内容,那你执行x/x 0xffffdacc,读到的就是刚才说的返回地址0xf7d39cba,完美和bt的输出呼应。

栈内存里的常见内容类型

用x命令看到的32位值,一般逃不出这几种:

  • 返回地址:当前函数执行完毕后要跳转回的上层函数入口,对应bt里上一个栈帧的起始地址。
  • 保存的寄存器值:比如ebp(栈帧基址寄存器),函数调用时会把上层栈帧的ebp压栈,方便后续恢复。
  • 局部变量:当前函数里定义的局部变量,会存在栈帧的特定位置,你可以用print &变量名拿到它的地址,再和x输出里的地址对应上。
  • 函数参数:上层函数调用当前函数时传入的参数,通常存在ebp上方的位置(比如ebp+8、ebp+12,每个参数占4字节),info frame里也会标注参数的存储位置。

小技巧:精准定位栈内容,不用瞎猜

如果觉得直接看x/10x太杂乱,可以针对特定位置定向查看:

  • 想看当前函数的返回地址:执行x/x $ebp+4(32位系统里,$ebp指向的是上层栈帧的ebp值,ebp+4就是返回地址的位置)。
  • 想看上一层函数传入的参数:依次执行x/x $ebp+8、x/x $ebp+12……每个参数占4字节,往后递推就行。

这样一步步对应,就能把x的输出和bt、info frame的信息完全串起来啦~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:50:30