如何在 C 的内联汇编中将 %edx 指定为输出而不是常规的 %eax?
How to specify %edx to be the output instead of conventional %eax in inline assembly in C?
我正在尝试使用 C 中的以下内联汇编来读取时间戳计数器的高位字 (%edx
) 以进行时间测量:
unsigned int tsc;
asm volatile ("rdtscp; xchgl %%edx, %%eax" : "=r" (tsc));
不幸的是,代码崩溃了。如果去掉xchgl
指令,或者使用rdtsc
指令,都没有问题。对于前者,虽然代码没有崩溃,但是我没有办法取出我想要的——%edx
寄存器中的值。我已经检查了一个在线 document 关于 C 中的内联汇编但是没有找到任何线索 return %edx
中的值直接到输出 C 变量而不需要任何额外的指令(如果我改变 xchgl
到 movl
,同样的崩溃发生)。怀着一点希望,我错过了任何语法或没有正确理解文档,我来这里问:有没有办法指定 %edx
寄存器作为输出而不是常规的 %eax
in inline assembly in C?谢谢。
PS1:我正在 Linux 上工作,它与英特尔 i386 兼容 CPU,它的 TSC 对我来说工作得很好。
PS2:出于某种原因,我只需要 %edx
.
中的值
您需要将寄存器指定为约束,以告诉编译器它必须选择一个特定的寄存器。
unsigned int tsc;
asm volatile ("rdtsc" : "=d" (tsc) : : "eax");
"d" 是作为输出操作数的 edx 寄存器。 “a”是 clobber 列表中的 eax 寄存器,因为它的内容已被指令更改。中间有两个冒号,因为没有输入操作数。
你的“=r”让编译器选择任何寄存器;它只是碰巧在一个没有内联的函数中的调试版本中选择了 EAX。您还需要告诉编译器所有其他已修改的寄存器,即使您不希望它们作为输出;除非您另有说明,否则编译器假定所有寄存器和内存均未修改且未读取。 https://whosebug.com/tags/inline-assembly/info
通常您会使用内在函数 instead of inline asm 以实现可移植性并避免混淆 asm:
How to get the CPU cycle count in x86_64 from C++?
但是如果您确实希望安全内联 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;它只会与 unsigned __int128
.
// Beware: breaks silently if compiled as 64-bit code
unsigned long long tsc;
asm volatile ("rdtsc" : "=A" (tsc));
我正在尝试使用 C 中的以下内联汇编来读取时间戳计数器的高位字 (%edx
) 以进行时间测量:
unsigned int tsc;
asm volatile ("rdtscp; xchgl %%edx, %%eax" : "=r" (tsc));
不幸的是,代码崩溃了。如果去掉xchgl
指令,或者使用rdtsc
指令,都没有问题。对于前者,虽然代码没有崩溃,但是我没有办法取出我想要的——%edx
寄存器中的值。我已经检查了一个在线 document 关于 C 中的内联汇编但是没有找到任何线索 return %edx
中的值直接到输出 C 变量而不需要任何额外的指令(如果我改变 xchgl
到 movl
,同样的崩溃发生)。怀着一点希望,我错过了任何语法或没有正确理解文档,我来这里问:有没有办法指定 %edx
寄存器作为输出而不是常规的 %eax
in inline assembly in C?谢谢。
PS1:我正在 Linux 上工作,它与英特尔 i386 兼容 CPU,它的 TSC 对我来说工作得很好。
PS2:出于某种原因,我只需要 %edx
.
您需要将寄存器指定为约束,以告诉编译器它必须选择一个特定的寄存器。
unsigned int tsc;
asm volatile ("rdtsc" : "=d" (tsc) : : "eax");
"d" 是作为输出操作数的 edx 寄存器。 “a”是 clobber 列表中的 eax 寄存器,因为它的内容已被指令更改。中间有两个冒号,因为没有输入操作数。
你的“=r”让编译器选择任何寄存器;它只是碰巧在一个没有内联的函数中的调试版本中选择了 EAX。您还需要告诉编译器所有其他已修改的寄存器,即使您不希望它们作为输出;除非您另有说明,否则编译器假定所有寄存器和内存均未修改且未读取。 https://whosebug.com/tags/inline-assembly/info
通常您会使用内在函数 instead of inline asm 以实现可移植性并避免混淆 asm:
How to get the CPU cycle count in x86_64 from C++?
但是如果您确实希望安全内联 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;它只会与 unsigned __int128
.
// Beware: breaks silently if compiled as 64-bit code
unsigned long long tsc;
asm volatile ("rdtsc" : "=A" (tsc));