starti命令最可靠地停在程序真实入口_start处,不依赖调试信息,可观察libc初始化、栈帧建立等早期逻辑;而start仅停在main第一行,已跳过关键启动过程。

直接在 _start 处下断点,或者用 starti 命令——这是最可靠、最接近“一启动就停”的方式。 其他方法(比如 start 或在 main 下断点)都晚于真正入口,会跳过 libc 初始化、栈帧建立、全局构造器等关键早期逻辑。
为什么 start 不等于“停在入口”
start 实际上是 b main + run 的快捷封装,它停在 main 函数第一行 C 代码,此时程序早已执行了大量汇编级初始化:动态链接器加载、__libc_start_main 调用、atexit 注册、全局对象构造(C++)等。你完全看不到 _start、栈指针初始值、寄存器原始状态。
-
start依赖调试信息,若没编译-g或 stripped 二进制,可能失败或不准 - 对纯汇编程序、裸机 ELF、或想分析 PLT/GOT 填充过程的场景,
start完全无用 - 它不暴露
argc/argv是如何从内核传入用户空间的
正确停在真实入口的两种方式
入口地址就是 ELF Header 中的 e_entry 字段,对应符号 _start。GDB 提供两个等效但语义清晰的操作:
- 运行
b _start,然后run—— 最直观,依赖符号表存在(编译时未 strip 即可) - 直接运行
starti—— 不依赖任何符号,强制停在e_entry地址,适合无调试信息或汇编调试
验证是否成功:停住后执行 info registers rip,应与 readelf -h ./a.out | grep Entry 输出一致;执行 x/5i $rip 应看到类似 xor %rbp,%rbp、mov %rdx,%r9 这类典型的 _start 开头指令。
常见失败原因和绕过方法
遇到 Function '_start' not defined 或 Cannot access memory,通常不是命令错,而是环境或二进制问题:
- 用了
strip ./a.out→ 重编译加-g,或改用starti - 程序是 PIE(位置无关可执行文件),且未启用 ASLR → 先
set disable-randomization off,再starti,否则 GDB 可能因地址偏移混乱而失败 - 目标是 C++ 程序且含全局构造器 →
_start停住后,stepi单步几条就能看到调用__libc_start_main,再往后才是main;别误以为“卡住了” - 用
b *0x401000手动地址下断 → 风险高:地址随 PIE/ASLR 变化,每次 run 都可能不同,不推荐作为常规手段
真正需要“一启动就停”的人,往往是在查启动崩溃、栈溢出早于 main、或逆向分析加载流程——这些场景下,差一个指令就可能错过关键线索。starti 是唯一不妥协的选择,它不假设、不跳过、不优化,把控制权交还给你。











