Я работаю над проектом C ++ в Visual Studio 2008 IDE, где мне нужно использовать новый Intel 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
}
А на х64 asm
не поддерживается.
Можете ли вы предложить, как я могу скомпилировать мой проект для 64-битной с RDRAND
инструкция?
Вам нужно либо обновить свой компилятор до того, который поддерживает _rdrand64_step
intrinsic (поддерживается начиная с 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
Если вы используете версию MASM из Visual Studio 2008, вам, вероятно, придется закомментировать инструкции RDRAND и раскомментировать следующие за ними директивы DB.
Вау, мне понадобилось время, чтобы понять это. Вот шаги для Visual Studio 2008 для x64
только компиляция:
(А) Создайте пустой проект: Файл -> Новый -> Проект. Затем нажмите «Visual C ++» и выберите «Пустой проект». Назовите его как-нибудь и нажмите OK, чтобы создать.
(В) Перейдите в папку установки VS, в моем случае это было C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\VCProjectDefaults
и скопировать masm.rules
файл и назовите его masm64.rules
(С) открыто masm64.rules
в блокноте и поиск Microsoft Macro Assembler
и изменить его на x64 Microsoft Macro Assembler
, Там будет два места, чтобы сделать это. Тогда ищите ml.exe
и изменить его на ml64.exe
, Затем сохраните этот файл и закройте Блокнот.
(D) Щелкните правой кнопкой мыши свой проект в «Обозревателе решений», выберите «Пользовательские правила сборки» и проверьте x64 Microsoft Macro Assembler
и нажмите ОК.
(Е) Щелкните правой кнопкой мыши свой проект в «Обозревателе решений» и выберите «Добавить» -> «Новый элемент», выберите Text File (.txt)
и назвать это что-то с .asm
расширение. Я позвоню funcs_asm_x64.asm
, Затем нажмите ОК.
(F) открыто funcs_asm_x64.asm
и введите свой x64 asm. Для меня было интересно звонить RDRAND
с 64-битным операндом. Я сделал следующее. Эта функция будет принимать один параметр в качестве указателя на 64-разрядное целое число, которое будет заполняться случайными битами. Вернется 1 в rax
если успех, в противном случае он вернет 0.
Здесь следует помнить, что код x64 использует только __fastcall
соглашение о вызовах, это означает, что первые 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
(Г) Затем щелкните правой кнопкой мыши свой проект в «Обозревателе решений» и выберите «Добавить» -> «Новый элемент», выберите C++ File (.cpp)
и назовите это main.cpp
и нажмите OK, чтобы создать. Затем добавьте следующее к main.cpp
файл:
extern "C" __int64 __fastcall RdRand64(unsigned __int64* pRndVal);
void main()
{
}
Основная часть extern "C"
определение. main()
метод необходим для удовлетворения требований MASM.
(ЧАС) Затем перейдите в Build -> Configuration Manager и откройте выпадающий список, в котором написано «Платформа активного решения» и выберите New. Затем выберите «x64» в поле «Введите или выберите новую платформу» и нажмите кнопку «ОК». Затем выберите «x64» в качестве «Платформа активного решения», а также выберите «Релиз» в «Конфигурация активного решения».
(Я) Закройте окно диспетчера конфигурации и создайте решение. Если это удалось, ищите funcs_asm_x64.obj
файл в \x64\Release
папка для вашего решения. Скопируйте этот файл в основную папку решения (где вам нужно было использовать RDRAND
инструкция).
(J), Тогда в вашем основном решении, где вам нужно использовать RDRAND
Инструкция, щелкните правой кнопкой мыши по вашему проекту в «Обозревателе решений» и перейдите в Свойства. Затем перейдите в Linker -> Командная строка и добавьте имя вашего файла obj. Очевидно, сделать это только для x64
платформа для Debug
а также Release
, В моем случае это было funcs_asm_x64.obj
, Нажмите OK, чтобы сохранить.
(К) Затем, чтобы использовать эту функцию, которую я только что создал, сначала добавьте extern "C"
определение, как у вас было в первом проекте:
extern "C" __int64 __fastcall RdRand64(unsigned __int64* pRndVal);
и тогда вы можете назвать его таковым (очевидно, он не может быть встроен):
unsigned __int64 randomNumber = 0;
__int64 bResult = RdRand64(&randomNumber);
(1) Очевидно, что все вышеперечисленное не является необходимым для Win32
или же x86
строить. Для этого просто используйте встроенную сборку, как я показал в моем первоначальном посте.
(2) Также, очевидно, вам нужно будет позвонить __cpuid
Команда, чтобы убедиться, что RDRAND
Инструкция поддерживается. На многих процессорах это все еще нет. Так что, если это не так, не называйте мой 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
затем сохраните шаг и сделайте все это в одном решении.
Это довольно просто, хотя и косвенно: создайте крошечную оболочку C для _rdrand64_step
, скомпилируйте его в файл .OBJ, используя VS2012 без каких-либо необычных опций (No / LTCG, no / Gs и т. д.), и свяжите этот объектный файл как есть с вашим проектом VS2008. Компилятор VS2008 может не знать инструкции, но компоновщик VS2008 не заботится.