Каковы различия заголовка ELF между файлом объекта ELF и общим объектом? - PullRequest
19 голосов
/ 08 июля 2011

Прежде всего, я спрашиваю об этом с технической точки зрения, а не с точки зрения пользователя кода библиотеки.Одним из примеров различия является то, что общие объекты содержат программные заголовки, а обычные объектные файлы - нет.В чем другие различия?

Что касается цели моего вопроса, я пытаюсь выяснить, какой контент необходимо удалить из общего объектного файла, чтобы компоновщик рассматривал его как обычный объектный файл.и попытаться переместить и статически связать его в сгенерированный исполняемый файл, а не идентифицировать его как разделяемую библиотеку и создать ссылку DT_NEEDED.Это, в свою очередь, является первым шагом к примитивному «преобразованию» разделяемой библиотеки во что-то, что может быть статически связано (однако, может потребоваться дальнейшая работа для обеспечения удовлетворительного перемещения).

1 Ответ

11 голосов
/ 08 июля 2011

Одно из основных отличий, которое вы обнаружите, заключается в том, что на последнем этапе компоновки несколько компонентов библиотеки C статически связаны в библиотеку, образуя символы INIT и FINI, среди прочего.Они указываются с помощью DT_INIT и DT_FINI записей в заголовке программы;вам нужно будет преобразовать их в статические записи конструктора / деструктора.Записи DT_NEEDED будут потеряны при преобразовании в .o;вам нужно будет повторно добавить их вручную.

PLT, сгенерированный на последнем этапе соединения, должен быть либо объединен с окончательным выходным файлом, либо преобразован обратно в обычные перемещения;это нетривиально, так как PLT - это просто код.GOT также является проблемой;он расположен с фиксированным относительным смещением от сегмента .text и содержит указатели на элементы данных.Однако он также содержит указатель на структуру _DYNAMIC, которой может быть только один на библиотеку или исполняемый файл.И вы не можете изменить смещения в GOT, потому что они ссылаются непосредственно из кода.

Так что довольно трудно снова преобразовать .so в истинное .o;информация была потеряна при конвертации в PLT / GOT.Лучшим подходом может быть изменение динамического компоновщика в библиотеке C для поддержки связывания совместно используемой библиотеки, которая уже отображается в памяти как статическое изображение.То есть вы бы преобразовали .so в .o, просто преобразовав его в выровненный по страницам раздел, доступный только для чтения;затем передайте это динамическому компоновщику, чтобы переназначить с соответствующими разрешениями и выполнить обычную инициализацию совместно используемой библиотеки.Затем добавьте статический конструктор для вызова в библиотеку C для инициализации общей библиотеки.Наконец, добавьте соответствующие экспортированные символы, соответствующие динамическим символам в сегменте .text общей библиотеки.

Одна из проблем этого подхода заключается в том, что статические конструкторы могут выполняться до статического конструктора, который инициализирует ваше поддельное солиб.В этом случае они не должны пытаться вызывать функции из solib, иначе вы, возможно, потерпите крах, так как solib еще не инициализирован.Этого потенциально можно избежать, превратив экспортированные символы в функцию батута, которая гарантирует, что сначала инициализируется solib (хотя это не так просто с символами данных!)

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

...