Ответ 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 будет инициализирован первым (не так просто с символами данных, хотя!)
Вы также можете обнаружить, что этот предыдущий вопрос может вам пригодиться.