哪个内联汇编代码对于rdtscp是正确的?

Jam*_*mes 14 assembly gcc x86-64 inline-assembly

免责声明:单词无法描述我厌恶AT&T风格的语法

我有一个问题,我希望是由寄存器clobbering引起的.如果没有,我有一个更大的问题.

我使用的第一个版本是

static unsigned long long rdtscp(void)
{
    unsigned int hi, lo;
    __asm__ __volatile__("rdtscp" : "=a"(lo), "=d"(hi));
    return (unsigned long long)lo | ((unsigned long long)hi << 32);
}
Run Code Online (Sandbox Code Playgroud)

我注意到这个版本中没有'破坏'的东西.这是否是一个我不知道的问题...我想这取决于编译器是否内联函数.使用此版本会导致我无法始终重现的问题.

我发现的下一个版本是

static unsigned long long rdtscp(void)
{
    unsigned long long tsc;
    __asm__ __volatile__(
        "rdtscp;"
        "shl $32, %%rdx;"
        "or %%rdx, %%rax"
        : "=a"(tsc)
        :
        : "%rcx", "%rdx");

    return tsc;
}
Run Code Online (Sandbox Code Playgroud)

这是令人安心的不可读和官方的看,但就像我说我的问题并不总是可重复的所以我只是试图排除我的问题的一个可能的原因.

认为第一个版本存在问题的原因是它覆盖了以前持有函数参数的寄存器.

什么是正确的...版本1,或版本2,或两者兼而有之?

amd*_*mdn 20

这是C++代码,它将返回TSC并将辅助32位存储到引用参数中

static inline uint64_t rdtscp( uint32_t & aux )
{
    uint64_t rax,rdx;
    asm volatile ( "rdtscp\n" : "=a" (rax), "=d" (rdx), "=c" (aux) : : );
    return (rdx << 32) + rax;
}
Run Code Online (Sandbox Code Playgroud)

最好在C++语句中进行shiftadd合并两个32位的一半,而不是内联,这允许编译器按照它认为合适的方式调度这些指令.

  • 是的,"= c"规范告诉编译器ECX将保持输出,这意味着它被破坏了 (4认同)
  • 简要解释为什么我们需要函数的“aux”参数? (3认同)
  • 有时可以参考使用此类型代码的地方...因此,例如,请查看http://lxr.free-electrons.com/source/arch/x86/include/asm/msr .h#L205和http://lxr.free-electrons.com/source/arch/x86/include/asm/msr.h#L42(“rdtscp”的操作码是此处给出的字节序列)。 (2认同)