Pregunta

I need to get random number from Intel's random generator in processor (Intel Core i3). I don't want to use any library. I want use assembler paste in C++, but I don't khow which registers and instructions should use.

¿Fue útil?

Solución

Calling the RDRAND instruction on supported CPUs (currently, only Ivy Bridge and Haswell Intel CPUs) will place a random value into a specified register. For instance, this will give you a random 64-bit value:

RDRAND %rax

On success, the carry bit will be set. See Intel's Bull Mountain Software Implementation Guide for more details. ("Bull Mountain" is the code name for Intel's hardware RNG.)

Otros consejos

... but I don't khow which registers and instructions should use.

Below is the inline assembler I use on Linux machines with GCC. I believe I ripped a significant portion from an Intel manual. It was probably written by David Johnston, who provides the awesome technical answers to questions. He is also the guy designed the hardware at Intel.


int RDRAND_bytes(byte* buff, size_t bsize)
{
    if (!HasRDRAND())
        return -1;

    size_t idx = 0, rem = bsize;
    size_t safety = bsize / sizeof(unsigned int) + 4;

    unsigned int val;
    while (rem > 0 && safety > 0)
    {
        char rc;    
        __asm__ volatile(
                "rdrand %0 ; setc %1"
                : "=r" (val), "=qm" (rc)
        );

        // 1 = success, 0 = underflow
        if (rc)
        {
            size_t cnt = (rem < sizeof(val) ? rem : sizeof(val));
            memcpy(buff + idx, &val, cnt);

            rem -= cnt;
            idx += cnt;
        }
        else
        {
            safety--;
        }
    }

    // Wipe temp on exit
    *((volatile unsigned int*)&val) = 0;

    // 0 = success; non-0 = failure (possibly partial failure).
    return (int)(bsize - rem);
}

And the code below is used for HasRDRAND. It detect both AMD and Intel CPUs (I think that's all the CPUs that provide RDRAND).

struct CPUIDinfo {
    unsigned int EAX;
    unsigned int EBX;
    unsigned int ECX;
    unsigned int EDX;
};

// Be careful below. EBX/RBX needs to be preserved depending on the memory model and use of PIC.
void cpuid_info(CPUIDinfo *info, const unsigned int func, const unsigned int subfunc) {
    __asm__ __volatile__ (
            "cpuid"
            : "=a"(info->EAX), "=b"(info->EBX), "=c"(info->ECX), "=d"(info->EDX)
            : "a"(func), "c"(subfunc)
    );
}

int HasAmdCpu() {
    CPUIDinfo info;
    cpuid_info(&info, 0, 0);
    if (memcmp((char *) (&info.EBX), "htuA", 4) == 0
            && memcmp((char *) (&info.EDX), "itne", 4) == 0
            && memcmp((char *) (&info.ECX), "DMAc", 4) == 0) {

        return 1;
    }


int HasIntelCpu() {
    CPUIDinfo info;
    cpuid_info(&info, 0, 0);
    if (memcmp((char *) (&info.EBX), "Genu", 4) == 0
            && memcmp((char *) (&info.EDX), "ineI", 4) == 0
            && memcmp((char *) (&info.ECX), "ntel", 4) == 0) {

        return 1;
    }

    return 0;
}

int HasRDRAND() {    
    if (!HasAmdCpu() || !HasIntelCpu())
        return 0;

    CPUIDinfo info;
    cpuid_info(&info, 1, 0);

    static const unsigned int RDRAND_FLAG = (1 << 30);
    if ((info.ECX & RDRAND_FLAG) == RDRAND_FLAG)
        return 1;

    return 0;
}

Also see How to use RDRAND intrinsics? It does not answer your immediate question, but it may be an alternative for you (and may help others).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top