библиотека, указанная в LD_PRELOAD, не может быть загружена

Я столкнулся с некоторыми проблемами при использовании LD_PRELOAD для загрузки файла so.

Шаги следующие:

  1. libtest.c:

    void fun()
    {
        return 
    }
    
  2. gcc -o libtest.so libtest.c -fPIC --shared

  3. экспорт LD_PRELOAD=pwd/libtest.so

  4. main.c

    extern void fun(); void main() { fun() }

  5. gcc -о основной -L. main.c -ltest

  6. Затем ldd main

    ldd main linux-vdso.so.1=>(0x00007ffff7ffd000) /home/shiyanlou/Code/libtest.so(0x00007ffff7df9000) libtest.so=>not found libc.so.6=>/lib/x86_64-linux-gnu/libc.so.6 (0x00007ffffa29000) /lib64/ld-linux-x86-64.so.2 (0x0000555555554000)

  7. выполнить основной ./main он продвигает: ошибка при загрузке общей библиотеки: libtest.so. не удается открыть общий объектный файл: Нет такого файла или каталога.

Интересно, почему он подсказывает, что libtest.so не может быть найден после того, как я экспортировал переменную LD_PRELOAD. Однако я также пытался использовать LD_PRELOAD, чтобы указать другую общую библиотеку (не «libc.so») для внедрения функции malloc, это работает! Почему LD_PRELOAD работает только для общей библиотеки, которая не использовалась при линковке???


person Larry    schedule 20.02.2016    source источник


Ответы (2)


Вам нужно создать 2 версии *.so. Тот, который имеет поведение по умолчанию, загружается и жестко связывается с помощью «-ltest».

Теперь создайте свой libtest.so по умолчанию и с помощью nm -B докажите, что символ, который вы ожидаете перехватить, динамически связан.

Теперь встройте main.c в main.o, затем проверьте main.o с помощью nm, чтобы также увидеть, что у символа есть неудовлетворенное требование внешней связи.

Теперь свяжите ./main с main.o и libtest.so, а затем запустите его. ./main должен работать с этой копией по умолчанию, демонстрировать поведение по умолчанию, а также показывать правильный путь к правильному DSO с помощью команды ldd.

...

Теперь вы делаете шаг, чтобы создать версию LD_PRELOAD.

Вы должны назвать это libtest2.so. Вы не используете -ltest2

Дело в том, что тот, кто собирал ./main, вообще не знает о libtest2.so, жесткой зависимости от компоновки нет.

libtest2.so имеет альтернативное поведение, например, make foo() возвращает другую строку/число), и теперь цель состоит в том, чтобы перехватить эту вторую версию во время выполнения, поэтому первая версия не вызывается по умолчанию (или вообще). Используя среду LD_PRELOAD.

LD_PRELOAD=./libtest2.so ./main

...

Удачи.

person Darryl Miles    schedule 20.02.2016
comment
Привет, спасибо за вашу помощь. Я знаю, что ваш метод работает. Но я просто хочу знать, почему LD_PRELOAD не работает для библиотеки, которую я использовал для компоновки моей исполняемой программы? - person Larry; 21.02.2016
comment
Потому что он уже загружен? -ltest сделать жесткую зависимость DSO, и это не то, о чем LD_PRELOAD. Вы неправильно понимаете цель. Может быть, если вы скопируете на другое имя и загрузите его вместо этого. cp libtest.so libtest9.so, затем LD_PRELOAD=./libtest9.so ./main Поскольку libtest.so уже загружен, следовательно, /home/shiyanlou/Code/libtest.so(0x00007ffff7df9000) по умолчанию, динамический компоновщик загрузит DSO только один раз в адресное пространство процесса. При копировании файла он становится другим DSO. - person Darryl Miles; 21.02.2016
comment
Спасибо за ваше дальнейшее объяснение. Подводя итог, я использую libtest.so для создания жесткой зависимости DSO, а LD_PRELOAD также имеет значение /home/shiyanlou/Code/libtest.so. Когда я выполняю ./main, он загружает libtest.so из-за жесткой зависимости DSO, а не LD_PRELOAD. И тогда LD_PRELOAD будет проигнорирован, так как тот же DSO уже был загружен. Как следствие, libtest.so на самом деле не загружен, и ./main не может быть выполнено. Я прав? Если да, то почему LD_PRELOAD называется LD_PRELOAD? Разве он не должен загружаться перед любым другим DSO?? - person Larry; 21.02.2016
comment
Я здесь не для того, чтобы обсуждать, почему он так назван. Но, короче говоря, вы запрашиваете загрузку одного и того же DSO (и как жесткая зависимость, и как LD_PRELOAD), и он действительно загружается. Так в чем проблема? Что важно, загружается ли LD_PRELOAD? и удается ли ему перехватывать символы? Поскольку ответы да и да, какая разница, что он выглядит так, как будто он был загружен через жесткую зависимость, поскольку наблюдаемое поведение исполняемого файла такое же. Теперь скопируйте и переименуйте DSO и снова понаблюдайте. - person Darryl Miles; 22.02.2016
comment
Кажется, я понял, почему это не сработало. Спасибо, бро. - person Larry; 25.02.2016

Я скопировал и переименовал DSO как libtest2.so и сбросил LD_PRELOAD на переименованный DSO (с абсолютным путем). Он также сообщает, что libtest.so не может быть найден.

Я думаю, что причина, по которой это происходит, заключается в том, что libtest.so, который используется для жесткой зависимости, не может быть загружен.

То есть, пока LD_PRELOAD был загружен, но жесткая зависимость не может быть удовлетворена, поэтому он также не может выполнить ./main.

Теперь я могу сделать вывод, что при выполнении ./main DSO с жесткой зависимостью должен быть удовлетворен, потому что каждый DSO с жесткой зависимостью также должен быть загружен (хотя этот DSO должен быть полностью заменен!), иначе он выдаст сообщение о том, что DSO не может быть найден!

Спасибо за вашу помощь @Darryl Miles

person Larry    schedule 25.02.2016