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

发布于 2024-12-09 07:06:17 字数 784 浏览 3 评论 0原文

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

经过在 Vorbis 内部进行长时间的深度调试后,我发现该错误是由系统函数“pow”(的双次幂)返回一个完全有效的输入(nan)引起的,并且这种情况仅在第二次调用(ov_read)时发生),在第一次调用时,传递给“pow”的相同精确值将返回有效结果。

8 小时后,通过阅读大量 Intel 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

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

奥代

I had mysterious bug in loading Vorbis Ogg files on Mac OSX. The first file is loaded correctly, the second crashes in some code that indicates the file is corrupted, the same happens even if I load the same exact file twice.

After long hours of deep debugging inside Vorbis I found out that the bug is caused by the system function "pow" (double power of) returning a (nan) for a completely valid input, and that happens only on the second call to (ov_read), on the first call the same exact values passed to "pow" returns valid result.

8 hours later and lots of Intel x87 documentation reading I found the problem. Long story short there is a function deep inside vorbis "vorbis_ftoi " that uses this assembly code:

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

Which should push and pop on the Intel FPU Stack. However on LLVM it generates this code:

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

Which pushes on the stack but never pops causing an FPU stack overflow. And that's obviously a bug in LLVM

The proper code generated by GCC looks like this:

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

I wasted a day and a half and some bytes of my brian learning some garbage (x87 Instruction Set and Registers) on this, so I though I would share it.

Auday

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

肤浅与狂妄 2024-12-16 07:06:17

更简单的补丁,仅在使用 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,但要知道我很感激你的发现。谢谢。

Simpler patch, has affect only when compiling with 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

Unfortunately, I don't have enough reputation to vote up the OP, but know that I'm grateful for your find. Thank you.

愿与i 2024-12-16 07:06:17

出色的!谢谢。另一种解决方案是简单地完全删除 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 */

Excellent! Thank you. Another solution is to simply remove the asm altogether. Here is a patch:

--- 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 */
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文