为啥 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 --32
和 ld -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 个字节时,您将获得值 0x33323130
, cmp
将以 ZF=1(“等于”)结尾。最后 4 个字节将是 0x37363534
与 0x41363534
,所以 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 以这种方式打印寄存器值的主要内容,如果未能解决你的问题,请参考以下文章