You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

GDB中examine与print命令返回同一内存地址不同值的原因排查

为什么GDB的xp命令对同一内存地址返回不同值?

这个问题我之前调试时也碰到过,核心原因是**x(examine)和p(print)命令的设计逻辑完全不同**:一个是直接读取指定大小的内存字节,一个是按数据类型来解析内存,哪怕指向同一个地址,处理方式也有本质区别。

先搞懂两个命令的核心差异

x命令:纯内存视角,按指定单元大小读取

x是专门用来“检查内存原始内容”的命令,它完全听你的指令读取指定大小的内存块。格式是x/<n/f/u>,其中u就是内存单元大小:

  • b:1字节(byte)
  • h:2字节(半字,halfword)
  • w:4字节(字,word,多数架构下的默认值)
  • g:8字节(八字节,giant)

如果你没指定u,GDB会用当前设置的默认单元大小(可以用show x命令查看)——比如你例子里的x/d $ebp-0x1c应该是默认按字节读取,所以只拿了地址处的1字节数据。

p命令:类型视角,按变量类型(或默认类型)解析

p命令是用来“打印变量值”的,当你直接解引用一个裸地址(比如*0xffffd10c)时,GDB必须先确定这个地址指向的是什么类型的数据:

  1. 如果这个地址对应程序里的某个变量(比如局部变量、全局变量),GDB会直接用该变量的类型来读取数据(比如变量是short就读2字节,int读4字节)。
  2. 如果没有符号信息,GDB会默认把它当成int*来解引用(32位架构下读4字节,64位读8字节)。

你的例子里到底发生了什么?

看你第一次的调试输出:

(gdb) x/d $ebp-0x1c
0xffffd10c: 126
(gdb) p *0xffffd10c
$1 = 382
  • x/d读取的是0xffffd10c处的1字节0x7e(十进制126)。
  • p *0xffffd10c读取的是该地址处的2字节(因为GDB通过符号信息知道这里是short类型的变量):0x017e(十进制382,低字节是0x7e,高字节是0x01)。

再看你更新的测试:

(gdb) p/x *0xffffd110
$5: 0x9c9
(gdb) x/x $ebp-0x18
0xffffd110: 0xc9
  • x/x读取的是0xffffd110处的1字节:0xc9
  • p/x *0xffffd110读取的是2字节:0x09c9(也就是输出里的0x9c9,省略了前导0),其中0xffffd110是低字节0xc9,下一个地址0xffffd111是高字节0x09

怎么让两个命令返回一致的结果?

很简单,显式匹配两者的读取大小/类型就行:

方法1:给x命令指定匹配p的单元大小

如果p读的是2字节的short类型,那给xh参数指定半字大小:

x/dh $ebp-0x1c  # h表示读取2字节数据

这样读取的结果就会和p *0xffffd10c完全一致。

方法2:给p命令显式指定类型

如果你想让p只读取1字节(和x的默认字节读取一致),可以强制把地址转换成char*类型:

p/x *(char*)0xffffd110

这样输出的就是0xc9,和x/x $ebp-0x18的结果一致。

额外技巧:查看GDB的默认设置

show x命令可以查看x命令的默认格式和单元大小,方便你排查问题:

show x

输出大概是这样的:

The output format for the examine command is "x".
The default number of units to display is 1.
The default unit size is "byte".

内容的提问来源于stack exchange,提问作者Mr.SrJenea

火山引擎 最新活动