最直接打印变量地址的方法是用 p &var,gdb会显示其在栈上的实际内存地址;需确保变量在当前栈帧可见、编译时加 -g 且未启用过高优化(如 -o2),否则可能报“no symbol”错误。

用 p &var 直接打印变量地址
最直接的办法就是用 p &var(注意是取地址符 &),GDB 会显示该变量在栈上的实际内存地址。前提是变量名在当前栈帧中可见——也就是你得先 frame 切到对应函数,或者确保断点停在变量作用域内。
常见错误现象:执行 p &buf 报错 No symbol "buf" in current context,说明要么变量被优化掉了,要么当前不在定义它的栈帧里。
- 编译时必须加
-g,否则调试信息缺失,&var查不到 - 如果用了
-O2或更高优化级,局部变量可能被存进寄存器或完全消除,&var会失败 - 结构体成员要用
p &s.a,不能只写&s(那是整个结构体的起始地址)
info frame 看栈帧基址,再手动算偏移
当变量名不可见(比如调试 stripped 二进制、或逆向场景),就得靠栈帧布局推算地址。info frame 会输出 saved rbp at 0x7fffffffe160 和 caller of ... is ... 这类关键行,其中 saved rbp 就是当前栈帧的基地址(即 rbp 值),而局部变量通常位于 rbp - offset 处。
IDA 或反汇编里看到的 mov DWORD PTR [rbp-0x14], edi,就表示变量存于 rbp - 0x14;把 rbp 值代入即可得绝对地址。
-
info registers rbp可单独查寄存器值,比info frame更快定位基址 - 64 位下注意用
$rbp,32 位用$ebp;别混淆成$rsp(那是栈顶,变量不一定在它附近) - 偏移为正数(如
[rbp+0x10])通常是传入的参数,不是局部变量
x 命令按地址查看内存内容,验证变量位置
拿到地址后,用 x 命令确认那里确实是你要的值。比如 x/1wx 0x7fffffffe14c 表示以 4 字节十进制格式读一个 word,x/s 0x7fffffffe150 查字符串。
容易踩的坑是单位和格式选错:x/4xb 是 4 个字节,x/4xw 是 4 个 4 字节整数(共 16 字节),别看漏了后缀。
- 常用组合:
x/10xg $rbp-0x20(查 10 个 8 字节数据,适合 64 位栈变量) -
x/s要求地址指向以\0结尾的字符串,否则会越界读到乱码甚至触发访问异常 - 地址没对齐(比如
0x7fffffffe14f)时,xw可能读出错位数据,优先用xb逐字节看
为什么 print var 不等于地址,但有时能蒙对
p var 输出的是变量的值,不是地址;但若 var 本身是指针(比如 char *p = "hello"),那 p p 打印的就是字符串首地址——这时候容易误以为 p 命令能查地址,其实只是巧合。
真正要区分清楚:&var 是变量在内存中的位置,var 是它存的内容,*var 是它指向的内容(仅当 var 是指针时有效)。
- 数组名
arr在多数上下文中退化为地址,所以p arr和p &arr[0]效果一样,但p &arr得到的是整个数组的地址(类型不同) -
info locals能列出当前帧所有局部变量名,但不带地址;它是快速确认变量是否“存活”的第一道检查
栈帧里的地址不是静态的,每次运行都变;依赖 ASLR 的程序里,rbp 值每次都不一样,偏移才是唯一可靠的锚点。











