From c6c463ee1a9faac8b1439f62f85033074c18f96f Mon Sep 17 00:00:00 2001 Message-Id: From: Mark Wooding Date: Mon, 6 Jun 2016 11:01:46 +0100 Subject: [PATCH 1/1] rand/rand.c (rdrand_quick): Improve the loop. Organization: Straylight/Edgeware From: Mark Wooding The `RDRAND' instruction can fail, leaving carry clear. Previously, I just exposed the carry flag in a register (with `SETC'), and looped around in C. Rewrite the loop in assembler. This is makes the flow cleaner, and (coincidentally) avoids a dependency on the `SETcc' instructions (though if I thought a processor might have `RDRAND' and not `SETcc', I wouldn't have written the original code the way I did). But the main benefit is that I don't have nightmares about seeing ...; setc al; test al, al; ... sequences any more. There's still the issue of `i' being tested for zero twice, but I don't think I can fix that without resorting to `asm goto', and that has its own problems. --- rand/rand.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/rand/rand.c b/rand/rand.c index 29b180d8..f9f16d5d 100644 --- a/rand/rand.c +++ b/rand/rand.c @@ -165,17 +165,13 @@ static int trivial_quick(rand_pool *r) { return (-1); } static int rdrand_quick(rand_pool *r) { unsigned long rr; - unsigned char w; - int i; - - for (i = 0; i < 16; i++) { - __asm__ ("rdrand %0; setc %1" : "=r" (rr), "=g" (w) : : "cc"); - if (w) { - rand_add(r, &rr, sizeof(rr), 8*sizeof(rr)); - return (0); - } - } - return (-1); + int i = 16; + + __asm__ ("0: rdrand %0; jc 9f; dec %1; jnz 0b; 9:" + : "=r" (rr), "=r" (i) : "1" (i) : "cc"); + if (!i) return (-1); + rand_add(r, &rr, sizeof(rr), 8*sizeof(rr)); + return (0); } #endif -- [mdw]