为啥 gdb 以这种方式打印寄存器值

Posted

技术标签:

【中文标题】为啥 gdb 以这种方式打印寄存器值【英文标题】:Why is gdb printing registers values in that way为什么 gdb 以这种方式打印寄存器值 【发布时间】:2017-03-29 04:15:26 【问题描述】:

所以我有一个任务,我必须使用 32 位寄存器比较 128 位数字。所以我考虑检查每一位(从左边开始),并将其与其他数字进行比较。我有这种情况:

我有一个.txt 文件,其中写入了两个16-byte 数字(没有空格或换行符),如下所示:

00000000000000010000000000000003

我使用系统调用(x86 不是 64 位)读取它们并存储在 2 个缓冲区中。当我想从他们那里获取一个字节时,我会这样做:

movl $15, %eax
addl $NUMBER1, %eax
movzbl (%eax), %eax

所以现在我在%eax 中有该数字的最后一个字节(索引当然从零开始)。然后我去: btl $0, %eax

所以在这种情况下应该很容易。我在 eax 中存储了一个字节 1。我检查它的第一位(当然是从右侧),所以 32 位 1 = 000000000000000000000000000000001,所以我应该在 carry flag 中得到 1。我用jc carry_1 检查它——当然,它有效。但后来,我试图检查其他东西。因为显然我不应该比较从最低有效数字开始的两个数字,我应该从左边开始。所以我选择btl $31, %eax,是的,当然在这种情况下,我在进位标志中得到0。所以我只是想检查一下我的%eax 的外观,以确保我没有意外得到任何东西。

所以在 gdb 中我启动了我的可执行文件。我到了movzbl 的那条线,我已经通过了那条线。现在是时候检查了:

print /t $eax。我虽然会得到:000000000000000000000000000000001,但没有。我看到的东西:

33      movzbl (%eax), %eax
(gdb) s
34      btl $31, %eax
(gdb) print /t $eax
$1 = 110001

那么为什么是110001?当我检查3 时,它是110011,所以结尾是正确的,但是开头的11 呢?我的意思是它肯定不是来自twos complement 的符号位(因为只有一个 + 它会为零,因为我的数字是正数)。那你知道是什么吗?

我正在使用 as --32ld -melf_i1386 在 Manjaro 64 位上编译它

【问题讨论】:

那个“16 字节数字”看起来更像是 32 字节长的 ASCII 字符串,可能代表十六进制编码(如 "12AB" 表示正确转换后的值 0x12AB)。当您必须比较它们时,您可以将它们作为字符串进行比较,无需将它们转换为数字,ASCII字符保留了数值的所有重要特征,例如'0' < '1' < '9' < 'A' < 'F',所以如果两个数字都是带有前导零,32 个字符长,然后仅按字符比较 char 会以无符号方式判断哪个更少/更大/相等。而且你不需要逐位比较,dword by dword cmp 就可以了。 cmp 部分解释...为简化起见,我将仅比较 8 个字符长的字符串 "01234567" vs "0123456A" -> 当您加载两个字符串的前 4 个字节时,您将获得值 0x33323130cmp 将以 ZF=1(“等于”)结尾。最后 4 个字节将是 0x373635340x41363534,所以 cmp 会告诉第二个 num 是“高于”(正确,偶然)。我很好地发现自己在撒谎,因为字符串是“big endian”和 x86 “little endian”,"0100" vs "0010" 将以0x30303130 vs 0x30313030 结尾 => 第二个“上面” => 错误答案。所以在ASCII中你必须cmp一个字符一个字符。 Dword 与 num 一起使用。值。 【参考方案1】:

那为什么是 110001?

您遗漏了代码的重要部分,例如从文本文件中读取数字的部分。但是您似乎很可能只是读取了所有字符并将它们存储在某个地方。字符 '1' 的 ASCII 码是 49,二进制(/t 开关给你二进制)是110001。所以如果你在内存中得到的是字符'1',那么这个输出完全是预期的。

【讨论】:

我刚刚注意到我是智障。你是完全正确的,我已经解决了这个问题,我来这里是为了说我很愚蠢,但你更快 :D 谢谢

以上是关于为啥 gdb 以这种方式打印寄存器值的主要内容,如果未能解决你的问题,请参考以下文章

gdb可以跟踪内存分配日志

GDB使用——pwn相关

当 gcc 中的应用程序在没有 gdb 的情况下崩溃时,如何生成堆栈转储和转储的寄存器值?

使用gdb进行写操作

海思寄存器操作

gdb - 获取寄存器的变量名