Переключение между более чем двумя общими библиотеками (LD_PRELOAD)

Предположим, что существуют три разделяемые библиотеки A.so, B.so и C.so, каждая из которых имеет функцию f(). Я хочу переключаться между каждой функцией f() при определенных обстоятельствах, определяемых во время выполнения. Используя трюк LD_PRELOAD, я выполню программу p (т.е. пользователя этих библиотек) следующим образом:

LD_PRELOAD=A.so:B.so:C.so ./p

f() в A.so будет значением по умолчанию. В этом экземпляре f() я могу получить доступ к f() из B.so, используя dlsym(), следующим образом:

void f() // in A.so
{
...
    void *f_in_B = dlsym(RTLD_NEXT, "f");
...
}

Как я могу получить доступ к экземпляру f() в C.so?


ОБНОВЛЕНИЕ:

Хотя ответ yugr работает в простом случае, у него есть проблемы в более общих условиях. Я пролью свет на проблему, предоставив больше подробностей о текущей ситуации:

Мне нужны два разных распределителя динамической памяти, и я не хочу иметь дело с внутренними деталями реализации glibc malloc(),.... Проще говоря, у меня есть две отдельные области памяти, каждая со своим собственным glibc. Я использую LD_PRELOAD для переключения между распределителями на основе некоторых условий времени выполнения. Я использовал ответ yugr для загрузки и доступа к вторичной библиотеке.

Во-первых, я вызвал ptmalloc_init() во вторичной библиотеке для инициализации malloc() структур данных. Я также управлял вызовами brk() на уровне системных вызовов ОС таким образом, чтобы каждая библиотека имела свой собственный большой диапазон brk() и этот >избегает дальнейших конфликтов.

Проблема в том, что решение работает только на границе application/glibc. Например, когда я использую malloc() в дополнительной библиотеке, он вызывает такие функции, как __default_morecore() в основной библиотеке, внутренне, и эти вызовы могут не быть захваченным трюком LD_PRELOAD.

Почему это происходит? Я думал, что внутренние символы библиотеки устанавливаются внутри во время компиляции библиотеки, но здесь кажется, что они используйте символы из основной библиотеки LD_PRELOAD. Если разрешение выполняется компоновщиком, почему эти кажущиеся внутренними символы не захватываются приемом LD_PRELOAD?

Как я могу исправить проблему? Должен ли я переименовывать все экспортированные функции в дополнительной библиотеке? Или единственный возможный подход заключается в использовании одной библиотеки и вникании в реализацию?


person TheAhmad    schedule 11.10.2020    source источник
comment
Прочтите документацию по dlopen(3) и dlsym(3) и укажите минимальный воспроизводимый пример в вашем вопросе. Прочтите также документ Дреппера Как писать разделяемые библиотеки и документация по make, binutils, GCC и Книга дракона   -  person Basile Starynkevitch    schedule 11.10.2020
comment
Это какой-то вызов или реальная проблема?   -  person Lorinczy Zsigmond    schedule 11.10.2020
comment
@LorinczyZsigmond, это настоящий. Мне приходится использовать модифицированные реализации некоторых функций в glibc и использовать их вместо оригинальных, при определенных условия. Вы можете предположить, что A.so — это моя оболочка, которая проверяет условие и выбирает между исходной функцией в glibc (например, B.so) и индивидуальный (например, C.so).   -  person TheAhmad    schedule 11.10.2020
comment
Или я должен сделать проверки в начале f() в настроенном glibc и использовать его как стандартный? Действительно, это решит проблему, но не будет работать более чем в двух случаях.   -  person TheAhmad    schedule 11.10.2020


Ответы (1)


Вы можете dlopen каждую из трех библиотек при запуске получить их дескрипторы и использовать их для вызова dlsym(h, "f") для получения конкретных реализаций f. Если вы не знаете имена библиотек заранее, вы можете использовать dl_iterate_phdr для их получения (см. этот код например).

person yugr    schedule 11.10.2020