GDB如何获取被GCC优化消除的局部变量的值?
问题场景
使用gcc -g -O1 t.c参数编译以下C代码:
int main() { int a = 1; int b = 2; int c = 3; int d = 4; return 0; }
GCC的优化逻辑会消除所有未使用的局部变量,通过GDB的disassemble命令查看反汇编结果可以验证:汇编代码仅保留了return 0对应的指令,没有任何局部变量分配、赋值的相关操作:
(gdb) disassemble main Dump of assembler code for function main: 0x0000000000401106 <+0>: mov $0x0,%eax 0x000000000040110b <+5>: ret End of assembler dump.
但实际调试时执行info locals命令,GDB却能正确输出所有C代码中定义的局部变量值:
(gdb) info locals a = 1 b = 2 c = 3 d = 4
疑问:生成的汇编代码中不存在这些局部变量的对应操作指令,GDB是通过什么机制获取到这些变量取值的?
答案
核心原因是GCC在带调试信息编译时,会把编译期可确定的变量常量值直接写入DWARF调试段,不需要依赖运行时的指令、栈或寄存器存储:
- 加
-g参数编译时,GCC会在最终生成的二进制文件里附加独立的DWARF格式调试信息,这部分内容存在专门的调试段中,不属于程序运行时执行的代码流,所以反汇编看不到相关内容。 - 开O1优化时,编译器确实会删掉这些未使用局部变量的栈空间分配、赋值指令——因为这些操作对程序执行结果没有任何影响,属于冗余操作。但整个编译优化过程中,编译器始终跟踪着所有变量的取值轨迹:这几个局部变量从定义到函数结束都没有被修改过,初始值是编译阶段就能100%确定的常量。
- 对于这类编译期就能确定全生命周期取值的变量,GCC会直接把变量名、类型、对应生效的代码地址范围、固定常量值全部写入DWARF调试条目里,不会要求运行时真的给变量分配存储位置。
- GDB执行
info locals命令时,会先定位到当前暂停位置对应的代码地址,再去匹配DWARF中属于当前函数作用域、且在当前地址生效的所有变量条目。对于标记了固定常量值的变量,GDB直接读取调试信息里记录的值输出即可,根本不需要去内存或寄存器中读取。
可以通过readelf -w 编译生成的二进制文件名查看DWARF内容验证,能找到对应变量的调试条目,其中DW_AT_const_value字段就直接存着变量的固定值,类似:
DW_TAG_variable DW_AT_name : a DW_AT_type : 对应int类型的调试条目偏移 DW_AT_const_value : 1
只有当变量的取值能在编译期被完整、准确追踪时,GCC才会记录这类常量值。如果变量取值依赖运行时输入、或者被优化后取值轨迹无法确定,调试信息里就不会有固定值记录,此时执行
info locals就会看到对应变量显示<optimized out>,表示变量已被优化、无法获取取值。
内容的提问来源于stack exchange,提问作者ks1322
相关产品推荐
相关产品推荐

