我遇到了这段代码,需要了解它在做什么。它似乎只是在声明两个字节然后什么都不做......
uint64_t x;
__asm__ __volatile__ (".byte 0x0f, 0x31" : "=A" (x));
谢谢!
我遇到了这段代码,需要了解它在做什么。它似乎只是在声明两个字节然后什么都不做......
uint64_t x;
__asm__ __volatile__ (".byte 0x0f, 0x31" : "=A" (x));
谢谢!
这是直接在代码流中生成两个字节(0F 31)。这是一条 RDTSC 指令,它将时间戳计数器读入 EDX:EAX,然后通过输出约束“=A”(x) 将其复制到变量“x”中
0F 31 是 RDTSC(读取时间戳计数器)指令的 x86 操作码;它将读取的值放入 EDX 和 EAX 寄存器。
__ asm__ 指令不只是声明两个字节,而是将内联汇编放入 C 代码中。据推测,程序有一种方法可以在之后立即使用这些寄存器中的值。
它正在插入一个 0F 31 操作码,根据本网站,它是:
0F 31 P1+ f2 RDTSC EAX EDX IA32_T... Read Time-Stamp Counter
然后它将结果存储在x
变量中
它是 inline asm forrdtsc
,写出机器代码编码以支持不知道助记符的真正古老的汇编程序。
不幸的是,它只能在 32 位代码中正常工作,因为"=A"
在 64 位代码中不会将 64 位操作数分成两半。(gcc 手册甚至使用rdtsc
了一个例子来说明这一点)
编写此代码(使用 gcc -m32 或 -m64 编译为最佳代码)的安全方法是:
#include <stdint.h>
uint64_t timestamp_safe(void)
{
unsigned long tsc_low, tsc_high; // not uint32_t: saves a zero-extend for -m64 (but not x32 :/)
asm volatile("rdtsc" : "=d"(tsc_high), "=a" (tsc_low));
return ((uint64_t)tsc_high << 32) | tsc_low;
}
在 32 位代码中,它只是rdtsc
/ ret
,但在 64 位代码中,它会进行必要的移位/或将两半都放入rax
返回值。
在Godbolt 编译器资源管理器上查看它。