1

我正在尝试编写这个内联程序集,它使用rdrand指令返回一个随机数。该数字存储在eax寄存器中,然后移动到rng_num变量中。但我得到了标题中的错误。

    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");

这是原始的 x86 Intel 语法代码:

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
4

1 回答 1

3

正如 fuz 和 Peter 在评论中提到的那样,正确的答案是不使用内联汇编。

但是这里有几种方法可以在内联汇编中编写它。

    uint32_t rng_num;
    int iterations = 100;
    asm volatile("1: rdrand %0\n\t"
                 "dec %1\n\t"
                 "ja 1b\n\t"    // jump if CF=0 (from rdrand) and ZF=0 (from dec)
                 : "=r" (rng_num), "+r"(iterations));

    // alternative that doesn't need partial-flag merging
    asm volatile("1: rdrand %0\n\t"
                 "jc 2f\n\t"
                 "dec %1\n\t"
                 "jnz 1b\n\t"
                 "2:\n\t"
                 : "=r" (rng_num), "+r"(iterations));

注意:
- 这些依赖于rdrand在失败时将目标设置为 0。
-ja指令同时检查指令中的 C 标志rdranddec. 这可能不如使用两个单独的分支(如在第二个示例中)那样有效,具体取决于组合两个部分寄存器的成本。我相信彼得可以提供详细信息。(Peter 说:在新的足以拥有 RDRAND 的 CPU 上没有部分标志停顿应该没问题。)

以下是问题代码中的问题列表:
- 不在寄存器名称上使用%%前缀。 - 使用没有破坏。 - 检查 CF=0 是否成功,而不是 CF=1。 - 使用非内联程序集本地的标签名称。 - 不使用输出寄存器。 - 返回零以指示超时,而不是使用单独的错误指示。[注意,我没有修复这个。] - 使用指令。 -在内联汇编中使用指令。 ecx
ecx
rdrand



loop
ret

于 2019-04-20T01:12:09.353 回答