我正在尝试在 GCC 中使用以下代码。抛出错误(我猜是因为__asm
)。为什么这种简单易用的格式在 GCC 中不起作用?此处提供Syntax of extended assembly。当在内联汇编中使用更多变量时,我感到困惑。有些人可以将以下程序转换为适当的形式,并在有变量使用的地方给出必要的解释。
int time, subtime;
float x = 5.0f;
__asm {
cpuid
rdtsc
mov subtime, eax
cpuid
rdtsc
sub eax, subtime
mov subtime, eax // Only the last value of subtime is kept
// subtime should now represent the overhead cost of the
// MOV and CPUID instructions
fld x
fld x
cpuid // Serialize execution
rdtsc // Read time stamp to EAX
mov time, eax
fdiv // Perform division
cpuid // Serialize again for time-stamp read
rdtsc
sub eax, time // Find the difference
mov time, eax
}
任何简单和更好的链接将使我能够学习这种内联汇编编程,也赞赏。
答案 0 :(得分:5)
您的问题实际上是一个代码转换问题,它通常是Stackoverflow的主题。然而,答案可能对其他读者有益。
此代码是原始素材的转换,并不代表增强功能。实际的 FDIV / FDIVP 和 FLD 可以简化为单个 FLD 和 FDIV < / em> / FDIVP ,因为您要自己划分浮点值。正如Peter Cordes所指出的那样,你可以用FLD1加载值为1.0的堆栈顶部。这可以起作用,因为将任何数字除以它自己(除了0.0)将花费相同的时间来划分5.0本身。这样就不需要将变量x
传递给汇编程序模板了。
您使用的代码是20年前Pentium II的documented by Intel变体。描述了该处理器的内容。不同之处在于您使用的代码不会执行该文档中描述的预热。我不相信这种机制在现代处理器和操作系统上会运行得很好(被警告)。
相关代码旨在衡量单个 FDIV指令完成所需的时间。假设您确实要转换此特定代码,则必须使用 GCC extended assembler templates。扩展的汇编程序模板首次使用 GCC 开发人员并不容易。对于汇编代码,您甚至可以考虑将代码放入单独的汇编文件中,单独汇编,然后从 C 调用它。
汇编程序模板使用input constraints和output constraints将数据传入和传出模板(与MSVC不同)。它还使用clobber list来指定可能已被更改的寄存器#39; t显示为输入或输出。默认情况下, GCC 内联汇编使用ATT syntax而不是 INTEL 。
使用带有ATT语法的扩展汇编程序的等效代码可能如下所示:
#include <stdio.h>
int main()
{
int time, subtime;
float x = 5.0f;
int temptime;
__asm__ (
"rdtsc\n\t"
"mov %%eax, %[subtime]\n\t"
"cpuid\n\t"
"rdtsc\n\t"
"sub %[subtime], %%eax\n\t"
"mov %%eax, %[subtime]\n\t"
/* Only the last value of subtime is kept
* subtime should now represent the overhead cost of the
* MOV and CPUID instructions */
"flds %[x]\n\t"
"flds %[x]\n\t" /* Alternatively use fst to make copy */
"cpuid\n\t" /* Serialize execution */
"rdtsc\n\t" /* Read time stamp to EAX */
"mov %%eax, %[temptime]\n\t"
"fdivp\n\t" /* Perform division */
"cpuid\n\t" /* Serialize again for time-stamp read */
"rdtsc\n\t"
"sub %[temptime], %%eax\n\t"
"fstp %%st(0)\n\t" /* Need to clear FPU stack before returning */
: [time]"=a"(time), /* 'time' is returned via the EAX register */
[subtime]"=r"(subtime), /* return reg for subtime */
[temptime]"=r"(temptime) /* Temporary reg for computation
This allows compiler to choose
a register for temporary use. Register
only for BOTH so subtime and temptime
calc are based on a mov reg, reg */
: [x]"m"(x) /* X is a MEMORY reference (required by FLD) */
: "ebx", "ecx", "edx"); /* Registers clobbered by CPUID
but not listed as input/output
operands */
time = time - subtime; /* Subtract the overhead */
printf ("%d\n", time); /* Print total time of divide to screen */
return 0;
}
答案 1 :(得分:1)
gcc,icc和visual c,它们对于内联汇编程序的语法都非常不同(这不是C标准的一部分)。 GCC有点复杂,但也更高效,因为你告诉编译器哪些寄存器用于什么,以及哪些寄存器被破坏(使用)。
https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
https://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html
http://asm.sourceforge.net/articles/rmiyagi-inline-asm.txt
我的gcc汇编程序有点生疏(自从我使用它以来的几年),所以可能会有一些错误
int main(int argc, char *argv[])
{
int time=0, subtime = 100;
const float x = 5.0f;
asm (
"xorl %%eax, %%eax \n" /* make sure eax is a known value befeore cpuid */
"cpuid \n"
"rdtsc \n"
"movl %%eax, %[aSubtime] \n"
"cpuid \n"
"rdtsc \n"
"subl %[aSubtime], %%eax \n"
// subtime should now represent the overhead cost of the
// MOV and CPUID instructions
"fld %[ax] \n"
"fld %[ax] \n"
"cpuid \n" // Serialize execution
"rdtsc \n" // Read time stamp to EAX
"movl %%eax, %[atime] \n"
"fdivp \n" // Perform division
"cpuid \n" // Serialize again for time-stamp read
"rdtsc \n"
"subl %[atime], %%eax \n"
// "movl %%eax, %2 \n" Not needed, since we tell the compiler that asm exists with time in eax
: "=a" (time) /* time is outputed in eax */
: [aSubtime] "m" (subtime),
[ax] "m" (x),
[atime] "m" (time)
: "ebx", "ecx", "edx"
);
/* FPU is currently left in a pushed state here */
return 0;
}