【问题标题】:making mistake in inline assembler in gcc [duplicate]gcc中的内联汇编程序出错[重复]
【发布时间】:2011-05-27 06:50:13
【问题描述】:

我已经成功地在 gcc 中编写了一些内联汇编程序来向右旋转一位 遵循一些很好的说明:http://www.cs.dartmouth.edu/~sergey/cs108/2009/gcc-inline-asm.pdf

这是一个例子:

static inline int ror(int v) {
    asm ("ror %0;" :"=r"(v) /* output */ :"0"(v) /* input */ );
    return v;
}

但是,我希望代码计算时钟周期,并且看到了一些错误的(可能是微软的)格式。我不知道如何在 gcc 中做这些事情。有什么帮助吗?

unsigned __int64 inline GetRDTSC() {
   __asm {
      ; Flush the pipeline
      XOR eax, eax
      CPUID
      ; Get RDTSC counter in edx:eax
      RDTSC
   }
}

我试过了:

static inline unsigned long long getClocks() {
    asm("xor %%eax, %%eax" );
    asm(CPUID);
    asm(RDTSC : : %%edx %%eax); //Get RDTSC counter in edx:eax

但我不知道如何让 edx:eax 对以 64 位干净地返回,也不知道如何真正刷新管道。

另外,我找到的最好的源代码是:http://www.strchr.com/performance_measurements_with_rdtsc

那是提到奔腾,所以如果在不同的英特尔/AMD 变体上有不同的方法,请告诉我。我更喜欢适用于所有 x86 平台的东西,即使它有点难看,也更喜欢每个变体的一系列解决方案,但我不介意了解它。

【问题讨论】:

  • 如果我的问题比另一个问题早 2 年被问到,我的问题怎么会是重复的?
  • 可能是因为另一个问题的答案质量更高,并且标记为重复将在顶部提供指向它的链接。

标签: c++ assembly intel clock


【解决方案1】:

这会将结果存储在值中。合并结果需要额外的周期,因此调用此代码之间的周期数将比结果差异少一些。

unsigned int hi,lo;
unsigned long long value;
asm (
    "cpuid\n\t"
    "rdtsc"
    : "d" (hi), "a" (lo)
);
value = (((unsigned long long)hi) << 32) | lo;

【讨论】:

  • 这坏了:你有 hilo 作为输入操作数。如果在禁用优化的情况下编译它可能会起作用,但仅此而已。你也忘了volatile。工作代码见Get CPU cycle count?
【解决方案2】:

以下是你想要的:

inline unsigned long long rdtsc() {
  unsigned int lo, hi;
  asm volatile (
     "cpuid \n"
     "rdtsc" 
   : "=a"(lo), "=d"(hi) /* outputs */
   : "a"(0)             /* inputs */
   : "%ebx", "%ecx");     /* clobbers*/
  return ((unsigned long long)lo) | (((unsigned long long)hi) << 32);
}

在代码中尽可能少地放置内联 ASM 很重要,因为它会阻止编译器进行任何优化。这就是为什么我在 C 代码中完成结果的移位和 oring,而不是在 ASM 中进行编码。同样,我使用 0 的“a”输入让编译器决定何时以及如何将 eax 归零。可能是你程序中的一些其他代码已经将它归零了,如果编译器知道的话,它可以保存一条指令。

另外,上面的“clobbers”也很重要。 CPUID 覆盖 eax、ebx、ecx 和 edx 中的所有内容。您需要告诉编译器您正在更改这些寄存器,以便它知道不要在那里保留任何重要的东西。您不必列出 eax 和 edx,因为您将它们用作输出。如果您不列出这些 clobbers,那么您的程序很可能会崩溃,并且您会发现很难找到问题所在。

【讨论】:

  • 不应该是 %%ebx 和 %%ecx 吗?
  • 这其中的哪一部分强制管道,volatile 或 \n?
  • CPUID 是一个序列化指令。 % 与 %% 与您对内联汇编中的寄存器所做的其他事情有关。我永远不记得什么时候需要,但是如果你做错了编译器会抱怨你。此代码在 GCC 4.4.1 中为我编译。
猜你喜欢
  • 2011-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-20
  • 1970-01-01
  • 2013-09-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多