Мне нужно получить случайное число от генератора случайных чисел Intel в процессоре (Intel Core i3). Я не хочу использовать какую-либо библиотеку. Я хочу использовать пасту ассемблера в C++, но я не знаю, какие регистры и инструкции следует использовать.
Как я могу получить случайное число от процессора Intel с помощью ассемблера?
Ответы (2)
Вызов инструкции RDRAND
на поддерживаемых процессорах (в настоящее время только на процессорах Ivy Bridge и Haswell Intel) поместит случайное значение в указанный регистр. Например, это даст вам случайное 64-битное значение:
RDRAND %rax
В случае успеха будет установлен бит переноса. Дополнительную информацию см. в Руководстве по внедрению программного обеспечения Bull Mountain. («Bull Mountain» — это кодовое название аппаратного ГСЧ Intel.)
... но я не знаю, какие регистры и инструкции следует использовать.
Ниже показан встроенный ассемблер, который я использую на машинах Linux с GCC. Я считаю, что я скопировал значительную часть из руководства Intel. Вероятно, его написал Дэвид Джонстон, который дает замечательные технические ответы на rdand вопросы. Он также занимается разработкой аппаратного обеспечения в Intel.
int RDRAND_bytes(byte* buff, size_t bsize)
{
if (!HasRDRAND())
return -1;
size_t idx = 0, rem = bsize;
size_t safety = bsize / sizeof(unsigned int) + 4;
unsigned int val;
while (rem > 0 && safety > 0)
{
char rc;
__asm__ volatile(
"rdrand %0 ; setc %1"
: "=r" (val), "=qm" (rc)
);
// 1 = success, 0 = underflow
if (rc)
{
size_t cnt = (rem < sizeof(val) ? rem : sizeof(val));
memcpy(buff + idx, &val, cnt);
rem -= cnt;
idx += cnt;
}
else
{
safety--;
}
}
// Wipe temp on exit
*((volatile unsigned int*)&val) = 0;
// 0 = success; non-0 = failure (possibly partial failure).
return (int)(bsize - rem);
}
А приведенный ниже код используется для HasRDRAND
. Он обнаруживает как процессоры AMD, так и процессоры Intel (я думаю, что это все процессоры, поддерживающие RDRAND).
struct CPUIDinfo {
unsigned int EAX;
unsigned int EBX;
unsigned int ECX;
unsigned int EDX;
};
// Be careful below. EBX/RBX needs to be preserved depending on the memory model and use of PIC.
void cpuid_info(CPUIDinfo *info, const unsigned int func, const unsigned int subfunc) {
__asm__ __volatile__ (
"cpuid"
: "=a"(info->EAX), "=b"(info->EBX), "=c"(info->ECX), "=d"(info->EDX)
: "a"(func), "c"(subfunc)
);
}
int HasAmdCpu() {
CPUIDinfo info;
cpuid_info(&info, 0, 0);
if (memcmp((char *) (&info.EBX), "htuA", 4) == 0
&& memcmp((char *) (&info.EDX), "itne", 4) == 0
&& memcmp((char *) (&info.ECX), "DMAc", 4) == 0) {
return 1;
}
int HasIntelCpu() {
CPUIDinfo info;
cpuid_info(&info, 0, 0);
if (memcmp((char *) (&info.EBX), "Genu", 4) == 0
&& memcmp((char *) (&info.EDX), "ineI", 4) == 0
&& memcmp((char *) (&info.ECX), "ntel", 4) == 0) {
return 1;
}
return 0;
}
int HasRDRAND() {
if (!HasAmdCpu() || !HasIntelCpu())
return 0;
CPUIDinfo info;
cpuid_info(&info, 1, 0);
static const unsigned int RDRAND_FLAG = (1 << 30);
if ((info.ECX & RDRAND_FLAG) == RDRAND_FLAG)
return 1;
return 0;
}
Также см. Как использовать встроенные функции RDRAND? Это не отвечает на ваш непосредственный вопрос, но может быть альтернативой для вас (и может помочь другие).
RDRAND
для AMD см. в Руководстве программиста по архитектуре AMD64, том 3: Общие и системные Инструкции.
- person jww; 12.10.2015