我在代码中发现了一个奇怪的分段错误,如果这可能是GCC错误或者只是我的错,我想听听您的意见!
该功能如下:
void testMMX( ... ) {
unsigned long a = ...;
unsigned char const* b = ...;
unsigned long c = ...;
__asm__ volatile (
"pusha;"
);
__asm__ volatile ( "mov %0, %%eax;" : : "m"( a ) : "%eax" ); // with "r"( a ) it just works fine!
__asm__ volatile ( "add %0, %%eax;" : : "m"( b ) : "%eax" );
__asm__ volatile ( "mov %0, %%esi;" : : "m"( c ) : "%eax", "%esi" );
__asm__ volatile (
"sub %eax, %esi;"
"dec %esi;"
"movd (%esi), %mm0;"
"popa;"
);
}
如果我用-O0编译它,它就可以了。但它与-O1和-O2一起使用SegFaults。我花了很长时间才弄清楚这个段错是由帧指针省略引起的。 pusha指令将堆栈大小增加4 * 8 = 32字节(x86_32),因此ESP也应该增加。但是gcc不承认这一点。如果我手动添加ESP修复
__asm__("add $32, %esp")
或在gcc中使用“-fno-omit-frame-pointer”标志我可以使用-O1和-O2编译并运行它而不会出现任何错误!
所以现在我的问题是:如果启用了帧指针省略,为什么gcc不会使用任何推送/弹出内联汇编程序操作来调整ESP?这是一个gcc bug吗? gcc甚至能够检测到这个吗?我错过了什么吗?
解决这个问题会非常有趣。
提前致谢!
答案 0 :(得分:4)
否 - gcc 无法检测到这一点。它不会对asm
块中显示的指令执行任何分析。您有责任告知编译器任何副作用。你能解释一下你正在进行的测试吗?
此外,您应该考虑为此代码使用单个asm
块; volatile
可能会阻止重新排序asm
块,但您cannot assume this yields consecutive instructions。