Visual studio intel/AT&;双asm方言项目的问题;T
我正在从事一个项目,该项目需要同时使用QNX Momentics(基于eclipse,g++4.6.1工具链)和Visual Studio 2010进行编译。对于一些例程,我决定采用手动汇编实现,因为即使是内部函数也没有得到很好的优化。第一个编译器具有ATt&T语法,可以使用-masm=intel标志“intelized”,第二个编译器仅使用intel方言 使用intel标志,我可以通过一个——不好但有效——定义的技巧超越符号方面:Visual studio intel/AT&;双asm方言项目的问题;T,visual-studio,gcc,assembly,intel,inline-assembly,Visual Studio,Gcc,Assembly,Intel,Inline Assembly,我正在从事一个项目,该项目需要同时使用QNX Momentics(基于eclipse,g++4.6.1工具链)和Visual Studio 2010进行编译。对于一些例程,我决定采用手动汇编实现,因为即使是内部函数也没有得到很好的优化。第一个编译器具有ATt&T语法,可以使用-masm=intel标志“intelized”,第二个编译器仅使用intel方言 使用intel标志,我可以通过一个——不好但有效——定义的技巧超越符号方面: #ifdef _WIN32 #define _cmd(
#ifdef _WIN32
#define _cmd(...) __VA_ARGS__
__asm {
#else
#define _cmd(...) #__VA_ARGS__
asm volatile (
#endif
// constants
// set loop counter
_cmd( xor eax, eax; )
:
:
#ifdef _WIN32
}
#else
);
#endif
现在,一个问题是,我无法使用内联AT&T按名称访问函数的局部变量或参数
register __m128i x asm("xmm6");
无法使用局部变量,它被分配给xmm0。内部函数未定义的局部变量或参数会导致AT&T中未定义的引用,因此我决定使用裸堆栈处理,例如
_cmd( movupd xmmword ptr [eax], xmm3; )
遇到了一个新问题:
函数参数和局部变量在两种方言中的处理方式完全不同。考虑下面的例子:
template<typename T>
void linearRegression2DAsm(unsigned int p_oNumPoints, T *p_pXcoords, T *p_pYcoords,
double *oX, double *oY, double *oXY,
double p_oAvgX, double p_oAvgY)
{
unsigned int p_rLoopsize = p_oNumPoints - (p_oNumPoints % 2);
double oAvgX[2];
结果应该是在oAvgX中,它可以与Intel配合使用,但不能成功使用Intel标记的AT&T asm编译器。
其次,我担心额外的O2标志可能会优化其他变量,因此不能保证在不同的编译上构建相同的堆栈
我需要内联,但无法找到任何解决双方言问题的方法。您可以在GCC的内联程序集中按名称访问局部变量,只是您必须以与VS2010不同的方式来执行。在内联程序集的末尾,您应该/必须提供输入列表、输出列表和“clobbered”列表;其中,输入列表和输出列表都可以包含局部变量。还要注意的是,“clobbered”的列表非常重要(编译器假定任何未列为clobbered或未列为输出的内容都不会更改,包括所有内存内容等) 依赖偶然的东西(比如发生在哪个寄存器中的东西,或者发生在哪个内存位置或堆栈位置中的东西)是一个严重的bug,不管您使用哪个编译器,也不管它是否在某些有限的测试用例中实际工作。唯一正确的方法是依赖为此目的提供的设施(例如GCC内联汇编中的输入/输出列表) 对于任何非平凡的内联装配件;鉴于内联汇编不是任何(C/C++)标准的一部分;我认为让它在多个编译器中可靠工作的唯一明智方法是复制内联程序集 还要注意,不同的操作系统有不同的约定(例如,不同的ABI、不同的内核系统调用等)。基本上,(作为最坏的情况)您可能需要做以下事情:
#ifdef WIN32_VS2010
/* Inline assembly to suit Visual Studio 2010 for Win32 here */
#elifdef WIN32_ICC
/* Inline assembly to suit Intel's "ICC" compiler for Win32 here */
#elifdef LINUX_ICC
/* Inline assembly to suit Intel's "ICC" compiler for Linux here */
#elifdef WIN32_GCC
/* Inline assembly to suit GCC compiler for Win32 here */
#elifdef LINUX_GCC
/* Inline assembly to suit GCC compiler for Linux here */
#else
/* Generate error about unsupported target here */
#endif
一种方法是将变量包装到一个结构中,使用足够多的虚拟变量强制将其对齐到4、8或16。然后可以使用offsetof(struct x,member)计算成员的相对位置,希望这些数字可以在编译时作为兼容字符串注入
#define LOCAL(a) ((offsetof(struct mystruct,a)==0?"0":offsetof(a)==4?"4":"error"))
asm(" push ebp \n\t"
" mov ebp, %0 \n\t"
" mov %0, " LOCAL(a) "\n\t" // this would convert to [ebp + 4]
" pop ebp \n\t"
:"=0" (&my_struct) :::);
VC版本可以开始:
asm(" push ebp ");
asm(" lea ebp, struct.a ");
之后,使用相同的(丑陋的)语法和相同数量的局部变量。问候您,感谢您的回复。我知道AT&T/GCC程序集中的列表和CulbBER列表,但如何,例如,我可以访问代码块中间的变量吗?使用in列表,将其分配给一些内存,然后稍后访问此?最重要的是,如何将变量分配给sse寄存器?到目前为止,我尝试失败了……这是一个巨大的秘密;但变量只是一种幻觉——它们并不存在。存在的是地址和这些地址的内存内容;和登记册。您可能希望告诉GCC程序集的输入是某个对象(例如“变量”)的地址,以便内联程序集可以将该地址处的数据加载到SSE寄存器中。您可能想告诉GCC SSE寄存器也是一个输入(尽管我不确定GCC是否以这种方式正确支持SSE)。
asm(" push ebp ");
asm(" lea ebp, struct.a ");