I'm trying to write this inline assembly, which returns a random number using the rdrand instruction. The number is stored in the eax register, and then moved to the rng_num variable. But I get the error that is in the title.
uint32_t rng_num;
asm volatile("movl $100, %ecx\n\t"
"__trng_cpu_ret:\n\t"
"rdrand %%eax\n\t"
"jnc .__trng_cpu_end\n\t"
"loop __trng_cpu_ret\n\t"
".__trng_cpu_fail:\n\t"
"movl $0, %%eax\n\t"
".__trng_cpu_end:\n\t"
"ret\n\t"
: "=r" (rng_num)
:
:"%eax");
This is the original x86 Intel syntax code:
mov ecx, 100 ;number of retries
retry:
rdrand eax
jnc .done ;carry flag is clear on success
loop retry
.fail:
;no random number available
.done:
;random number is is EAX
The correct answer, as mentioned by fuz and Peter in the comments, is to not use inline assembly.
But here are a couple ways to write this in inline assembly.
Notes:
- These rely on
rdrandsetting the destination to 0 when it fails.- The
jainstruction checks both the C flag from therdrandinstruction and also the Z flag from thedec. This may be less efficient than using two separate branches, as in the second example, depending on the cost of combining the two partial registers. I'm sure Peter can provide details. (Peter says: no partial flag stalls on CPUs new enough to have RDRAND, should be fine.)Here's a list of problems in the code in the question:
- Doesn't use
%%prefix onecxregister name.- Uses
ecxwithout a clobber.- Checks CF=0 for success of
rdrandinstead of CF=1.- Uses label names that are not local to the inline assembly.
- Doesn't use output register.
- Returns zero to indicate timeout instead of using a separate error indication. [Note, I didn't fix this one.]
- Uses
loopinstruction.- Uses
retinstruction within inline assembly.