如何将 RDRAND 指令添加到用 VS 2008 编译的 64 位代码中?
How to add RDRAND instruction into 64-bit code compiled with VS 2008?
我在 Visual Studio 2008 IDE 从事 C++ 项目,我需要使用 immintrin.h
中定义的英特尔新 RDRAND instruction. I did a quick search, and MSDN recommends using _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 位编译我的项目吗?
您需要将编译器升级到支持 _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
如果您使用的是 Visual Studio 2008 年的 MASM 版本,您可能需要注释掉 RDRAND 指令并取消注释后面的 DB 指令。
哇,我花了一段时间才弄明白。以下是 Visual Studio 2008 仅用于 x64
编译的步骤:
(A) 创建一个空白项目:文件 -> 新建 -> 项目。然后点击 "Visual C++" 和 select "Empty Project." 给它起个名字,然后点击确定创建。
(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) 右键单击 "Solution Explorer" 和 select "Custom build rules" 中的项目并选中 x64 Microsoft Macro Assembler
并单击确定.
(E) 在 "Solution Explorer" 中右键单击您的项目,然后 select 添加 -> 新项目,select Text File (.txt)
并将其命名为 .asm
扩展名。我称之为 funcs_asm_x64.asm
。然后点击确定。
(F) 打开 funcs_asm_x64.asm
并输入你的 x64 asm。对我来说,我对使用 64 位操作数调用 RDRAND
很感兴趣。我做了以下事情。该函数将一个参数作为指向一个 64 位整数的指针,它将用随机位填充。如果成功它将 return 1 in rax
,否则它将 return 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)然后在"Solution Explorer"中右击你的项目,select添加->新建项,selectC++ File (.cpp)
并命名为main.cpp
,点击确定创建。然后将以下内容添加到 main.cpp
文件中:
extern "C" __int64 __fastcall RdRand64(unsigned __int64* pRndVal);
void main()
{
}
主要部分是extern "C"
定义。 main()
需要方法来满足 MASM 要求。
(H) 然后转到构建 -> 配置管理器并打开显示 "Active solution platform" 和 select 新建的下拉列表。然后在 "Type or select the new platform" 中选择 "x64" 并单击确定。然后 select "x64" as "Active solution platform" 还有 select "Release" in "Active solution configuration."
(I) 关闭配置管理器 window 并构建解决方案。如果成功,请在 \x64\Release
文件夹中寻找 funcs_asm_x64.obj
文件作为您的解决方案。将该文件复制到您的主解决方案文件夹中(您需要在其中使用 RDRAND
指令。)
(J) 然后在您需要使用 RDRAND
指令的主要解决方案中,右键单击 "Solution Explorer" 中的项目并转到特性。然后转到链接器 -> 命令行并添加您的 obj 文件名。显然只对 Debug
和 Release
的 x64
平台这样做。在我的例子中是 funcs_asm_x64.obj
。点击确定保存。
(K) 然后要使用我刚刚创建的函数,首先添加 extern "C"
定义,就像您在第一个项目中所做的那样:
extern "C" __int64 __fastcall RdRand64(unsigned __int64* pRndVal);
然后你可以这样调用它(显然它不能内联):
unsigned __int64 randomNumber = 0;
__int64 bResult = RdRand64(&randomNumber);
(1) 显然以上所有内容对于 Win32
或 x86
构建都不是必需的。为此,只需使用我在原始 post.
中展示的内联程序集
(2) 同样显然您需要调用 __cpuid
命令以确保支持 RDRAND
指令。在许多 CPU 上,它仍然不是。所以如果不是,那么不要调用我的 RdRand64
方法,因为它会崩溃!您可以使用此代码检查结果并将其存储在全局变量中的某处:
#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;
}
(3) 有一种方法可以将asm
文件包含在VS 2008
的同一个项目中。不幸的是,如果您这样做,您将无法将项目切换回 Win32
并在需要时进行编译。因此,如果您仅为 x64
编译它,则保存一个步骤并在同一解决方案中完成所有操作。
这相当简单,尽管是间接的:为 _rdrand64_step
创建一个小型 C 包装器,使用 VS2012 将其编译成一个 .OBJ 文件,没有花哨的选项(没有 /LTCG,没有 /Gs 等),并且 link 这个目标文件按原样放入你的 VS2008 项目中。 VS2008编译器可能不知道指令,但是VS2008linker不关心
我在 Visual Studio 2008 IDE 从事 C++ 项目,我需要使用 immintrin.h
中定义的英特尔新 RDRAND instruction. I did a quick search, and MSDN recommends using _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 位编译我的项目吗?
您需要将编译器升级到支持 _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
如果您使用的是 Visual Studio 2008 年的 MASM 版本,您可能需要注释掉 RDRAND 指令并取消注释后面的 DB 指令。
哇,我花了一段时间才弄明白。以下是 Visual Studio 2008 仅用于 x64
编译的步骤:
(A) 创建一个空白项目:文件 -> 新建 -> 项目。然后点击 "Visual C++" 和 select "Empty Project." 给它起个名字,然后点击确定创建。
(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) 右键单击 "Solution Explorer" 和 select "Custom build rules" 中的项目并选中 x64 Microsoft Macro Assembler
并单击确定.
(E) 在 "Solution Explorer" 中右键单击您的项目,然后 select 添加 -> 新项目,select Text File (.txt)
并将其命名为 .asm
扩展名。我称之为 funcs_asm_x64.asm
。然后点击确定。
(F) 打开 funcs_asm_x64.asm
并输入你的 x64 asm。对我来说,我对使用 64 位操作数调用 RDRAND
很感兴趣。我做了以下事情。该函数将一个参数作为指向一个 64 位整数的指针,它将用随机位填充。如果成功它将 return 1 in rax
,否则它将 return 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)然后在"Solution Explorer"中右击你的项目,select添加->新建项,selectC++ File (.cpp)
并命名为main.cpp
,点击确定创建。然后将以下内容添加到 main.cpp
文件中:
extern "C" __int64 __fastcall RdRand64(unsigned __int64* pRndVal);
void main()
{
}
主要部分是extern "C"
定义。 main()
需要方法来满足 MASM 要求。
(H) 然后转到构建 -> 配置管理器并打开显示 "Active solution platform" 和 select 新建的下拉列表。然后在 "Type or select the new platform" 中选择 "x64" 并单击确定。然后 select "x64" as "Active solution platform" 还有 select "Release" in "Active solution configuration."
(I) 关闭配置管理器 window 并构建解决方案。如果成功,请在 \x64\Release
文件夹中寻找 funcs_asm_x64.obj
文件作为您的解决方案。将该文件复制到您的主解决方案文件夹中(您需要在其中使用 RDRAND
指令。)
(J) 然后在您需要使用 RDRAND
指令的主要解决方案中,右键单击 "Solution Explorer" 中的项目并转到特性。然后转到链接器 -> 命令行并添加您的 obj 文件名。显然只对 Debug
和 Release
的 x64
平台这样做。在我的例子中是 funcs_asm_x64.obj
。点击确定保存。
(K) 然后要使用我刚刚创建的函数,首先添加 extern "C"
定义,就像您在第一个项目中所做的那样:
extern "C" __int64 __fastcall RdRand64(unsigned __int64* pRndVal);
然后你可以这样调用它(显然它不能内联):
unsigned __int64 randomNumber = 0;
__int64 bResult = RdRand64(&randomNumber);
(1) 显然以上所有内容对于 Win32
或 x86
构建都不是必需的。为此,只需使用我在原始 post.
(2) 同样显然您需要调用 __cpuid
命令以确保支持 RDRAND
指令。在许多 CPU 上,它仍然不是。所以如果不是,那么不要调用我的 RdRand64
方法,因为它会崩溃!您可以使用此代码检查结果并将其存储在全局变量中的某处:
#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;
}
(3) 有一种方法可以将asm
文件包含在VS 2008
的同一个项目中。不幸的是,如果您这样做,您将无法将项目切换回 Win32
并在需要时进行编译。因此,如果您仅为 x64
编译它,则保存一个步骤并在同一解决方案中完成所有操作。
这相当简单,尽管是间接的:为 _rdrand64_step
创建一个小型 C 包装器,使用 VS2012 将其编译成一个 .OBJ 文件,没有花哨的选项(没有 /LTCG,没有 /Gs 等),并且 link 这个目标文件按原样放入你的 VS2008 项目中。 VS2008编译器可能不知道指令,但是VS2008linker不关心