Open pxpxpxpxpx opened 5 years ago
gcc-7.1.0
[root@localhost quickrdrand-master]# gcc -v Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/local/libexec/gcc/x86_64-pc-linux-gnu/7.1.0/lto-wrapper Target: x86_64-pc-linux-gnu Configured with: ../configure --enable-checking=release --enable-languages=c,c++ --disable-multilib Thread model: posix gcc version 7.1.0 (GCC)
I found that when compiling on a computer without rdrand or rdseed, it removes the instruction from the available instructions. You would need to pass in a directive to tell it to make the instruction available.
From the GCC documentation ..
The following built-in function is available when -mrdrnd is used. All of them generate the machine instruction that is part of the name.
unsigned int __builtin_ia32_rdrand16_step (unsigned short *)
unsigned int __builtin_ia32_rdrand32_step (unsigned int *)
unsigned int __builtin_ia32_rdrand64_step (unsigned long long *)
Similarly -mrdseed works for RdSeed
I've added those two flags. Pull the changes and let me know if it works.
Nothing changes.....
My machine has..
gcc -v Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/5.3.1/lto-wrapper Target: x86_64-redhat-linux Configured with: ../configure --enable-bootstrap --enable-languages=c,c++,objc,obj-c++,fortran,ada,go,lto --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-plugin --enable-initfini-array --disable-libgcj --with-isl --enable-libmpx --enable-gnu-indirect-function --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux Thread model: posix gcc version 5.3.1 20160406 (Red Hat 5.3.1-6) (GCC)
It's working fine.
gcc quickrdrand.c rdrand_stdint.c [root@deadhat quickrdrand]# ./a.out 5af7563d366abc92 60003fe21cd37bea 8a2dc9b80d31b6c4 9851daf1c30b739f 7020a9b3c9166643 84cd37efc9de5dd9 a5a8b711549eb64f 74750382f683367c 675abbbd5d5f3eb4 e4c9706db81644d1 d35d753ad6277c92 e4cd016fecc2b04a 5e0d419f27d8a3c8 d54ed1414bc857c4 d319fa5c13cdfbfd f99e1b262abbc69b ...
I compile this on many platforms, including new ones that haven't been released yet (I work for Intel and test the RNG that I designed on new chips).
I've poked around the internet for reasons why gcc might not accept rdrand or rdseed and they all point back to the -mrdrnd and -mrdseed flags.
I haven't solved this problem yet, but very thank you for all requests. And is there any external causes?
See here. https://github.com/weidai11/cryptopp/issues/431 . It looks like GCC 7.1 is the problem and it may not have been compiled with the new instruction support.
@dj-on-github,
We had a fair amount of trouble with rdrand
and rdseed
. It is not so much compiler versions. Simply using compiler version would be easy. Rather it is a confluence of VMs with old OSes, old assemblers and new compilers. The cloud VMs with mismatched components turned out to be the real problem (or our assumptions about matched components in a toolchain was wrong).
When taking toolchains into consideration, I think you need Binutils 2.24 for rdrand
, and Binutils 2.26 for rdseed
. Binutils provides the assembler, and that is what produces rdrand
or rdseed
instructions. (I'm going back a while, so the Binutils version numbers may be off).
For RDRAND and RDSEED on Unix and Linux, we found it easiest to emit the byte codes. That sidesteps both the compiler and assembler. Here are the byte codes for rdrand
and rdseed
(in MASM syntax):
RDRAND_EAX:
DB 0Fh, 0C7h, 0F0h
RDRAND_RAX:
DB 048h, 0Fh, 0C7h, 0F0h
RDSEED_EAX:
DB 0Fh, 0C7h, 0F8h
RDSEED_RAX:
DB 048h, 0Fh, 0C7h, 0F8h
Another sharp edge is GCC Issue 80180, Incorrect codegen from rdseed intrinsic, which resulted in CVE-2017-11671. Using inline ASM that also checks the CY flag was another reason we stopped using intrinsics.
Now our RDARND
and RDSEED
looks similar to the following on Unix and Linux:
#if defined(__amd64) || defined(__x86_64)
// Fills 8 bytes
inline void RDRAND64(void* output)
{
__asm__ __volatile__
(
"1:\n"
".byte 0x48, 0x0f, 0xc7, 0xf0;\n"
"jnc 1b;\n"
: "=a" (*reinterpret_cast<uint64_t*>(output))
: : "cc"
);
}
#endif // RDRAND64
Another sharp edge is OpenBSD. (I know one of the BSDs has problems, and I am fairly sure it was OpenBSD). OpenBSD never accepted GPLv3, so they are pinned at GPLv2 and stuck around the 2007's. As such, you can expect to encounter GCC 4.2.1 and Binutils 1.14 or so. The toolchain is so old it cannot compile and assemble SSE4.2, if I recall correctly.
That's how I used to do it back when no compiler supported RdRand. If this is going to keep coming up, I may have to update rdrand.c and rdrand_stdint.c to cope. It feels a little unsatisfactory though.
What platform are you compiling it on?