ANT*_*ONY 2 x86 assembly gcc code-conversion visual-c++
我试图在GCC中使用以下代码.它抛出错误(我猜是因为__asm).为什么这种简单易用的格式在GCC中不起作用?这里提供了扩展汇编的语法.当在内联汇编中使用更多变量时,我感到困惑.有人可以将以下程序转换为适当的形式,并在有变量使用的地方给出必要的解释.
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
}
Run Code Online (Sandbox Code Playgroud)
任何简单和更好的链接将使我能够学习这种内联汇编编程,也赞赏.
您的问题实际上是一个代码转换问题,这通常是Stackoverflow的主题.然而,答案可能对其他读者有益.
此代码是原始源材料的转换,并不意味着增强.实际的FDIV/FDIVP和FLD可以简化为单个FLD和FDIV/FDIVP,因为您将浮点值除以自身.正如Peter Cordes所指出的那样,你可以使用FLD1加载值为1.0的堆栈顶部.这可以起作用,因为将任何数字除以它自己(除了0.0)将花费相同的时间来划分5.0本身.这将消除将变量传递x到汇编程序模板的需要.
您使用的代码是20年前英特尔为Pentium II 记录的内容的变体.描述了该处理器的内容.不同之处在于您使用的代码不会执行该文档中描述的预热.我不相信这种机制在现代处理器和操作系统上会运行得太好(需要注意).
有问题的代码旨在测量单个 FDIV指令完成所需的时间.假设您确实想要转换此特定代码,则必须使用GCC 扩展汇编程序模板.扩展的汇编程序模板不容易在第一次使用GCC开发人员时使用.对于汇编代码,您甚至可以考虑将代码放入单独的汇编文件中,单独汇编,然后从C调用它.
汇编程序模板使用输入约束和输出约束将数据传入和传出模板(与MSVC不同).它还使用clobber列表来指定可能已更改但未显示为输入或输出的寄存器.默认情况下,GCC内联汇编使用ATT语法而不是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;
}
Run Code Online (Sandbox Code Playgroud)