Aud*_*day 9 macos assembly intel llvm vorbis
我在Mac OSX上加载Vorbis Ogg文件时遇到了神秘的错误.第一个文件正确加载,第二个文件在某些代码中崩溃,表明文件已损坏,即使我加载相同的文件两次,也会发生相同的情况.
在Vorbis内部进行了长时间的深度调试后,我发现该错误是由系统函数"pow"(双倍功率)引起的,它返回一个(nan)表示完全有效的输入,并且仅在第二次调用时发生(ov_read ),在第一次调用时,传递给"pow"的相同精确值返回有效结果.
8小时后,很多英特尔x87文档读取我发现了问题.长话短说,在vorbis"vorbis_ftoi"内部有一个函数,它使用这个汇编代码:
__asm__("fistl %0": "=m"(i) : "t"(f));
Run Code Online (Sandbox Code Playgroud)
哪个应该在英特尔FPU堆栈上推送和弹出.但是在LLVM上它会生成以下代码:
fld QWORD PTR [ebp-0x20]
fist DWORD PTR [ebp-0x14]
Run Code Online (Sandbox Code Playgroud)
它推送堆栈但从不弹出导致FPU堆栈溢出.这显然是LLVM中的一个错误
GCC生成的正确代码如下所示:
fld QWORD PTR [ebp-0x20]
fist DWORD PTR [ebp-0xc]
fstp st(0) // pops off the stack
Run Code Online (Sandbox Code Playgroud)
我浪费了一天半的时间和我的brian的一些字节学习了一些垃圾(x87指令集和寄存器),所以我会分享它.
奥代
小智 2
出色的!谢谢。另一种解决方案是简单地完全删除 asm。这是一个补丁:
--- lib/os.h 2011-11-13 20:36:24.000000000 -0500
+++ lib/os.h 2011-11-15 18:45:00.000000000 -0500
@@ -93,27 +93,16 @@
typedef ogg_int16_t vorbis_fpu_control;
static inline void vorbis_fpu_setround(vorbis_fpu_control *fpu){
- ogg_int16_t ret;
- ogg_int16_t temp;
- __asm__ __volatile__("fnstcw %0\n\t"
- "movw %0,%%dx\n\t"
- "andw $62463,%%dx\n\t"
- "movw %%dx,%1\n\t"
- "fldcw %1\n\t":"=m"(ret):"m"(temp): "dx");
- *fpu=ret;
}
static inline void vorbis_fpu_restore(vorbis_fpu_control fpu){
- __asm__ __volatile__("fldcw %0":: "m"(fpu));
}
/* assumes the FPU is in round mode! */
static inline int vorbis_ftoi(double f){ /* yes, double! Otherwise,
we get extra fst/fld to
truncate precision */
- int i;
- __asm__("fistl %0": "=m"(i) : "t"(f));
- return(i);
+ return (int)floor(f+.5);
}
#endif /* Special i386 GCC implementation */
Run Code Online (Sandbox Code Playgroud)