Как добавить инструкцию RDRAND в 64-битный код, скомпилированный с VS 2008?

Я работаю над проектом 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 инструкция?

1

Решение

Вам нужно либо обновить свой компилятор до того, который поддерживает _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.

5

Другие решения

Вау, мне понадобилось время, чтобы понять это. Вот шаги для 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 затем сохраните шаг и сделайте все это в одном решении.

0

Это довольно просто, хотя и косвенно: создайте крошечную оболочку C для _rdrand64_step, скомпилируйте его в файл .OBJ, используя VS2012 без каких-либо необычных опций (No / LTCG, no / Gs и т. д.), и свяжите этот объектный файл как есть с вашим проектом VS2008. Компилятор VS2008 может не знать инструкции, но компоновщик VS2008 не заботится.

0
По вопросам рекламы [email protected]