【发布时间】: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 dwordcmp就可以了。 -
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 一起使用。值。