汇编新手求助:如何在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
相关产品推荐
相关产品推荐

