5

I was looking at H.J. Lu's PATCH: Update x86 rdrand intrinsics. I can't tell if I should be using _rdrand_u64, _rdrand64_step, or if there are other function(s). There does not appear to be test cases written for them.

There also seems to be a lack of man pages (from Ubuntu 14, GCC 4.8.4):

$ man -k rdrand
rdrand: nothing appropriate.

How does one use the RDRAND intrinsics to generate, say, a block of 32 bytes?


A related question is RDRAND and RDSEED intrinsics GCC and Intel C++. But it does not tell me how to use them, or how to generate a block.

Community
  • 1
  • 1
jww
  • 90,984
  • 81
  • 374
  • 818
  • @Filip - Yes, BullRun has got a lot of negative criticism due to Snowden leaks (et al). In this case, I'm using a custom random number generator that extracts then expands entropy. There are multiple sources, so NSA backdoors will not cause a catastrophic generator failure. – jww Jul 03 '15 at 23:03

1 Answers1

5

If you look at <immintrin.h> (mine is in `/usr/lib/gcc/x86_64-linux-gnu/4.9/include/', Ubuntu 15.04 64bit), there are compatible (with MSVC, Intel CC) functions defined which pass data back to GCC built-ins

extern __inline int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_rdrand64_step (unsigned long long *__P)
{
     return __builtin_ia32_rdrand64_step (__P);
}

for 64bit parameter and two others for 16 bit and 32bit parameters

_rdrand16_step (unsigned short *__P)
_rdrand32_step (unsigned int *__P)

You supposed to use those so your code would be compatible with MSVC, Intel CC and other compilers.

_rdrand64_step will fill 64bit parameter, passed by pointer, with random bits and return error code. Ditto for 32bit and 16bit versions

UPDATE

"These intrinsics generate random numbers of 16/32/64 bit wide random integers. The generated random value is written to the given memory location and the success status is returned: '1' if the hardware returned a valid random value, and '0' otherwise."

https://software.intel.com/en-us/node/523864

UPDATE

Per @vy32 request, this is working for me. Well, my system gt updated since original answer, so now it is Ubuntu 20.04.1, x64, GCC v9.3, compilation flags

gcc -m64 -mrdrnd -O3 a.c

Code

#include <stdio.h>
#include <immintrin.h>

int main() {
    unsigned long long result = 0ULL;

    int rc = _rdrand64_step (&result);

    printf("%i %llu", rc, result);

    return (rc != 1);
}

Concerning CF flag and "Ignoring this is a common implementation error that does not show up in testing, but does show up when you run the DRNG under load", I believe this is what built-in is doing. If you comment out printf and compile to assembler with -S flag, code will look like,

xorl    %eax, %eax
rdrand  %rax
movl    $1, %edx
...    
cmovc   %edx, %eax

which means that %eax is zeroed, %edx is set to 1 and then via cmovc %edx might be set to 0 if CF is raised. And this value is returned from function.

So I believe built-in is already dealing with carry flag in a proper way, and user should just check output of _rdrandXX_step(ull*) as described in manual.

Severin Pappadeux
  • 16,848
  • 3
  • 34
  • 60
  • What are the return values? How do we know if the function succeeded or failed? – jww Jul 05 '15 at 21:09
  • 1
    GCC made a mess of this. Their use of [`unsigned long long`](http://stackoverflow.com/q/38681146) is frustrating. – jww Jul 31 '16 at 12:00
  • @vy32 what exactly are you asking for? Why do you need carryflag wrt random numbers? – Severin Pappadeux Jul 28 '20 at 21:03
  • @SeverinPappadeux you should read the Intel application note. The DRNG can only deliver 800MB/s of randomness, and it clears the CF if no randomness is available. Ignoring this is a common implementation error that does not show up in testing, but does show up when you run the DRNG under load. – vy32 Jul 29 '20 at 23:55
  • BTW, could you post an entire working example? I'm unable to get the `_rdrand64_step` to work in an actual program. Thanks! – vy32 Jul 29 '20 at 23:55
  • @vy32 and another couple of sentences wrt Carry flag. I believe built-in is handing it properly – Severin Pappadeux Jul 30 '20 at 01:32
  • The builtin (and the intrinsic) return the CF result via the 0 or 1 return value, nothing needs to be "handled". The `cmov` nonsense is to materialize the flag value as a 0 / 1 integer in a register (for printf). This is a pretty inefficient approach, silly gcc/clang! They're using the `0` integer output of RDRAND for the failure case. It's also fully separate from the `rc != 1` return value clang materialize the normal way (xor-zero / rdrand / setc). https://godbolt.org/z/3e6aYb – Peter Cordes Jul 30 '20 at 01:51
  • @vyx32 is very appreciative! – vy32 Jul 31 '20 at 02:28