news 2026/5/27 1:44:44

用GDB调试C程序,一步步看RSP和RBP寄存器在函数调用时怎么变

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用GDB调试C程序,一步步看RSP和RBP寄存器在函数调用时怎么变

深入理解函数调用栈:用GDB动态追踪RSP和RBP寄存器变化

调试器是程序员最强大的武器之一,而理解函数调用过程中栈的变化则是掌握程序运行机制的关键。本文将带你通过GDB调试一个简单的C程序,一步步观察RSP(栈指针寄存器)和RBP(基址指针寄存器)在函数调用过程中的变化,让你对栈帧有直观而深刻的理解。

1. 准备工作:编译调试版程序

首先我们需要一个带有调试信息的可执行文件。考虑以下简单的C程序:

// stack_demo.c #include <stdio.h> int add(int a, int b) { int c = a + b; return c; } int main() { int sum = add(3, 5); printf("sum = %d\n", sum); return 0; }

使用gcc编译时添加-g选项生成调试信息:

gcc -g stack_demo.c -o stack_demo

2. 启动GDB并设置断点

启动GDB调试我们刚编译的程序:

gdb ./stack_demo

在GDB中,我们首先在main函数和add函数入口处设置断点:

(gdb) break main Breakpoint 1 at 0x1167: file stack_demo.c, line 9. (gdb) break add Breakpoint 2 at 0x1149: file stack_demo.c, line 4. (gdb) run Starting program: /path/to/stack_demo Breakpoint 1, main () at stack_demo.c:9 9 int sum = add(3, 5);

3. 观察main函数的栈帧建立

在main函数开始执行时,我们首先关注RSP和RBP的值:

(gdb) info registers rsp rbp rsp 0x7fffffffdcd8 0x7fffffffdcd8 rbp 0x0 0x0

此时RSP指向栈顶,RBP为0,表示main函数尚未建立自己的栈帧。接下来执行几条指令:

  1. endbr64- 现代CPU的安全指令,不影响栈
  2. push rbp- 将当前RBP值(0)压入栈

执行push rbp后观察寄存器变化:

(gdb) ni 0x000055555555516c 9 int sum = add(3, 5); (gdb) info registers rsp rbp rsp 0x7fffffffdcd0 0x7fffffffdcd0 rbp 0x0 0x0

可以看到RSP减少了8字节(从0x7fffffffdcd8变为0x7fffffffdcd0),因为64位系统下push操作会将8字节值压栈。

  1. mov rbp, rsp- 将当前RSP值赋给RBP
(gdb) ni 0x000055555555516f 9 int sum = add(3, 5); (gdb) info registers rsp rbp rsp 0x7fffffffdcd0 0x7fffffffdcd0 rbp 0x7fffffffdcd0 0x7fffffffdcd0

现在RBP和RSP指向同一位置,标志着main函数栈帧的基址。

  1. sub rsp, 0x20- 为局部变量分配栈空间
(gdb) ni 0x0000555555555173 9 int sum = add(3, 5); (gdb) info registers rsp rbp rsp 0x7fffffffdca0 0x7fffffffdca0 rbp 0x7fffffffdcd0 0x7fffffffdcd0

RSP减少了0x20字节,为局部变量sum等预留空间。此时栈布局如下:

地址内容
0x7fffffffdcd0保存的RBP值(0)
...main的局部变量区
0x7fffffffdca0当前栈顶

4. 函数调用时的栈变化

当执行到call add指令时,观察栈和寄存器的变化:

(gdb) until 14 14 sum = add(3, 5); (gdb) disassemble ... 0x0000555555555184 <+29>: call 0x555555555149 <add> ... (gdb) ni Breakpoint 2, add (a=3, b=5) at stack_demo.c:4 4 int c = a + b;

调用call指令会做两件事:

  1. 将返回地址(下一条指令地址)压栈
  2. 跳转到目标函数

查看调用后的寄存器状态:

(gdb) info registers rsp rbp rsp 0x7fffffffdca8 0x7fffffffdca8 rbp 0x7fffffffdcd0 0x7fffffffdcd0

RSP减少了8字节(存储返回地址),我们可以验证栈顶确实存储着返回地址:

(gdb) x /1xg $rsp 0x7fffffffdca8: 0x0000555555555189

5. add函数的栈帧建立

进入add函数后,同样会建立栈帧:

  1. push rbp- 保存main函数的RBP
