gcc -O3优化:xmm0寄存器是什么?

7
我正在编写一个vsprintf函数,用于我的64位操作系统内核(使用C语言编写),并且检查它在Visual Studio和Cygwin gcc中运行良好。然后,我将其放入我的内核并运行……但是内核无法正常工作。
我进行了调试并找出了问题:vsprintf包含下面的汇编代码。
movdqa xmm0,XMMWORD PTR [rip+0x0]

真正的问题在于我从来不使用浮点数!

我猜这是gcc的优化,似乎很正确,因为没有优化也能很好地工作。

是否有解决方案,也就是说,可以禁用xmm寄存器的gcc选项?


xmm/ymm寄存器不仅用于浮点运算,movdqa是一条整数指令。 - Cory Nelson
啊哈...但是XMM寄存器似乎无法使用,因为我还没有在内核中初始化它们... - ikh
2
有趣的是,你的英语并没有什么大问题! :-) - user529758
2个回答

8

生成XMM寄存器移动指令是因为在System V AMD64 ABI中,浮点参数储存在XMM0-XMM7中。

由于我们无法仅通过看可变参数函数的代码是否使用浮点数来确定是否需要将浮点值压入va_list,因此编译器需要生成相应的指令。


您可以使用-mno-sse标志禁用SSE。例如:

__attribute__((noinline))
void f(const char* x, ...) {
    va_list va;
    va_start(va, x);
    vprintf(x, va);
    va_end(va);
}

没有 -mno-sse 标志:
subq    $0x000000d8,%rsp
testb   %al,%al
movq    %rsi,0x28(%rsp)
movq    %rdx,0x30(%rsp)
movq    %rcx,0x38(%rsp)
movq    %r8,0x40(%rsp)
movq    %r9,0x48(%rsp)
je  0x100000f1b
movaps  %xmm0,0x50(%rsp)
movaps  %xmm1,0x60(%rsp)
movaps  %xmm2,0x70(%rsp)
movaps  %xmm3,0x00000080(%rsp)
movaps  %xmm4,0x00000090(%rsp)
movaps  %xmm5,0x000000a0(%rsp)
movaps  %xmm6,0x000000b0(%rsp)
movaps  %xmm7,0x000000c0(%rsp)
0x100000f1b:
leaq    0x000000e0(%rsp),%rax
movl    $0x00000008,0x08(%rsp)
movq    %rax,0x10(%rsp)
leaq    0x08(%rsp),%rsi
leaq    0x20(%rsp),%rax
movl    $0x00000030,0x0c(%rsp)
movq    %rax,0x18(%rsp)
callq   0x100000f6a ; symbol stub for: _vprintf
addq    $0x000000d8,%rsp
ret

使用-mno-sse标志:

subq    $0x58,%rsp
leaq    0x60(%rsp),%rax
movq    %rsi,0x28(%rsp)
movq    %rax,0x10(%rsp)
leaq    0x08(%rsp),%rsi
leaq    0x20(%rsp),%rax
movq    %rdx,0x30(%rsp)
movq    %rcx,0x38(%rsp)
movq    %r8,0x40(%rsp)
movq    %r9,0x48(%rsp)
movl    $0x00000008,0x08(%rsp)
movq    %rax,0x18(%rsp)
callq   0x100000f6a ; symbol stub for: _vprintf
addq    $0x58,%rsp
ret

您也可以使用
target属性来仅在该函数中禁用SSE,例如:
__attribute__((noinline, target("no-sse")))
//                       ^^^^^^^^^^^^^^^^
void f(const char* x, ...) {
    va_list va;
    va_start(va, x);
    vprintf(x, va);
    va_end(va);
}

但要警告的是,其它支持SSE的函数不知道f不使用SSE,因此使用浮点数调用它们会导致未定义行为:

int main() {
    f("%g %g", 1.0, 2.0);  // 1.0 and 2.0 are stored in XMM0–1
                           // So this will print garbage e.g. `0 6.95326e-310`
}

有了那个选项,我就不能使用SSE浮点数了,对吧?我只想禁用那个优化...但如果没有其他方法,我应该遵循你的建议..谢谢。 - ikh
啊...我的交叉编译器不支持那个属性... 你知道怎么启用吗?我可以编译gcc。 - ikh
哦,不是不支持,但其他函数也有同样的问题!谢谢。 - ikh

0

使用 -O2 而不是 -O3,它会起作用。


2
原问题提出者已经清楚了解这个问题是由优化引起的。已经有一个很好的解答了。你的回答并没有增加太多价值。无论如何,欢迎您来到StackOverflow。祝您在这里过得愉快! - Onots

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接