我正在编写一个 vsprintf 函数来使用我的 64 位操作系统内核(由 C 编写),并检查它在 Visual Studio 和 Cygwin gcc 中是否运行良好。 然后,我放入我的内核并运行...但是内核运行不正常
调试发现问题所在:vsprintf contains next assembly code
movdqa xmm0,XMMWORD PTR [rip+0x0]
真正的问题是我从不使用 float !
我猜那是 gcc 的优化,它似乎是正确的,因为它在没有优化的情况下工作得很好。
是否有任何解决方案,可以说,gcc 选项禁用 xmm 寄存器的优化?
最佳答案
生成了 XMM 寄存器移动指令,因为在 System V AMD64 ABI 中,浮点参数存储在 XMM0–XMM7 中。
由于仅通过查看可变参数函数我们不知道是否使用了 float ,因此编译器需要生成指令以将浮点值也推送到 va_list
。
您可以使用 -mno-sse
flag to disable 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
attribute仅针对该功能禁用 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,因此用 float 调用它们会导致未定义的行为:
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`
}
关于c - gcc -O3 优化::xmm0 寄存器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19615280/