cmpq比较什么? [英] What does cmpq compare?
问题描述
谜题具有以下功能签名:
mystery has this function signature:
int mystery(char *, int);
这是神秘函数的汇编代码:
This is the mystery function assembly code:
mystery:
movl $0, %eax ;set eax to 0
leaq (%rdi, %rsi), %rcx ; rcx = rdi + rsi
loop:
cmpq %rdi, %rcx
jle endl
decq %rcx
cmpb $0x65, (%rcx)
jne loop
incl %eax
jmp loop
endl:
ret
这行cmpq %rdi, %rcx
比较什么?地址或字符值?如果要比较存储在寄存器中的地址,那又有什么意义呢?如果一个地址大于另一个地址,那么呢?
What does this line cmpq %rdi, %rcx
compare? The address or the character value? If it is comparing the address stored inside the registers, what's the point though? If one address is greater than the other, so?
推荐答案
类似于memrchr
,其中cmpq
检查搜索位置返回到缓冲区的开头,并且cmpb
检查匹配的字节.
Looks like memrchr
, with the cmpq
checking for the search position getting back to the start of the buffer, and the cmpb
checking for a matching byte.
cmp
只是根据dst - src
设置标志,就像sub
一样.因此,它当然会比较其输入操作数.在这种情况下,它们都是持有指针的qword寄存器.
cmp
just sets FLAGS according to dst - src
, exactly like sub
. So it compares its input operands, of course. In this case they're both qword registers holding pointers.
我不建议使用jle
进行地址比较;最好将地址视为未签名.尽管对于x86-64而言,实际上并不重要;您不能有一个跨越有符号溢出边界的数组,因为那里存在非规范的孔". 在64-位x86?
I wouldn't recommend jle
for address comparison; better to treat addresses as unsigned. Although for x86-64 it doesn't actually matter; you can't have an array that spans the signed-overflow boundary because the non-canonical "hole" is there. Should pointer comparisons be signed or unsigned in 64-bit x86?
不过,jbe
会更有意义.除非您实际上具有从最高地址到最低地址跨越边界的数组,否则指针将从0xfff...fff
换为0
.但是无论如何,您可以通过执行if (p == start) break
而不是p <= start
来解决此错误.
Still, jbe
would make more sense. Unless you actually have arrays that span across the boundary from the highest address to the lowest address, so the pointer wraps from 0xfff...fff
to 0
. But anyway, you could fix this bug by doing if (p == start) break
instead of p <= start
.
此函数中有一个错误,假设它是为x86-64 System V ABI编写的:其签名的大小为int
arg,但假定其符号扩展为指针char *endp = start + len
时的宽度.
There is a bug in this function though, assuming it's written for the x86-64 System V ABI: its signature takes an int
size arg, but it assumes its sign-extended to pointer width when it does char *endp = start + len
.
The ABI allows narrow args to have garbage in the high bits of their register. Is a sign or zero extension required when adding a 32bit offset to a pointer for the x86-64 ABI?
此操作还存在一些主要的性能问题:一次检查1个字节是总垃圾,而SSE2一次检查16个字节.而且,它不使用任何一个条件分支作为循环分支,因此它每次迭代有3次跳转,而不是2次.即,有一个额外的未使用的条件分支.
There are also major performance problems with this: checking 1 byte at a time is total garbage vs. SSE2 16 bytes at a time. Also, it doesn't use either conditional branch as the loop branch, so it has 3 jumps per iteration instead of 2. i.e. an extra not-taken conditional branch.
此外,它在循环后减去指针,而不是在循环内浪费inc %eax
.如果要在循环内执行inc %eax
,则最好检查它的大小,而不是指针比较.
Also, it pointer-subtract after the loop instead of wasting an inc %eax
inside the loop. If you're going to do inc %eax
inside the loop, you might as well check the size against it instead of the pointer compare.
无论如何,编写该函数的目的是为了易于逆向工程,而不是高效. jmp
以及2个条件分支使该IMO变得更糟,而不是底部有条件的惯用循环.
Anyway, the function is written to be easy to reverse engineer, not to be efficient. The jmp
as well as 2 conditional branches makes it worse for that IMO, vs. an idiomatic loop with a condition at the bottom.
这篇关于cmpq比较什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!