К счастью rdrand
принимает только один аргумент, и это регистр. Таким образом, вам нужно охватить лишь несколько случаев, если вы хотите, чтобы компилятор мог свободно выбирать. Осторожно, это все еще довольно некрасиво:)
inline int rdrand()
{
int result;
__asm__ __volatile__ (
".byte 0x0f, 0xc7\n\t"
".ifc %0, %%eax\n\t"
".byte 0xf0\n\t"
".else\n\t"
".ifc %0, %%ebx\n\t"
".byte 0xf3\n\t"
".else\n\t"
".ifc %0, %%ecx\n\t"
".byte 0xf1\n\t"
".else\n\t"
".ifc %0, %%edx\n\t"
".byte 0xf2\n\t"
".else\n\t"
".ifc %0, %%esi\n\t"
".byte 0xf6\n\t"
".else\n\t"
".ifc %0, %%edi\n\t"
".byte 0xf7\n\t"
".else\n\t"
".ifc %0, %%ebp\n\t"
".byte 0xf5\n\t"
".else\n\t"
".error \"uknown register\"\n\t"
".endif\n\t"
".endif\n\t"
".endif\n\t"
".endif\n\t"
".endif\n\t"
".endif\n\t"
".endif\n\t"
: "=R" (result) : : "cc");
// "=R" excludes r8d..r15d in 64-bit mode
return result;
}
Для 64-битного размера операнда вам понадобится префикс REX.W (0x48), но ограничение "=R"
вместо "=r"
позволит избежать использования других битов, установленных в Префикс REX.
Обратите внимание, что rdrand
также использует флаг переноса, обработка которого оставлена в качестве упражнения для читателя. gcc6 может использовать операнды вывода флага, что более эффективно, чем setcc
.