我正在尝试理解OpenSSL中使用的x86汇编函数,该函数使用CPU的RDRAND指令来获取随机字节。下面是函数体:
OPENSSL_ia32_rdrand:
mov $8,%ecx
.Loop_rdrand:
rdrand %rax
jc .Lbreak_rdrand
loop .Loop_rdrand
.Lbreak_rdrand:
cmp $0,%rax
cmove %rcx,%rax
ret我搞不懂cmp和cmove指令的用途。我不是x86汇编程序员,但从我看过的参考资料中可以看出,我对它所做的事情的理解是:
10 load retry counter to ecx
20 get random number into rax
30 if successful (carry flag set) goto 50
40 decrement counter and goto 20 if not zero
50 check if rax is zero
60 if it is, move rcx to rax
70 return 因此,只有当rdrand失败(进位标志被清除)时,rax才能为0,并且仅当1) rdrand成功(进位设置)并将非零数放入rax时,或者2) ecx中的重试计数器已减至0时,才能到达cmp指令。在情况1中,cmp失败,cmove不执行移动。在情况2中,rcx包含0,而cmove将0移动到0。无论哪种方式,cmove都是不可行的。
我是否误解了一条或多条汇编指令的作用?
发布于 2014-04-29 19:47:15
你有点误会了。
你的主要部分是正确的,有8次尝试使用RDRAND来检索随机数,但是如果CMOVE返回0作为随机数,那么RDRAND不一定是NOP。在这种情况下,此函数将以‘随机数’的形式返回RCX (循环计数)的值。简而言之,此函数仅在没有可用的随机数时返回0-否则它将返回来自RDRAND的实际随机数或从RDRAND收到0的迭代数。
发布于 2014-04-30 03:55:37
不只是你有一点小小的误解。无论是谁编写的,都不知道他们在做什么(嗯,OpenSSL你说...真是个惊喜)。英特尔软件开发人员手册建议:
#define SUCCESS 1
#define RETRY_LIMIT_EXCEEDED 0
#define RETRY_LIMIT 10
int get_random_64( unsigned __int 64 * arand)
{
int i ;
for ( i = 0; i < RETRY_LIMIT; i ++)
{
if(_rdrand64_step(arand) ) return SUCCESS;
}
return RETRY_LIMIT_EXCEEDED;
}在进行了一些细微的修改以使其在gcc上编译之后,我得到了:
get_random_64:
movl $10, %edx
movl $1, %ecx
.L3:
rdrand %rax
movq %rax, (%rdi)
cmovb %ecx, %eax
testl %eax, %eax
jne .L4
subq $1, %rdx
jne .L3
rep ret
.L4:
movl $1, %eax
ret当rdrand()随机产生它时,这实际上会返回一个零,而不是在这种情况下返回一个小的非零整数。我想说,一个不能返回0的随机函数,返回一个介于1和8之间的整数的概率略有增加,这是设计上有缺陷的,因为它的输出是有偏差的。
https://stackoverflow.com/questions/23360694
复制相似问题