惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

The Hacker News
The Hacker News
C
Cisco Blogs
P
Privacy & Cybersecurity Law Blog
Cloudbric
Cloudbric
S
Security Affairs
PCI Perspectives
PCI Perspectives
The Last Watchdog
The Last Watchdog
AWS News Blog
AWS News Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
N
News and Events Feed by Topic
W
WeLiveSecurity
T
Tenable Blog
L
LINUX DO - 最新话题
T
Tor Project blog
Help Net Security
Help Net Security
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
P
Proofpoint News Feed
爱范儿
爱范儿
O
OpenAI News
Hacker News - Newest:
Hacker News - Newest: "LLM"
Y
Y Combinator Blog
I
Intezer
C
Check Point Blog
Stack Overflow Blog
Stack Overflow Blog
Recent Announcements
Recent Announcements
Google DeepMind News
Google DeepMind News
S
Securelist
P
Privacy International News Feed
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
V
Vulnerabilities – Threatpost
Schneier on Security
Schneier on Security
量子位
SecWiki News
SecWiki News
L
Lohrmann on Cybersecurity
T
Threat Research - Cisco Blogs
Recent Commits to openclaw:main
Recent Commits to openclaw:main
M
MIT News - Artificial intelligence
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Scott Helme
Scott Helme
H
Help Net Security
Vercel News
Vercel News
云风的 BLOG
云风的 BLOG
Spread Privacy
Spread Privacy
Know Your Adversary
Know Your Adversary
I
InfoQ
TaoSecurity Blog
TaoSecurity Blog
Blog — PlanetScale
Blog — PlanetScale
N
News | PayPal Newsroom
小众软件
小众软件
C
CERT Recently Published Vulnerability Notes

博客园 - PKICA

编译配置解答 git实用命令 rust底层设计理念值得注意的几个地方总结 rust可变引用作为函数参数的机理详解 Rust内存重解释transmute C与Rust类型映射 Rust FFI 安全抽象范式 rust延迟初始化原语 rust重借用机制与原理 rust参数传递模型 汇编语言语法详解 gdb-pwndbg的安装与使用指南 gdb调试插件gef C语言thread_local linux系统readelf命令使用指南 gcore转储进程内存 gdb查看命令 RGB与YUV颜色编码的区别 Rust原子类型 C++ STL求两个集合交集差集 gdb调试集锦 ubuntu24.0.4使用root用户登录 ubuntu24.0.4输入密码后跳回登录界面 AI内存压缩技术TurboQuant及存疑 ubuntu切换到指定内核版本 在没有顶级科技大佬直接背书的情况下deepseek为啥能够异军突起? HuggingFace和deepseek的关系 当前主流AI大模型 Rust写时克隆Cow系列2
gdb汇编调试
PKICA · 2026-04-15 · via 博客园 - PKICA

当你进入汇编级别(Assembly level)的调试时,通常是因为 C 源代码已经无法解释当前的现象(比如你遇到的栈被踩烂、寄存器污染或 ??() 这种断层)。

在 GDB 中,从“源码级”切换到“汇编级”调试,主要依靠以下三板斧:

1. 开启汇编视觉模式(最推荐)

不要一行行输入命令,直接进入 GDB 的 TUI (Text User Interface) 模式,让你边看代码边看汇编。

  • layout split: 同时显示源代码和汇编代码。

  • layout regs: 显示寄存器状态和汇编代码。

  • focus asm: 将键盘焦点切换到汇编窗口,方便翻页。

  • layout next:切换到下一个布局方案
  • layout prev:切换到上一个布局方案

小技巧:在 TUI 模式下,当前执行的那一行汇编会被高亮。配合 stepi 极其直观。

在 GDB 的 TUI(文本用户界面)模式中,想要退出 layout asm 或关闭图形窗口回到纯命令行模式,有几种常用的方式:

1). 彻底退出 TUI 模式

如果你想关闭所有窗口(汇编、寄存器等),回到最原始的命令行界面:

  • 快捷键: Ctrl + X 紧接着按 A

    这是一个开关操作:如果当前在 TUI 模式,按它可以退出;如果在命令行模式,按它可以重新进入上一次的布局。

2). 切换回源码布局

如果你只是不想看汇编了,想切回 C/C++ 源码界面:

  • 命令: layout src

    注意:这需要你的程序在编译时带了 -g 选项,否则窗口会显示找不到源码。

常见问题:界面乱了怎么办?

在 TUI 模式下,如果程序运行输出(printf)污染了汇编窗口,导致界面字符错位,不需要退出,只需输入:

  • refresh 或者按下 Ctrl + L

    这会重新绘制屏幕,修复显示乱码。

提个醒: 如果你发现按方向键无法查看历史命令,而是移动了汇编窗口,可以输入 focus cmd 将输入焦点切回命令行窗口。

2. 核心指令:执行控制

在汇编调试中,传统的 n (next) 和 s (step) 颗粒度太粗了,你需要:

  • stepi (或 si): 执行一条机器指令。如果这行指令是 call,它会跳进函数内部。

  • nexti (或 ni): 执行一条机器指令。如果这行指令是 call,它会直接执行完该函数,停在下一条指令。

  • until *0x地址: 运行到指定的内存地址处停下。

3. 观察寄存器与内存

既然是汇编,寄存器就是你的变量。

  • info registers (或 i r): 查看所有通用寄存器的值。

  • p $rax: 打印特定寄存器(如 rax)的值。在 64 位系统中,通常 rax 存放函数返回值。

  • display /i $pc: 每次停下时,自动显示下一条要执行的汇编指令。

  • x/gx $rsp: 检查栈顶。对于调试递归引起的 ??(),这是看谁把返回地址改了的唯一方法。

4. 关键场景:如何通过汇编定位递归崩溃?

当你遇到 ??()bt 失效时,在汇编级你可以这样排查:

A. 查看当前的指令指针 (RIP)

如果 rip 指向了一个不属于代码段的地址(比如 0x0 或一个巨大的随机数),说明你的程序执行了 ret 指令,但从栈上弹出的返回地址是错的。

B. 检查函数序言 (Prologue)

使用 disassemble 查看当前函数的开头:

(gdb) disassemble my_func

你会看到类似这样的指令:

push   %rbp
mov    %rsp,%rbp
sub    $0x40,%rsp  <-- 这里在分配栈空间

如果递归太深,执行到 sub $0x40,%rsp 后,栈指针 $rsp 可能会越界进入不可写的内存页,直接触发 SIGSEGV

5. 实用反汇编技巧

  • disassemble /m: 将汇编代码和源代码穿插显示(非常适合理解 C 代码如何转译成机器码)。

  • disassemble /r: 显示原始的十六进制机器码(Opcode)。

  • set disassembly-flavor intel: 如果你看补惯 AT&T 格式(mov %src, %dest),可以切换到 Intel 格式(mov dest, src)。

总结

如递归问题,在汇编层级看其实就是:

  • 大量的 push %rbp 将旧的帧指针压栈。

  • 不断的 call 指令跳转回函数开头。

  • 最终 $rsp 撞到了内存管理的墙(Guard Page)。

进阶挑战: 下次在 GDB 里,试着在递归崩溃前执行 x/5i $pc,看看崩溃那一刻 CPU 到底是在执行 push(压栈失败)还是 mov(访问非法地址)。

参考资料: