Подтвердить что ты не робот

Каковы различия заголовков ELF между объектным файлом ELF и общим объектом?

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

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

4b9b3361

Ответ 1

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

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

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

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

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