如何使用汇编程序从英特尔处理器中获取随机数?

Posted

技术标签:

【中文标题】如何使用汇编程序从英特尔处理器中获取随机数?【英文标题】:How I can get the random number from Intel's processor with assembler? 【发布时间】:2012-07-10 05:26:43 【问题描述】:

我需要从处理器(英特尔酷睿 i3)中的英特尔随机生成器获取随机数。我不想使用任何库。我想在 C++ 中使用汇编程序粘贴,但我不知道应该使用哪些寄存器和指令。

【问题讨论】:

【参考方案1】:

在支持的 CPU(目前只有 Ivy Bridge 和 Haswell Intel CPU)上调用 RDRAND 指令会将随机值放入指定的寄存器中。例如,这会给你一个随机的 64 位值:

RDRAND %rax

成功时,将设置进位位。有关详细信息,请参阅英特尔的 Bull Mountain Software Implementation Guide。 (“Bull Mountain”是英特尔硬件RNG的代号。)

【讨论】:

您能否进一步详细说明它是 PRNG 还是条目生成器? 点击链接。 TLDR:这是一个真正的随机数生成器。【参考方案2】:

...但我不知道应该使用哪些寄存器和指令。

下面是我在带有 GCC 的 Linux 机器上使用的内联汇编程序。我相信我从英特尔手册中撕下了很大一部分。它可能是由 David Johnston 编写的,他为rdand 问题提供了很棒的技术答案。他也是在英特尔设计硬件的人。


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

下面的代码用于HasRDRAND。它同时检测 AMD 和 Intel CPU(我认为这是所有提供 RDRAND 的 CPU)。

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;


另请参阅How to use RDRAND intrinsics? 它不会回答您的直接问题,但它可能是您的替代方案(并且可能对其他人有所帮助)。

【讨论】:

它最初是我的工作,但英特尔的低级软件专家对你所拥有的东西进行了清理和改进,他们致力于交叉编译器和跨字宽兼容性。 有关RDRAND 的 AMD 可用性的参考,请参阅AMD64 Architecture Programmer’s Manual Volume 3: General-Purpose and System Instructions。

以上是关于如何使用汇编程序从英特尔处理器中获取随机数?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 PySpark DataFrame 中获取随机行?

如何获得 Firebase 节点的随机子节点?

如何从英特尔 SGX Enclave 获取报价

如何在 PostgreSQL 中获得随机笛卡尔积?

如何从数据库中获取随机问题包括类别?

如何从文件中获取随机结构?