【问题标题】:Assembler instruction: rdtsc汇编指令:rdtsc
【发布时间】:2016-04-21 00:10:07
【问题描述】:

谁能帮我理解https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html中给出的汇编器

是这样的:

uint64_t msr;
asm volatile ( "rdtsc\n\t"    // Returns the time in EDX:EAX.
               "shl $32, %%rdx\n\t"  // Shift the upper bits left.
               "or %%rdx, %0"        // 'Or' in the lower bits.
               : "=a" (msr)
               :
               : "rdx");

与以下有何不同:

uint64_t msr;
asm volatile ( "rdtsc\n\t"
               : "=a" (msr));

为什么我们需要 shift 和 or 操作,rdx 到底是做什么的?

编辑:在原始问题中添加了仍不清楚的内容。

  • “\n\t”有什么作用?
  • “:”是做什么的?
    • 分隔符输出/输入/clobbers...
  • 最后的rdx是否等于0?

只是回顾一下。第一行将时间戳加载到寄存器 eax 和 edx 中。第二行移动 eax 中的值并存储在 rdx 中。第三行将 edx 中的值与 rdx 中的值进行运算,并将其保存在 rdx 中。第四行将 rdx 中的值分配给我的变量。最后一行将 rdx 设置为 0。

  • 为什么前三行没有“:”?
    • 它们是一个模板。第一行“:”是输出,第二行是可选输入,第三行是可选的clobbers列表(更改的寄存器)。
  • 实际上是 eax 和 d - edx 吗?这是硬编码的吗?

再次感谢! :)

EDIT2:回答了我的一些问题...

【问题讨论】:

  • 实际使用见Get CPU cycle count?。 (@Mysticial 的回答正确地将移位 / OR 留给了编译器,只将 rdtsc 放在内联汇编中。我的回答建议使用 __rdtsc() 内在代替。不过,不是重复的,因为这个问题是关于使用它来学习内联汇编例如,实际上并不是如何实现 rdtsc。

标签: gcc assembly x86 timestamp rdtsc


【解决方案1】:
uint64_t msr;
asm volatile ( "rdtsc\n\t"    // Returns the time in EDX:EAX.
               "shl $32, %%rdx\n\t"  // Shift the upper bits left.
               "or %%rdx, %0"        // 'Or' in the lower bits.
               : "=a" (msr)
               :
               : "rdx");

因为rdtsc 指令返回它的结果是edxeax,而不是 64 位机器上的直接 64 位寄存器(有关更多信息,请参阅英特尔系统的编程手册;它是 x86 指令),第 2 个 指令将rdx 寄存器向左移动32 位,这样edx 将位于高32 位而不是低32 位。
"=a" (msr) 会将eax 的内容移动到msr%0),即它的低 32 位,所以总共有 edx(高 32 位)和 eax(低 32 位)到 rdx,即 msr
rdx 是一个 clobber,它将代表 msr C 变量。

这类似于在 C 中执行以下操作:

static inline uint64_t rdtsc(void)
{
    uint32_t eax, edx;
    asm volatile("rdtsc\n\t", "=a" (eax), "=d" (edx));
    return (uint64_t)eax | (uint64_t)edx << 32;
}

还有:

uint64_t msr;
asm volatile ( "rdtsc\n\t"
               : "=a" (msr));

这个,只会给你eax的内容变成msr

编辑:

1) "\n\t" 是为了让生成的程序集看起来更清晰且没有错误,这样你就不会得到movl $1, %eaxmovl $2, %ebx这样的东西
2) 最后的 rdx 是否等于 0? 左移会这样做,它会删除 rdx 中已经存在的位。
3) 实际上是 eax 和 d - edx 吗?这是硬编码的吗? 是的,有一个表格描述了哪些字符代表什么寄存器,例如“D”是rdi,“c”是ecx,...

【讨论】:

  • 我不太确定我们如何使用 rdx,而不是最后将 eax 分配给变量。我的逻辑是:1)第一行在 eax 和 edx 中加载时间戳。 2) 第二行将 eax 中的值左移 32 并存储到 rdx。 3) 第三行 ors edx 和 rdx 中的值并存储到 rdx 中。 4) 第四行返回 eax 作为输出。我哪里错了???
  • 2) 第二行将 rdx 移动 32 位,因此 edx 现在位于 rdx 的高 32 位而不是低位,然后您在 eax 中进行 OR msr aka rdx 的低位,并且由于“=a (msr)”,您一开始将 eax 存储在其中,希望可以清楚地说明。
  • @Leta:请接受接受一个可接受的答案不仅是可以接受的,而且是有礼貌的,并且是某种强制性的接受。在评论部分感谢某人是不够的。
  • 对不起,完全忘记了... :)
  • 我已经更新了我的答案,以便更容易理解,对不起。
【解决方案2】:

rdtsc 在一对 32 位寄存器(EDX 和 EAX)中返回时间戳。首先 sn-p 将它们组合成单个 64 位寄存器 (RDX),映射到 msr 变量。

第二个 sn-p 是错误的。我不确定会发生什么:要么根本不编译,要么只更新 msr 变量的一部分。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-27
    • 2011-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-06
    • 2014-05-28
    相关资源
    最近更新 更多