GCC分段故障与-O1和内联汇编程序

时间:2014-01-30 10:41:08

标签: linux debugging ubuntu gcc inline-assembly

我在代码中发现了一个奇怪的分段错误,如果这可能是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甚至能够检测到这个吗?我错过了什么吗?

解决这个问题会非常有趣。

提前致谢!

1 个答案:

答案 0 :(得分:4)

否 - gcc 无法检测到这一点。它不会对asm块中显示的指令执行任何分析。您有责任告知编译器任何副作用。你能解释一下你正在进行的测试吗?

此外,您应该考虑为此代码使用单个asm块; volatile可能会阻止重新排序asm块,但您cannot assume this yields consecutive instructions