我正在使用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位项目?
答案 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个参数在寄存器中传递:RCX
,RDX
, R8
和R9
:
.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文件名。显然,仅针对x64
和Debug
的{{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
编译它,则保存一个步骤并在同一解决方案中完成所有操作。