MIPS, ELF и частичное связывание - PullRequest
4 голосов
/ 11 ноября 2011

У меня большой программный проект со сложным процессом сборки, который работает так:

  1. Компиляция отдельных исходных файлов.
  2. Частично связать объектные файлы для каждого модуля вместе в другой .o, используя ld -r.
  3. Скрыть личные символы в каждом модуле, используя objcopy -G.
  4. Частично объединить объекты модуля, снова используя ld -r.
  5. Объединение модулей в общий объект.

Шаг 3 необходим, чтобы разрешить глобальные переменные, закрытые для модуля, которые не экспортируются в остальную часть проекта.

Это все отлично работает с ARM и IA32. К сожалению, теперь я должен заставить все работать на mips (в частности, mipsel-linux-gnu для Android). И общий объект MIPS ABI значительно сложнее, чем на других платформах, и он не работает.

Происходит следующее: шаг 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-перенаправление. Это озадачивает меня. Я понятия не имею, связано ли это с моей предыдущей проблемой, или это другая проблема, или это вообще не проблема ...

Update

Очевидно MIPS просто не поддерживает скрытые глобальные символы!

Мы обошли это путем искажения названий символов, которые должны быть скрыты, чтобы никто не мог сказать, кто они. Это сильно подталкивает внешние требования, но я продал управление им, указав, что это был единственный способ получить отправляемый продукт.

Это абсолютно ужасно (и включает в себя какую-то очень отвратительную работу с make-файлом), поэтому я бы предпочел лучшее решение, если у кого-то есть такое ...

Ответы [ 2 ]

1 голос
/ 24 апреля 2012

Я не уверен насчет конкретных проблем GOT, которые у вас возникают.Есть много ошибок и проблем с GOT, LO16 / HI16 в binutils.Я думаю, что большинство из них были исправлены в той версии, которую вы используете, если только вы не нацелены на MIPS16 (чего, похоже, не делаете).LO16 действительно необходим только там, помимо MIPS16, вы вытаскиваете полное 26-битное смещение из GOT, поскольку у вас есть 32-битные регистры.LO16 не требуется, но все еще формально требуется некоторыми ABI / API, но он был выдуман как самое большее предупреждение (вы можете попробовать удалить -Werror на этом этапе, если вы его используете).Я честно понимаю только основы этой части, но в остальной части вашей ситуации у меня были некоторые рекомендации, если не ответ (трудно убедиться, учитывая сложность вашей настройки).

В MIPS (ибольшинство сборок, с которыми я знаком), у вас есть три основных уровня видимости: локальный, глобальный и слабый.Кроме того, у вас есть связь для общих объектов.GNU, конечно, любит усложнять вещи и добавляет больше.Газ обеспечивает защищенный, скрытый и внутренний (как минимум, трудно идти в ногу со всеми расширениями).При всем этом шаги, которые вы выполняете, настраивая вручную видимость, кажутся ненужными.

Если вы можете удалить промежуточную глобальность переменных, это должно устранить необходимость сделать их не глобальными, что может только упростить любые проблемы GOT, с которыми вы столкнетесь позже.

Общие проблемынемного сбивает с толку.Я не уверен, что вы подразумеваете под скрытыми глобальными символами, это немного противоречит (конечно, переносимость и конкретные проекты дают сумасшедшие проблемы и ограничения).Похоже, что вам нужны символы кросс-сборки на одном этапе, но не на более позднем этапе.Без использования расширений GNU (чего лучше избегать в моей книге), вы можете заменить глобалы в шагах 1-2 на comm и / или слабые глобалы.Вы всегда можете использовать хитрость препроцессора, чтобы на этапе даже не было нескольких субблоков (некрасиво, но это переносимый код на этом уровне).

У вас действительно есть настройка 1) субмодулей 2) субмодулей -> модулей 3-5) модулей -> общей библиотеки.Упрощение, которое не может повредить.Вы всегда можете вставить в 2) или 3-5) интерфейс уровня C, просто чтобы найти, какая сборка GCC будет предлагать для ваших архитектур, и использовать это в качестве основы для разделения видимости на чистые интерфейсы.

Желаю яможет дать вам индивидуальное решение, но это невозможно без вашего полноценного проекта.Я могу заверить, что, хотя местоположение MIPS (особенно цепочки инструментов) имеет проблемы, параметры видимости (особенно если вы используете gas, libbfd и gcc) одинаковы.

0 голосов
/ 13 сентября 2013

ваш binutils слишком стар.некоторые изменения в 2.23 могут решить вашу проблему, например, «скрыть символы без ссылок PLT или GOT».

...