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

通过GDB调试理解程序栈结构及相关技术疑问咨询

GDB调试x86-64汇编栈帧疑问解答

汇编代码

segment .text
    global main
main:
    push    rbp
    mov rbp, rsp

GDB分步调试输出

push    rbp

(gdb) info register rbp rsp
rbp            0x1                 0x1
rsp            0x7fffffffe738      0x7fffffffe738

(gdb) info frame
Stack level 0, frame at 0x7fffffffe740:
 rip = 0x401140 in main (file.asm:12); saved rip = 0x7ffff7ddd790
 source language asm.
 Arglist at 0x7fffffffe730, args: 
 Locals at 0x7fffffffe730, Previous frame's sp is 0x7fffffffe740
 Saved registers:
  rip at 0x7fffffffe738

(gdb) info symbol 0x7ffff7ddd790
__libc_start_call_main + 128 in section .text of /usr/lib/libc.so.6
(gdb) nexti


        mov rbp, rsp

(gdb) info register rbp rsp
rbp            0x1                 0x1
rsp            0x7fffffffe730      0x7fffffffe730

(gdb) info frame
Stack level 0, frame at 0x7fffffffe740:
 rip = 0x401141 in main (stack.asm:13); saved rip = 0x7ffff7ddd790
 source language asm.
 Arglist at 0x7fffffffe730, args: 
 Locals at 0x7fffffffe730, Previous frame's sp is 0x7fffffffe740
 Saved registers:
  rbp at 0x7fffffffe730, rip at 0x7fffffffe738


        next instruction

(gdb) info register rbp rsp
rbp            0x7fffffffe730      0x7fffffffe730
rsp            0x7fffffffe730      0x7fffffffe730

(gdb) info frame
Stack level 0, frame at 0x7fffffffe740:
 rip = 0x401144 in main (stack.asm:14); saved rip = 0x7ffff7ddd790
 source language asm.
 Arglist at 0x7fffffffe730, args: 
 Locals at 0x7fffffffe730, Previous frame's sp is 0x7fffffffe740
 Saved registers:
  rbp at 0x7fffffffe730, rip at 0x7fffffffe738

疑问

  • 执行push rbp指令时,首次出现的saved rip = 0x7ffff7ddd790是否为__libc_start_call_main函数栈的初始地址?
  • 执行第一条push rbp指令时,info frame与寄存器信息显示栈帧大小为8字节(位于frame at 0x7fffffffe740与rsp 0x7fffffffe738之间),这8字节中存储的是什么内容?如何查看?
  • 执行第一条push rbp指令时,若局部变量和参数位于栈帧内,且栈帧范围为0x7fffffffe740到0x7fffffffe738,为何Arglist和Locals的地址为0x7fffffffe730,超出该栈帧范围?

解答

  1. 不是。这个saved rip是从__libc_start_call_main跳转到main函数后,返回时要执行的下一条指令地址,也就是__libc_start_call_main + 128的位置,并非__libc_start_call_main栈的初始地址。当main执行完毕后,CPU会跳回这个地址继续执行libc的收尾逻辑。

  2. 这8字节里存的是调用main时保存的返回地址(也就是刚才提到的saved rip的值0x7ffff7ddd790)。可以用GDB的x/gx 0x7fffffffe738命令查看这个地址的内容,x是检查内存的命令,gx表示按8字节(64位)十六进制格式显示。

  3. 这是因为你还没完成栈帧的初始化(未执行mov rbp, rsp),GDB此时对栈帧的识别有偏差。在x86-64的标准栈帧中,rbp是栈帧基址,执行mov rbp, rsp后,rbp才会指向当前栈帧的底部,此时GDB才能准确识别局部变量和参数的范围。而在执行push rbp后、mov rbp, rsp前,rbp还是旧值0x1,GDB无法正确解析当前栈帧的边界,所以显示的Arglist和Locals地址是不准确的,等执行完mov rbp, rsp后,栈帧结构才会正确建立。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 13:34:55