MAC OSX Intel LLVM Assembler ошибка (вызывает сбой загрузчика Vorbis OGG) - PullRequest
9 голосов
/ 11 октября 2011

У меня была загадочная ошибка при загрузке файлов Vorbis Ogg на Mac OSX. Первый файл загружен правильно, второй - сбой в некотором коде, который указывает, что файл поврежден, то же самое происходит, даже если я загружаю один и тот же точный файл дважды.

После долгих часов глубокой отладки внутри Vorbis я обнаружил, что ошибка вызвана системной функцией "pow" (двойная степень), возвращающей (nan) для полностью корректного ввода, и это происходит только при втором вызове to (ov_read), при первом вызове те же самые точные значения, переданные "pow", возвращают действительный результат.

8 часов спустя и много чтения документации Intel x87 я обнаружил проблему. Короче говоря, внутри vorbis есть функция vorbis_ftoi, которая использует этот код сборки:

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

Что должно вытолкнуть и вытолкнуть в стек Intel 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 Instruction Set and Registers) по этому поводу, поэтому я решил поделиться им.

Auday

Ответы [ 2 ]

3 голосов
/ 02 февраля 2012

Более простой патч, влияет только при компиляции с 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

К сожалению, у меня недостаточно репутации, чтобы проголосовать за ОП, но знаю, что я благодарен за вашу находку.Спасибо.

2 голосов
/ 16 ноября 2011

Отлично! Спасибо. Другое решение - просто удалить ассемблер. Вот патч:

--- 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 */
...