Проблема с оптимизацией времени соединения, приводящая к неопределенным символам с константами ASM
Я собираю mplayer с llvm-gcc-4.2.1.
С '-O1' (который отключает оптимизацию времени ссылки), программа успешно компилирует и связывает. С '-O2' или '-O1 -flto' ld жалуется на неопределенные символы:
Неопределенные символы для архитектуры x86_64: "_MM_FIX_0_707106781", на который ссылаются: _filter в vf_fspp.o "_MM_FIX_0_541196100", на который ссылаются: _filter в vf_fspp.o ld: символы не найдены для архитектуры x86_64 collect2: ld вернул 1 статус выхода
К вашему сведению, моя версия ld:
@(#)PROGRAM:ld PROJECT:ld64-123.2
llvm version 2.9svn, from Apple Clang 2.0 (build 137)
Я сосредоточусь только на MM_FIX_0_707106781, так как все остальные константы следуют той же процедуре.
MM_FIX_0_707106781 инициализируется с помощью макроса:
DECLARE_ASM_CONST(8, uint64_t, MM_FIX_0_707106781)=FIX64(0.707106781, 14);
который оценивает:
static const uint64_t __attribute__((used, aligned (8))) MM_FIX_0_707106781=0x2d412d412d412d41;
Эти константы используются в коде asm:
#define MANGLE (a) "_" #a "(%% rip)" __asm__ volatile (... "pmulhw" MANGLE (MM_FIX_0_707106781) ", %% mm7 \ n \ t"...);
У меня была похожая (такая же?) Проблема с функциями asm, которую я смог решить, добавив:".globl "LABLE_MANGLE(functionnamehere)"\n\t"
перед каждым ярлыком, но это знание не помогло мне с этими константами ASM.
Боюсь, это столько информации, сколько я могу предоставить. Еще раз, с -O1 код компилируется, связывается и запускается. С -O2 компоновщик не может найти эти константы asm.
Кто-нибудь может предложить решение этой проблемы? Благодарю.
4 ответа
Спасибо всем, кто нашел время, чтобы рассмотреть мой вопрос, однако я только что понял, что испортил свои инструменты компиляции и теперь могу компилировать нормально.
Проблема заключалась в том, что скрипты mplayer make вызывают для компиляции 'cc', ожидая, что cc == gcc. Это было не так в моей системе; cc был связан с другой версией gcc. Как только я сделал символическую ссылку cc на gcc, я получил проект для компиляции с -O4 (как установлено в скрипте настройки mplayer по умолчанию).
В заключение: неправильно настроенные инструменты компилятора вызывали конфликты во время соединения. Решено с помощью одного и того же компилятора на всех этапах сборки.
Изменить: На самом деле llvm-gcc по-прежнему не удается с -O4, но другие компиляторы (gcc-4.5.2 и gcc42, который является версией Apple GCC) успешно. Оба других компилятора не принимают флаг -flto, поэтому оптимизация времени соединения все еще не выполняется. Я, по крайней мере, счастлив, что могу скомпилировать с -O2, -O3 и т. Д., И это главная причина, по которой я был мотивирован поставить этот вопрос.
Естественно, я хотел бы иметь возможность использовать компилятор llvm-gcc, если захочу (на уровне выше -O1), однако вы должны рассмотреть этот вопрос как полурешенный, так как два других компилятора правильно работают с этим кодом.
Следующее позволило ffmpeg-0.8 скомпилироваться в моей системе:
./configure --cc=i686-apple-darwin10-gcc-4.2.1 --enable-gpl --enable-nonfree
В llvm-link есть ошибка - она не учитывает символы из внедренного asm. Я не знаю ни одного достойного обходного пути, кроме ссылки на тот же символ где-нибудь из того же модуля в C. Если вы выполняете отдельную компиляцию, это не проблема, так как используется нативный компоновщик. Для LTO будет использоваться линкер LLVM, и он имеет недостатки.
РЕДАКТИРОВАТЬ: я не заметил static
, что означает, что как встроенный asm, так и символ находятся в одном модуле, и это другая ошибка.
Ну, это определенно ошибка. Если вы думаете, что это ошибка компилятора, у вас есть несколько вариантов:
- Сообщите об ошибке Apple, так как кажется, что вы используете llvm-gcc, поставляемый с XCode
- Попробуйте захватить top-of-tree llvm & llvm-gcc (что уже устарело, кстати) и попытаться воспроизвести проблему (или, наоборот, захватить лязг). Если воспроизводит - тогда заполните LLVM PR.
Так обычно поступают с ошибками компилятора:)
Однако, как мне кажется, ошибка в исходном коде. Здесь вы предполагаете, что имя символа, соответствующего этой статической константе в конечном объекте, будет иметь некоторую форму. Обычно это вещи, определяемые реализацией, и компилятор может изменять имя произвольным образом (поскольку он статичен и, следовательно, внешне не виден).
Попробуйте удалить "статический" и проверить, существует ли проблема до сих пор. В качестве альтернативы (и это правильный путь), вы должны исправить свой встроенный ассемблер и предоставить свою константу через встроенный операнд ассемблера.