GDB中examine与print命令返回同一内存地址不同值的原因排查
为什么GDB的
x和p命令对同一内存地址返回不同值? 这个问题我之前调试时也碰到过,核心原因是**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必须先确定这个地址指向的是什么类型的数据:
- 如果这个地址对应程序里的某个变量(比如局部变量、全局变量),GDB会直接用该变量的类型来读取数据(比如变量是
short就读2字节,int读4字节)。 - 如果没有符号信息,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类型,那给x加h参数指定半字大小:
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




