MAC OSX Intel LLVM汇编程序错误(导致Vorbis OGG加载程序崩溃)

时间:2011-10-11 03:31:38

标签: macos assembly llvm intel vorbis

我在Mac OSX上加载Vorbis Ogg文件时遇到了神秘的错误。第一个文件正确加载,第二个文件在某些​​代码中崩溃,表明文件已损坏,即使我加载相同的文件两次,也会发生相同的情况。

在Vorbis内部进行了长时间的深度调试后,我发现该错误是由系统功能“pow”(双倍功率)引起的,返回一个(nan)表示完全有效的输入,而这只发生在第二次通话中to(ov_read),在第一次调用时,传递给“pow”的相同精确值返回有效结果。

8小时后,我发现了很多英特尔x87文档。长话短说,vorbis“vorbis_ftoi”内部有一个功能,它使用这个汇编代码:

__asm__("fistl %0": "=m"(i) : "t"(f));

哪个应该在英特尔FPU堆栈上推送和弹出。但是在LLVM上它会生成以下代码:

fld    QWORD PTR [ebp-0x20]
fist   DWORD PTR [ebp-0x14]

它推送堆栈但从不弹出导致FPU堆栈溢出。这显然是LLVM中的一个错误

GCC生成的正确代码如下所示:

fld    QWORD PTR [ebp-0x20]
fist   DWORD PTR [ebp-0xc]
fstp   st(0)        // pops off the stack

我浪费了一天半的时间和我的brian的一些字节学习了一些垃圾(x87指令集和寄存器),所以我会分享它。

Auday

2 个答案:

答案 0 :(得分:3)

更简单的补丁,只有在使用llvm进行编译时才会有效:

--- Xiph\vorbis\os.h    Mon Mar 28 08:42:43 2011
+++ Xiph\vorbis\os.h    Thu Feb 02 14:20:27 2012
@@ -81,7 +81,7 @@


 /* Special i386 GCC implementation */
-#if defined(__i386__) && defined(__GNUC__) && !defined(__BEOS__)
+#if defined(__i386__) && defined(__GNUC__) && !defined(__BEOS__) && !defined(__llvm__)
 #  define VORBIS_FPU_CONTROL
 /* both GCC and MSVC are kinda stupid about rounding/casting to int.
    Because of encapsulation constraints (GCC can't see inside the asm

不幸的是,我没有足够的声誉来投票支持OP,但我知道我很感激你的发现。谢谢。

答案 1 :(得分: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 */