У меня есть большой программный проект со сложным процессом сборки, который работает следующим образом:
- Скомпилируйте отдельные исходные файлы.
- Частично свяжите объектные файлы для каждого модуля в другой .o, используя
ld -r
. - Скрыть приватные символы в каждом модуле с помощью
objcopy -G
. - Частично свяжите объекты модуля вместе, снова используя
ld -r
. - Связывайте модули вместе в общий объект.
Шаг 3 необходим, чтобы разрешить частные глобальные переменные модуля, которые не экспортируются в остальную часть проекта.
Все это прекрасно работает с ARM и IA32. К сожалению, теперь мне нужно заставить все работать на mips (в частности, mipsel-linux-gnu для Android). А общий объектный ABI MIPS значительно сложнее, чем на других платформах, и он не работает.
Что происходит, так это то, что шаг 5 завершается с ошибкой:
CALL16 reloc at 0x1234 not against global symbol
Похоже, это связано с тем, что компилятор генерирует перемещения CALL16 для вызова функций в другой единице компиляции, но CALL16 позволяет вам вызывать только глобальные символы --- и из-за шага 3 некоторые из символов, которые мы пытаемся вызвать, не являются глобально больше.
На данный момент я вижу несколько возможных вариантов:
- убедить компоновщика разрешить перемещения CALL16 в обычные вызовы, относящиеся к ПК внутри модуля компиляции, на шаге 2.
- то же самое, но на шаге 4 или 5.
- сообщить компилятору, чтобы он не генерировал перемещения CALL16 для вызовов функций между модулями компиляции.
- Другие.
Отключение шага 3, боюсь, не вариант из-за внешних требований.
Что я действительно хотел бы сделать, так это сгенерировать абсолютный код, который во время загрузки исправляется по нужным адресам; он меньше, намного быстрее и значительно проще, и нам не нужно совместно использовать библиотеку между процессами. К сожалению, похоже, что Android dlopen()
не поддерживает это.
В настоящее время я не в своей тарелке. У кого-нибудь есть предложения?
Это gcc 4.4.5 (от Emdebian), binutils 2.20.1. Целью BFD является elf32-tradlittlemips. Хост-ОС — это Linux, и я выполняю кросс-компиляцию для Android.
Дополнение
Я также получаю подобные предупреждения с шага 4.
$MODULE.o: Can't find matching LO16 reloc against `$SYMBOLNAME' for R_MIPS_GOT16 at 0x18 in section `.text.$SYMBOLNAME'
Глядя на дизассемблирование входных данных для шага 4, я вижу, что компилятор сгенерировал такой код:
50: 8f9e0000 lw s8,0(gp)
50: R_MIPS_GOT16 $SYMBOLNAME
54: 8fd9001c lw t9,28(s8)
58: 0320f809 jalr t9
5c: 00a02021 move a0,a1
Разве GOT16 не фиксируется до старшей половины адреса, и за ним должен следовать LO16 для младшей половины? Но код выглядит так, как будто он пытается выполнить косвенное обращение GOT. Это меня озадачивает. Я понятия не имею, связано ли это с моей предыдущей проблемой, или это другая проблема, или это вообще не проблема...
Обновить
Очевидно, MIPS просто не поддерживает скрытые глобальные символы!
Мы обошли это, исказив имена символов, которые должны быть скрыты, чтобы никто не мог сказать, что они из себя представляют. Это довольно сильно подталкивает внешние требования, но я убедил руководство, указав, что это единственный способ получить поставляемый продукт.
Это совершенно ужасно (и включает в себя очень отвратительную работу с make-файлом), поэтому я бы предпочел лучшее решение, если у кого-то оно есть...