dj-on-github / quickrdrand

A program to quickly fetch and dump data from the RdRand or RdSeed instruction to binary or hex output.
5 stars 1 forks source link

rdrand.c: Assembler messages: rdrand.c:222: Error: no such instruction: `rdseed %ax' rdrand.c:257: Error: no such instruction: `rdseed %eax' rdrand.c:292: Error: no such instruction: `rdseed %rax' #1

Open pxpxpxpxpx opened 5 years ago

dj-on-github commented 5 years ago

What platform are you compiling it on?

pxpxpxpxpx commented 5 years ago

gcc-7.1.0

pxpxpxpxpx commented 5 years ago

[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)

dj-on-github commented 5 years ago

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

dj-on-github commented 5 years ago

I've added those two flags. Pull the changes and let me know if it works.

pxpxpxpxpx commented 5 years ago

Nothing changes.....

dj-on-github commented 5 years ago

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.

pxpxpxpxpx commented 5 years ago

I haven't solved this problem yet, but very thank you for all requests. And is there any external causes?

dj-on-github commented 5 years ago

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.

noloader commented 5 years ago

@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.

dj-on-github commented 5 years ago

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.