Разделяемая библиотека linux чем открыть
Общие сведения об общих библиотеках в Linux
Например, если вы создаете приложение, которое должно выполнять математические операции, вам не нужно создавать для этого новую математическую функцию, вы можете просто использовать существующие функции в библиотеках для этого языка программирования.
Linux поддерживает два класса библиотек, а именно:
Динамические или разделяемые библиотеки можно разделить на следующие категории:
Общие библиотеки именуются двумя способами: имя библиотеки (также известное как soname) и «имя файла» (абсолютный путь к файлу, в котором хранится код библиотеки).
Программа может вызывать библиотеку, используя ее имя или имя файла, а в пути к библиотеке хранятся каталоги, в которых библиотеки могут быть найдены в файловой системе. По умолчанию библиотеки расположены в/usr/local/lib,/usr/local/lib64,/usr/lib и/usr/lib64; библиотеки запуска системы находятся в/lib и/lib64. Однако программисты могут устанавливать библиотеки в произвольных местах.
Путь к библиотеке может быть определен в файле /etc/ld.so.conf, который вы можете редактировать с помощью редактора командной строки.
Строки в этом файле предписывают ядру загрузить файл в /etc/ld.so.conf.d. Таким образом, разработчики пакетов или программисты могут добавлять свои каталоги пользовательских библиотек в список поиска.
Если вы посмотрите на mariadb-x86_64.conf, вы увидите абсолютный путь к библиотекам пакета.
Приведенный выше метод устанавливает постоянный путь к библиотеке. Чтобы установить его временно, используйте переменную среды LD_LIBRARY_PATH в командной строке. Если вы хотите сохранить изменения постоянными, добавьте эту строку в файл инициализации оболочки/etc/profile (global) или
/.profile (для конкретного пользователя).
Давайте теперь посмотрим, как работать с разделяемыми библиотеками. Чтобы получить список всех зависимостей разделяемых библиотек для двоичного файла, вы можете использовать утилиту ldd. Вывод ldd имеет следующий вид:
Эта команда показывает все зависимости разделяемых библиотек для команды ls.
Поскольку разделяемые библиотеки могут существовать во многих разных каталогах, поиск во всех этих каталогах при запуске программы был бы очень неэффективным: что является одним из вероятных недостатков динамических библиотек. Поэтому используется механизм кеширования, выполняемый программой ldconfig.
Это очень важно, особенно если вы только что установили новые разделяемые библиотеки или создали свои собственные, или создали новые каталоги библиотек. Вам нужно запустить команду ldconfig, чтобы изменения вступили в силу.
После создания общей библиотеки ее необходимо установить. Вы можете переместить его в любой из стандартных каталогов, упомянутых выше, и запустить команду ldconfig.
В качестве альтернативы выполните следующую команду, чтобы создать символические ссылки от soname к имени файла:
Чтобы приступить к созданию собственных библиотек, ознакомьтесь с этим руководством в Linux Documentation Project (TLDP).
На этом пока все! В этой статье мы познакомили вас с библиотеками, объяснили общие библиотеки и способы управления ими в Linux. Если у вас есть какие-либо вопросы или дополнительные идеи, которыми вы можете поделиться, используйте форму комментариев ниже.
Администрирование систем Linux. Работа с разделяемыми библиотеками
Глава 29. Работа с разделяемыми библиотеками
29.1. Краткая информация о разделяемых библиотеках
При разговоре о библиотеках мы будем иметь в виду динамически связываемые библиотеки (или разделяемые объекты). Они являются бинарными файлами, содержащими код функций, которые не исполняются как приложения, а могут использоваться из других бинарных файлов.
29.2. Директории /lib и /usr/lib
При просмотре содержимого директорий /lib и /usr/lib можно обнаружить большое количество символьных ссылок. Имена большинства файлов разделяемых библиотек содержат подробные описания номеров версий, причем для этих файлов также создаются символьные ссылки с именами, содержащими лишь указания на номера основных версий.
29.3. Утилита ldd
29.4. Утилита ltrace
Имя пакета программного обеспечения дистрибутива Debian/Ubuntu, который содержит указанную разделяемую библиотеку, может быть установлено следующим образом.
Имя пакета программного обеспечения дистрибутива RedHat/Fedora, который содержит указанную разделяемую библиотеку, может быть установлено следующим образом.
Теперь при проверке целостности файлов из пакета программного обеспечения не выводится информации о каких-либо проблемах с файлом разделяемой библиотеки.
29.7. Трассировка вызовов библиотечных функций с помощью утилиты strace
Созданный нами файл может быть открыт только для чтения, но мы все равно попытаемся изменить его содержимое и использовать директиву :w! для принудительной записи данных в него. После этого мы закроем текстовый редактор vi и перейдем к рассмотрению содержимого файла журнала трассировки вызовов функций разделяемых библиотек.
Обратите внимание на то, что текстовый редактор vi осуществлял изменение прав доступа к файлу дважды. Файл журнала трассировки вызовов функций разделяемых библиотек содержит большой объем информации, поэтому его содержимое не приводится в полном объеме в данной книге.
Выполнение разделяемых библиотек в Linux
В данной статье мы поговорим о создании библиотек с возможностью их запуска и передачи им аргументов из командной строки. В ответ библиотека выдаст нам информацию об авторе и документацию своих функций. В качестве примера создадим небольшую библиотеку myexec:
int my_main(int argc,char *argv[]) <
printf(«Main started. Argc: %d\n»,argc);
for (;*argv;*argv++) printf(» %s\n»,*argv);
exit(0);
>
int f1(void) < printf("function %s\n",__FUNCTION__); >
int f2(void)
Функции f1() и f2() являются функциями библиотеки, из-за которых она собственно и пишется. Нас они не интересуют, поэтому они будут просто выводить свое имя сразу после вызова. Именно эти функции мы будем документировать. Функция my_main() будет точкой входа в библиотеку. Она показывает все входные аргументы, переданные из командной строки. Вызов exit() в конце обязателен, так как после выполнения функции my_main() управление никуда не возвращается, как в случае обычных выполняемых файлов. Поэтому нам нужно самостоятельно завершить выполнение.
Собираем, запускаем и видим то, что ожидали:
const char interp[] __attribute__((section(«.interp»))) = «/lib/ld-linux.so.2»;
Файл /lib/ld-linux.so.2 является загрузчиком для ОС Linux.
Другой способ не требует вмешательства в исходный код библиотеки. Требуемая секция добавляется в объектный файл с помощью утилиты objcopy:
Функция my_main() запустилась, но параметры передались не в том порядке_ в котором мы ожидали. За передачу параметров от ядра к функции main() отвечает специальный код компилятора, запакованный в объектный файл сrt1.o. При передаче управления от ядра к выполняемому файлу в стеке процесса содержатся:
Однако функция my_main() справедливо полагает, что первое значение в стеке есть адрес возврата вызвавшей ее функции. Ядро, как мы знаем, этот адрес не кладет в стек. Таким образом, мы теряем аргумент argc, остальные аргументы можно достать средствами языка C. Решение, кажется, лежит на поверхности. Достаточно «обернуть» вызов функции my_main() в какую-нибудь другую функцию, например:
В п. 1,2,3 стек засоряется, а в п. 4,5,6 вычищается. Как видно, п. 4,5,6 происходят после вызова my_main(), поэтому нам придется очистить стек самостоятельно до вызова нашей входной функции. По адресу 667-66с делается операция получения текущего адреса выполнения программы в регистр ebp: инструкция call положит адрес возврата в стек, а инструкция pop тут же его оттуда вытащит, поэтому эта часть на положение стека не влияет. Регистр ebp необходим для доступа к таблице PLT нашей библиотеки.
Также нам нужно создать указатель на массив указателей на аргументы командной строки, так как наша my_main(), как и обычная main(), принимает его в качестве второго аргумента. Итак, нам нужно очистить три двойных слова из стека и создать указатель. Вариантов сделать это предостаточно, вот один из вариантов функции pre():
void pre(void) <
asm volatile (
«xorl %ebp,%ebp\n\t» //
В п.1 очищаем ebp, далее очищаем стек на четыре двойных слова (вместо трех), обращаемся к памяти за стеком и достаем argc. В п. 4 создаем нужный указатель и в п.5 складываем готовые аргументы в стек для передачи my_main(). И наконец, в п.6 вызываем ее. Вставляем этот код в начало библиотеки, собираем c новой точкой входа pre и запускаем:
что даст нам ожидаемый вывод:
Линковка в Linux
Table of Contents
1 Ссылки
2 Линковка
Линковка это процесс компоновки различных кусков кода и данных вместе, в результате чего получается один исполняемый файл. Линковка может быть выполнена во время компиляции, во время загрузки (загрузчиком) и также во время исполнения (исполняемой программой). Раньше (конец 40-х) линковка выполнялась вручную, сейчас мы имеем программы линковщики (linkers), которые дают возможность динамической линковки разделяемых библиотек (shared libraries).
3 Основы
Пусть у нас есть два файла с кодом a.c и b.c. Чтобы скомпилировать эти два файла при помощи GCC, мы вызываем следующий код
Это вызывает следующую последовательность:
Запустить препроцессор на файле a.c и сохранить результат в промежуточный файл a.i
Запустить компилятор на a.i и сгенерировать ассемблерный код в a.s
Запустить ассемблер на a.s и сгенерировать объектный файл a.o
Работа линковщика состоит в том, чтобы получить на вход сгенерированные объектные файлы a.o и b.o и сгенерировать из них финальный исполняемый файл a.out
После этого мы можем запустить наш бинарный файл ./a.out. Оболочка командной строки вызовет функцию загрузчика, которая скопирует код и данные из исполняемого файла a.out в память, затем передаст управление в начало программы. Функция загрузчик называется execve, она загружает код и данные исполняемых объектных файлов в память, затем запускает их выполнение, прыгая на первую инструкцию.
4 Линковщики и Загрузчики
Линковщики (linkers) и загрузчики (loaders) выполняют концептуально разные, но в целом похожие задачи:
В итоге, получается что загрузчик выполняет загрузку программ; линковщик выполняет symbol resolution; оба выполняют релокацию.
5 Объектные файлы
Компиляторы и ассемблеры генерируют перемещаемые объектные файлы (а так же разделяемые объектные файлы). Линковщики компонуют эти объектные файлы вместе и генерируют исполняемые объектные файлы.
6 ELF
Объектные файлы разнятся в разных ОС. Первые UNIX системы использовали формат a.out. Ранние System V использовали формат COFF (common object file format). Windows NT использует разновидность формата COFF, называемую PE (portable executable); IBM использует собственный формат IBM 360. Современные UNIX системы, такие как Linux и Solaris используют формат UNIX ELF (executable and linking format).
6.1 Заголовки Elf
7 Символы и адресация символов
Каждый перемещаемый объектный файл содержит таблицу символов связанные символы. В контексте линковщика представлены следующие виды символов:
Линковщик разрещает адресацию символов путём соотношения каждой ссылки на символ только к одному определению символу из таблицы символов.
8 Линковка статических библиотек
9 Релокация
После того как линковщик разрешил адресацию всех символов, каждый адресация символа ссылается ровно на одно определение символа. В этот момент линковщик запускает процесс релокации, состоящий из двух шагов:
Ассемблер при релокации создаёт секции .relo.text и .relo.data, в которых содержится информация как разрешить адресацию (адрес для обращения к символу). ELF содержит в секциях релокации следующие данные:
10 Динамическая линковка: разделяемые библиотеки
Статические библиотеки, описанные выше, имеют существенный недостаток. Например, возьмём стандартные функции printf и scanf. Они используются почти что в каждой программе. Пусть на системе запущено 50-100 процессов, каждый процесс содержит свою копию исполняемого кода printf и scanf — это существенный объём затраченной памяти. Разделяемые библиотеки в свою очередь направлены на исправление этого недостатка статических библиотек. Разделяемые библиотеки это объектные модули, которые могут быть загружены в память в момент исполнения программы и после слинкованы с программой. Разделяемые библиотеки (shared libraries) называют так же разделяемые объекты (shared objects). На большинстве систем UNIX они именуются с суффиксом .so; на системах HP-UX — с суфиксом .sl; на системах Microsoft они называются DLL. Чтобы собрать разделяемый объектный файл, компилятор надо вызывать со специальным флагом
Эта команда сообщает компилятору, что надо сгенерировать разделяемую библиотеку libfoo.so, собранную из объектный файлов a.o и b.o. Флаг -fPIC сообщает компилятору, что надо сгенерировать адресо-независимый код (position independent code — PIC). Теперь представим что объектный модуль bar.o зависит от a.o и b.o. В этом случае мы компилируем его так:
Эта команда создаёт исполняемый файл a.out, который будет линковаться с libfoo.so в момент загрузки. Здесь a.out не содержит в себе объектный модулей a.o и b.o, которые были бы включены в него, если бы мы использовали статическую линковку. Исполняемый файл просто содержит некоторую информацию о релокации и таблицу символов, которые позволяют адресоваться к коду и данным в libfoo.so и эта адресация будет разрешена в процессе исполнения (runtime). Таким образом, a.out это не совсем исполняемый файл, который имеет зависимость от libfoo.so. Исполняемый файл содержит секцию .interp, где содержится имя динамического линковщика (который сам является разделяемым объектом в системах Linux — ld-linux.so). Таким образом, когда исполняемый файл загружается в память, загрузчик передаёт управление динамическому линковщику. Динамический линковщик содержит некоторый код, который отображает пространство адресов динамических библиотек на пространство адресов испольняемой программы.
В конце работы динамический линковщик передаёт контроль исполняемой программе. С этого момента местоположение разделяемого объекта зафиксировано в памяти.
11 Загрузка разделяемой библиотеки из приложения
Разделяемая библиотека может быть загружена из приложения в любой момент выполнения. Приложение может обратиться к динамическому линковщику с просьбой загрузить и прилинковать динамическую библиотеку. Linux, Solaris и другие системы поддерживают различниые функции, которые могут быть использованы для динамической загрузки разделяемых объектов. В Linux это системные вызовы dlopen, dlsym, dlclose, используемые для загрузки разделяемого объекта, поиска символа в разделяемом объекте и для закрытия разделяемого объекта.
C: создание и применение shared library в Linux
Библиотека – это файл, содержащий скопилированный код из нескольких объектных файлов в один файл библиотеки, который может содержать функции используемые другими программами.
Библиотеки могут быть статичными (static) и динамическими или разделяемыми (dynamic, shared).
Ниже – краткий пример создания и применения shared library на C в Linux.
Доступ к общей библиотеке может осуществляться по нескольким именам:
Версия для общей бибилиотеки меняется в случае, когда изменения в коде этой бибилиотеки делают её несовместимой с предыдущими версиями, например – если из библиотеки была убрана какая-то функция ( libpthread.so.1 )
Минорная версия меняется, если изменения не затронули совметимость библиотеки, например – какой-то фикс в одной из функций. В таком случае версия останется прежней, а изменится только минорная часть ( libpthread.so.1.1 ).
Такое соглашение об именах версий библиотек позволяет существование разных версий одной библиотеки в одной системе.
Программа, которая будет линковаться с этой бибилиотекой, не будет привязана к определённому файлу с последней версией библиотеки. Вместо этого, после установки последней версии – все связанные программы будут использовать её.
Создание библиотеки
Создадим простой файл libhello.c с одной функцией:
Создаём заголовочный файл библиотеки libhello.h с прототипом функции:
Приступаем к сборке библиотеки.