(gdb) ni 0x000055555555514e 4 int c = a + b; (gdb) info registers rsp rbp rsp 0x7fffffffdca0 0x7fffffffdca0 rbp 0x7fffffffdcd0 0x7fffffffdcd0
  1. mov rbp, rsp- 设置add函数的RBP
(gdb) ni 0x0000555555555151 4 int c = a + b; (gdb) info registers rsp rbp rsp 0x7fffffffdca0 0x7fffffffdca0 rbp 0x7fffffffdca0 0x7fffffffdca0
  1. 为局部变量分配空间(本例中编译器优化掉了这一步)

此时栈布局为:

地址内容
0x7fffffffdcd0main函数的RBP
...main的局部变量区
0x7fffffffdca8返回地址
0x7fffffffdca0保存的main RBP (当前RBP)

6. 函数返回时的栈恢复

当add函数执行完毕准备返回时:

  1. pop rbp- 恢复main函数的RBP
(gdb) finish Run till exit from #0 add (a=3, b=5) at stack_demo.c:4 0x0000555555555189 in main () at stack_demo.c:14 14 sum = add(3, 5); (gdb) info registers rsp rbp rsp 0x7fffffffdca8 0x7fffffffdca8 rbp 0x7fffffffdcd0 0x7fffffffdcd0
  1. ret- 从栈中弹出返回地址并跳转
(gdb) ni 15 printf("sum = %d\n", sum); (gdb) info registers rsp rbp rsp 0x7fffffffdcb0 0x7fffffffdcb0 rbp 0x7fffffffdcd0 0x7fffffffdcd0

7. 栈帧可视化总结

为了更直观地理解整个过程,下面用表格展示关键点的栈和寄存器状态:

阶段RSPRBP栈顶内容
main函数开始0x7fffffffdcd80x0-
执行push rbp后0x7fffffffdcd00x0保存的RBP(0)
执行mov rbp,rsp后0x7fffffffdcd00x7fffffffdcd0保存的RBP(0)
分配局部变量后0x7fffffffdca00x7fffffffdcd0-
call add之后0x7fffffffdca80x7fffffffdcd0返回地址
add函数push rbp后0x7fffffffdca00x7fffffffdcd0保存的main RBP
add函数mov rbp,rsp后0x7fffffffdca00x7fffffffdca0保存的main RBP

8. 高级调试技巧

除了基本的单步执行,GDB还提供了一些高级命令来观察栈:

  1. 查看栈内存内容:
(gdb) x /16xb $rsp
  1. 查看完整的栈帧信息:
(gdb) info frame
  1. 查看调用链:
(gdb) backtrace
  1. 观察特定内存地址的值:
(gdb) display /x *(long*)$rsp

通过结合这些命令,你可以更全面地了解程序执行过程中栈的变化情况。理解这些底层机制不仅能帮助你更好地调试程序,还能加深对计算机系统工作原理的认识。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/27 1:43:04

AI Agent 工具集:星瀚云面向五大人群的场景智能体

拿到星瀚云的 AI 设备、接入了算力&#xff0c;接下来最现实的问题是——它到底能帮我干什么活&#xff1f;这就是星瀚云"软件层"要解决的事。在"一主线 三支撑"架构里&#xff0c;AI Agent 工具集是 AI 能力的加工层&#xff0c;它把底层算力转化成普通人…

作者头像 李华
网站建设 2026/5/27 1:41:16

微信小程序商城搭建教程(适合无技术、预算低)零基础就能自己搭建

大家好&#xff0c;我是右以云SaaS平台的小右&#xff0c;平时就是帮各种老板研究怎么不用代码把生意搬到线上。右以云是一个无代码搭建工具&#xff0c;主要给没有技术团队的小商家提供小程序和网站的自助搭建服务。今天给大家整理的这份微信小程序商城搭建教程&#xff0c;就…

作者头像 李华
网站建设 2026/5/27 1:40:28

WzComparerR2:三步上手冒险岛游戏数据提取工具

WzComparerR2&#xff1a;三步上手冒险岛游戏数据提取工具 【免费下载链接】WzComparerR2 Maplestory online Extractor 项目地址: https://gitcode.com/gh_mirrors/wz/WzComparerR2 你是否对冒险岛游戏中的精美装备图标、炫酷技能动画和复杂的地图数据感到好奇&#xf…

作者头像 李华