OPENSSL_ia32_rdrand cmp / cmove指令

时间:2014-04-29 09:27:26

标签: assembly x86 openssl

我试图了解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时才能达到cmp指令)ecx中的重试计数器已递减为0.在情况1中,cmp失败,cmove不执行移动。在情况2中,rcx包含0,cmove移动0到0.无论哪种方式,cmove都是无操作。

我是否误解了一个或多个汇编指令的作用?

2 个答案:

答案 0 :(得分:3)

你有一点误会。

你的主要部分是正确的,有8次尝试使用RDRAND检索随机数,但CMOVE如果NOP返回0为{em}则不一定是RDRAND >随机数。在这种情况下,此函数将返回RCX(循环计数)的值为“随机数”。简而言之,当没有随机数可用时,此函数将仅返回0 - 否则它将从RDRAND返回实数随机数或从RDRAND收到0的迭代数。

答案 1 :(得分:1)

不只是你有轻微的误解。编程这个人并不知道他们在做什么(嗯,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()随机生成它时,实际上会返回零,而不是在这种情况下返回一个小的非零整数。我说一个无法返回零的随机函数,并且在一到八之间返回一个整数的概率略有增加是有缺陷的,因为它的输出有偏差。