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

时间:2016-06-27 00:42:33

标签: c++ assembly visual-studio-2008 64-bit rdrand

我正在使用Visual Studio 2008 IDE中的C ++项目,我需要使用英特尔新的RDRAND指令。我进行了快速搜索,MSDN建议使用immintrin.h中定义的_rdrand64_step内在函数,这是我在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
    }

但是在x64上asm不受支持。

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

2 个答案:

答案 0 :(得分:5)

您需要将编译器升级到支持_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 内在函数的编译器(自Visual Studio 2012以来支持),或使用普通(外部)程序集创建自己的函数(因为Visual C ++不支持内联函数)用于x86-64目标的程序集。)

例如:

reqr:
chr [1:3] "interpersonal" "communication" "communication and interpersonal"
chr [1:2] "team player" "initiative"
chr [1:2] "mechanical engineering" "written"

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

答案 1 :(得分:0)

哇,我花了一段时间来搞清楚。以下是仅适用于x64编译的Visual Studio 2008的步骤:

(A)创建一个空白项目:文件 - >新 - >项目。然后单击“Visual C ++”并选择“清空项目”。将其命名为,然后单击“确定”以创建。

(B)转到您的VS安装文件夹,我的情况是C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\VCProjectDefaults并复制masm.rules文件,并将其命名为masm64.rules

(C)在记事本中打开masm64.rules并搜索Microsoft Macro Assembler并将其更改为x64 Microsoft Macro Assembler。将有两个地方可以做到这一点。然后搜索ml.exe并将其更改为ml64.exe。然后保存该文件并关闭记事本。

(D)在“解决方案资源管理器”中右键单击您的项目,然后选择“自定义构建规则”并选中x64 Microsoft Macro Assembler并单击“确定”。

(E)在“解决方案资源管理器”中右键单击您的项目,然后选择添加 - >新项目,选择Text File (.txt)并将其命名为.asm扩展名。我称之为funcs_asm_x64.asm。然后单击“确定”。

(F)打开funcs_asm_x64.asm并输入您的x64 asm。对我来说,我有兴趣用64位操作数调用RDRAND。我做了以下。该函数将一个参数作为指向64位整数的指针,它将用随机位填充。如果成功,它将在rax中返回1,否则它将返回0.

要记住的一件事是x64代码仅使用__fastcall calling convention,这意味着函数的前4个参数在寄存器中传递:RCXRDXR8R9

.code

RdRand64  PROC
    ; RCX = pointer to receive random 64-bit value
    ; RETURN: [RAX] = 1 if success, 0 if failed

    xor         rax, rax

    test        rcx, rcx
    jz          lbl_out

    ;push       rdx
    xor         rdx, rdx
    DB          048h, 0fh, 0c7h, 0f2h       ;RDRAND RDX

    setc        al
    mov         [rcx], rdx
    ;pop        rdx

 lbl_out:
    ret

RdRand64  ENDP

END

(G)然后在“解决方案资源管理器”中右键单击您的项目,然后选择添加 - >单击新项目,选择C++ File (.cpp)并将其命名为main.cpp,然后单击确定以创建。然后将以下内容添加到main.cpp文件中:

extern "C" __int64 __fastcall RdRand64(unsigned __int64* pRndVal);

 void main()
{
}

主要部分是extern "C"定义。需要main()方法来满足MASM要求。

(H)然后转到Build - > Configuration Manager并打开下拉列表,其中显示“Active solution platform”并选择New。然后在“输入或选择新平台”中选择“x64”,然后单击“确定”。然后选择“x64”作为“Active solution platform”,并在“Active solution configuration”中选择“Release”。

(I)关闭配置管理器窗口并构建解决方案。如果成功,请在funcs_asm_x64.obj文件夹中查找\x64\Release文件以获取解决方案。将该文件复制到主解决方案文件夹(您需要使用RDRAND指令的位置。)

(J)然后在您需要使用RDRAND指令的主解决方案中,右键单击“解决方案资源管理器”中的项目,然后转到“属性”。然后转到Linker - >命令行并添加您的obj文件名。显然,仅针对x64Debug的{​​{1}}平台执行此操作。就我而言,它是Release。单击“确定”保存。

(K)然后使用我刚创建的这个函数,首先添加funcs_asm_x64.obj定义,就像在第一个项目中一样:

extern "C"

然后你可以这样调用它(显然它不能内联):

extern "C" __int64 __fastcall RdRand64(unsigned __int64* pRndVal);

(1)显然,unsigned __int64 randomNumber = 0; __int64 bResult = RdRand64(&randomNumber); Win32版本不需要以上所有内容。为此,只需使用我在原帖中显示的内联汇编。

(2)显然,您还需要调用x86命令以确保支持__cpuid指令。在许多CPU上它仍然没有。所以,如果不是,那就不要调用我的RDRAND方法,因为它会崩溃!您可以使用此代码在全局变量中检查并存储结果:

RdRand64

(3)有一种方法可以将#include <intrin.h> bool is_RDRAND_supported() { int name[4] = {0}; __cpuid(name, 0); if(name[1] == 0x756e6547 && //uneG name[2] == 0x6c65746e && //letn name[3] == 0x49656e69) //Ieni { int data[4] = {0}; __cpuid(data, 1); //Check bit 30 on the 2nd index (ECX register) if(data[2] & (0x1 << 30)) { //Supported! return true; } } return false; } 文件包含在asm的同一个项目中。不幸的是,如果你这样做,你将无法将项目切换回VS 2008并在需要时进行编译。因此,如果您仅为Win32编译它,则保存一个步骤并在同一解决方案中完成所有操作。