如何将RDRAND指令添加到使用VS 2008编译的64位代码中?

c00*_*0fd 1 c++ 64-bit assembly visual-studio-2008 rdrand

我正在使用Visual Studio 2008 IDE中的C++项目,我需要使用英特尔的新RDRAND指令.我做了一个快速搜索,MSDN建议使用_rdrand64_step内在定义immintrin.h,这是我在VS 2008中没有的.

在32位编译代码中,我可以使用asm关键字这样做:

    __asm
    {
        xor eax, eax

        ;RDRAND instruction = Set random value into EAX.
        ;Will set overflow [C] flag if success
        _emit 0x0F
        _emit 0xC7
        _emit 0xF0
    }
Run Code Online (Sandbox Code Playgroud)

但是在x64 asm上不受支持.

您能否建议如何使用该RDRAND指令编译64位项目?

Ros*_*dge 5

您需要将编译器升级到支持_rdrand64_step内在的编译器(自Visual Studio 2012以来支持),或者使用普通(外部)程序集来创建自己的函数(因为Visual C++不支持x86-64目标的内联汇编).

例如:

_TEXT   SEGMENT

    PUBLIC rdrand32_step
    PUBLIC rdrand32_retry
    PUBLIC rdrand64_step
    PUBLIC rdrand64_retry

    ; int rdrand32_step(unsigned *p)
rdrand32_step PROC
    xor     eax, eax
    rdrand  edx
    ; DB    0fh, 0c7h, 0f2h
    setc    al
    mov     [rcx], edx
    ret
rdrand32_step ENDP

    ; unsigned rdrand32_retry()
rdrand32_retry PROC
retry:
    rdrand  eax
    ; DB    0fh, 0c7h, 0f0h
    jnc     retry
    ret
rdrand32_retry ENDP

    ; int rdrand64_step(unsigned long long *p)
rdrand64_step PROC
    xor     eax, eax
    rdrand  rdx
    ; DB    048h, 0fh, 0c7h, 0f2h
    setc    al
    mov     [rcx], edx
    ret
rdrand64_step ENDP

    ; unsigned long long rdrand64_retry()
rdrand64_retry PROC
retry:
    rdrand  rax
    ; DB    048h, 0fh, 0c7h, 0f0h
    jnc     retry
    ret
rdrand64_retry ENDP

_TEXT   ENDS

    END
Run Code Online (Sandbox Code Playgroud)

如果您使用的是Visual Studio 2008中的MASM版本,则可能必须注释掉RDRAND指令并取消注释它们后面的数据库指令.

  • @ c00000fd:在64位代码中使用32位寄存器没有任何问题.在他的一些代码中,他使用的事实是,在64位模式下,您可以利用写入32位寄存器自动零扩展到整个64位寄存器的事实.这也可以节省一个字节,因为REX前缀不需要编码.例如`xor eax,eax`的编码比`xor rax,rax`少一个字节.Ross还从函数中返回一个32位的"int",因此他使用了_EDX_而不是_RDX_. (2认同)
  • @c00000fd 我编写的代码完全符合 Microsoft x64 调用约定。正如 Michael Petch 所解释的,我并没有忽略寄存器中的高 32 位。正如我在函数的“_retry”版本中所做的那样,循环不会导致无限循环,除非 CPU 损坏,但如果您想实现计数器,请随意扩展我的示例代码。 (2认同)