c语言 - 为什么我应该在 x86 和 x86_x64 上以不同的方式使用'rdtsc'?



我知道rdtsc将处理器时间戳计数器的当前值加载到两个寄存器中:EDX和EAX。为了在x86上实现它,我需要这样做(假设使用Linux):

    unsigned long lo, hi;
    asm( "rdtsc" : "=a" (lo), "=d" (hi));
    return lo;

对于x86_x64:

        unsigned long lo, hi;
        asm( "rdtsc" : "=a" (lo), "=d" (hi) ); 
        return( lo | (hi << 32) );

为什么?有人能向我解释一下吗?

RDTSC总是在EDX和EAX中将其64位结果拆分为高低两半,即使在64位模式下也是如此(请参阅手册),不幸的是,它没有将64位TSC打包为RAX。这就是为什么在asm语句之后需要额外的工作。

要从中生成一个64位整数,需要将hi作为unsigned long的一部分移位到它所属的位置。lo已经在正确的位置,写入这些32位寄存器会将两个寄存器的高位置零,因此我们可以将(移位的)一半进行"或"运算,而不必与低一半进行"与"运算。

在x86-64 Linux中,unsigned long是64位类型,因此内核实际上使用RDTSC返回值的两半。

32位版本更简单的唯一原因是内核通过丢弃高半部分将结果截断为32位。如果您确实希望在32位模式下使用64位TSC,那么相同的C源也可以在那里工作(使用uint64_tunsigned long long),尽管它不会编译为移位和or指令。编译器只知道它有一个64位整数,它的一半在EDX和EAX中。

另请参阅如何从C++获得x86_64中的CPU周期计数?-为了真正使用,别忘了制作这些asm volatile。否则,编译器可以假设重复执行会产生相同的输出,例如优化后的end-start=0。

区别不在于rdtsc,而在于Linux内核想用它做什么

在32位中,它返回一个32位的值。所以eax中的值已经足够好了
在64位中,它返回一个64位值。因此,它需要将两个寄存器中的值组合起来。

相关内容

  • 没有找到相关文章

最新更新