错误:无效的“ asm”:%字母后缺少操作数

时间:2019-04-19 21:59:39

标签: c gcc x86 inline-assembly rdrand

我正在尝试编写此内联程序集,该内联程序集使用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

1 个答案:

答案 0 :(得分:2)

如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。
-The ja instruction既检查来自rdrand指令的C标志,又检查来自dec的Z标志。与第二个示例一样,这可能不如使用两个单独的分支有效,具体取决于合并两个部分寄存器的成本。我确定彼得可以提供详细信息。 (彼得说:在新的足以拥有RDRAND的CPU上,没有部分标志停滞应该没事。)

以下是问题代码中的问题列表:
-不要在%%寄存器名称上使用ecx前缀。
-使用ecx,不加掩饰。
-检查CF = 0是否是rdrand而不是CF = 1的结果。
-使用不在嵌入式程序集中的标签名称。
-不使用输出寄存器。
-返回零以指示超时,而不使用单独的错误指示。 [注意,我没有解决这个问题。]
-使用loop指令。
-在内联汇编中使用ret指令。