delphiassemblyrandomopcoderdrand

Using Intel's RdRand opcode in Delphi 6/7


is there a way to use Intel's RdRand opcode in older Delphi versions like 6 or 7?

Maybe using

asm db $... end;

or something? How do I store the number into a variable?

Speed is very important. I can't use an external library for this.


Solution

  • I'm not able to test this since my processor doesn't support RdRand, but this should get you going:

    function RdRand: Cardinal;
    asm
      db  $0f
      db  $c7
      db  $f0
    end;
    

    The opcode for RdRand is 0x0f 0xc7 and the ModR/M value of 0xf0 puts the output into EAX, the function return value.

    Now, this is incomplete. You must also check the value of the carry flag to determine whether or not the RdRand execution succeeded.

    After invoking the RDRAND instruction, the caller must examine the carry flag (CF) to determine whether a random value was available at the time the RDRAND instruction was executed. As Table 3 shows, a value of 1 indicates that a random value was available and placed in the destination register provided in the invocation. A value of 0 indicates that a random value was not available. In current architectures the destination register will also be zeroed as a side effect of this condition.

    So that might lead you to code like this:

    function TryRdRand(out Value: Cardinal): Boolean;
    asm
      db   $0f
      db   $c7
      db   $f1
      jc   @success
      xor  eax,eax
      ret
    @success:
      mov  [eax],ecx
      mov  eax,1
    end;
    

    Again I cannot test it, but I hope it helps you on the way. The ModR/M of 0xf1 puts the output value into ecx which I then copy into [eax] if the operation succeeded.

    The above linked documentation goes on to say:

    It is recommended that applications attempt 10 retries in a tight loop in the unlikely event that the RDRAND instruction does not return a random number. This number is based on a binomial probability argument: given the design margins of the DRNG, the odds of ten failures in a row are astronomically small and would in fact be an indication of a larger CPU issue.

    You can readily implement this retry policy on top of the function above.

    Finally, I'm sure you are aware, but you must make calls to CPUID to check that the processor supports RdRand.