我正在尝试使用C中的以下内联程序集来读取时间戳计数器的高位字(%edx
(以进行时间测量:
unsigned int tsc;
asm volatile ("rdtscp; xchgl %%edx, %%eax" : "=r" (tsc));
不幸的是,代码崩溃了。如果删除了xchgl
指令,或者使用了rdtsc
指令,则没有问题。对于前者,尽管代码不会崩溃,但我无法取出我想要的东西——%edx
寄存器中的值。我检查了一个关于C中内联程序集的在线文档,但没有找到任何线索,可以在没有任何额外指令的情况下直接将%edx
中的值返回到输出C变量(如果我将xchgl
更改为movl
,也会发生同样的崩溃(。我几乎没有希望错过任何语法或没有正确理解文档,我来到这里想问:有没有办法在C中的内联汇编中指定%edx
寄存器作为输出,而不是传统的%eax
?非常感谢。
PS1:我在Linux上使用英特尔i386兼容的CPU,它的TSC对我来说很好
PS2:出于某种原因,我只需要%edx
中的值。
您需要将寄存器指定为约束,以告诉编译器它必须选择特定的寄存器。
unsigned int tsc;
asm volatile ("rdtsc" : "=d" (tsc) : : "eax");
"d";是作为输出操作数的edx寄存器"a";是clobber列表中的eax寄存器,因为其内容已被指令更改。中间有两个冒号,因为没有输入操作数。
您的"=r〃;让编译器选择任何寄存器;它只是碰巧在调试构建中的一个不内联的函数中选择EAX。您还需要告诉编译器所有其他被修改的寄存器,即使您不希望它们作为输出;编译器假定所有寄存器和内存都未修改且未读,除非您另有指示。https://stackoverflow.com/tags/inline-assembly/info
通常情况下,为了可移植性和避免干扰asm:
如何从C++获得x86_64中的CPU周期计数?
但是,如果您确实希望安全的内联asm在32位和64位上同时获得两半:
unsigned int tsc_hi, tsc_lo;
asm volatile ("rdtsc" : "=a" (tsc_lo), "=d" (tsc_hi));
或者,您可以对32位机器上的edx:eax寄存器对中的值使用"A"约束。但是在64位构建的";A";让编译器为64位整数选择RDX或RAX;则其将仅具有CCD_ 11。
// Beware: breaks silently if compiled as 64-bit code
unsigned long long tsc;
asm volatile ("rdtsc" : "=A" (tsc));