Программы
"Линковка" во время работы программы

"Линковка" во время работы программы

Доведём тему линковки до конца – когда для сборки и запуска программы нам даже не нужна сама библиотека!

Итак, в прошлой теме мы рассмотрели динамическую линковку с общей (shared) библиотекой (объектом). Чтобы уже добить эту тему, осталось рассмотреть вариант динамической загрузки библиотек.

Библиотеки Linux (по типу использования):

Динамическая загрузка библиотеки Си

Для реализации динамической загрузки библиотеки будем использовать интерфейс динамической загрузки (Dynamic Loading API). Имеется стандарт на реализацию для POSIX-совместимых систем, а также есть отдельные системо-специфичные возможности. Мы будем придерживать функций, описанных для POSIX.

Интерфейс динамической загрузки даёт приложению пользователя возможность использовать совместно используемые библиотеки. Функций будет не много, но этого вполне хватает для большинства задач.

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

Не будем изменять традиции, используем нашу библиотеку для работы со связным списком. Нам понядобятся dlopen() и dlsym() из <dlfcn.h>:

  • dlopen - Дает программе доступ к ELF-библиотеке;
  • dlsym - Возвращает адрес функции из библиотеки, загруженной при помощи dlopen;
  • dlerror - Возвращает текстовое описание последней возникшей ошибки;
  • dlclose - Закрывает доступ к библиотеке.
#include <dlfcn.h>
#include "linked_list.h"

// Помните, что функции - это указатели?
// Так вот, это как раз мы и используем ниже.
void (* print_list)(node_t *head);
void (* add)(node_t * head, char val);

int load_library() {
  // Открываем произвольный файл, реализующий интерфейс `linked_list.h`.
  // `RTLD_LAZY` - используем ленивый биндинг – подгружаем только символы
  // и соответствующие адреса. То есть берём адреса функций, но пока не
  // как функции.
  void * lib = dlopen("./liblinkedlist.so", RTLD_LAZY);
  if (lib == NULL) {
    return 1;
  }

  // Присваиваем адреса нужных символов нашим указателям (функциям)
  add = dlsym(lib, "add");
  print_list = dlsym(lib, "print_list");

  if (add == NULL) {
    return 2;
  }

  if (print_list == NULL) {
    return 3;
  }

  return 0;
}

int main() {
  int err = load_library();
  if (err) {
    printf("Library load error");
    return err;
  }

  // Подгрузили - пользуемся!
  char c;
  node_t head = { .next = NULL, .val = ' ' };

  while ((c = getc(stdin)) != EOF) {
    add(&head, c);
  }

  print_list(&head);
  return 0;
}
→ clang main.c
→ ./a.out

Таким образом мы можем реализовать подключаемые плагины для Си-шной программы. Можем подгрузить код, которого даже не было написано на момент запуска нашей программы!

Также может быть вам интересно:

Сделаем свою небольшую общую библиотеку

Мы уже делали библиотеку для Си. Настало сделать общую библиотеку!

Читать »

Обнимать! Снова обниматели лезут в код Linux!

В Linux собираются заменить мат на обнимашки

Читать »
Фото Как сделать свою middleware в Django (с примерами)

Как сделать свою middleware в Django (с примерами)

Middleware или "промежуточное программное обеспечение" - элегантный способ установить общие правила обработки запросов и ответов приложения. Давайте напишем парочку middleware, чтобы понять, как они работают.

Фото Как настроить отправку почты из Django

Как настроить отправку почты из Django

Письма об ошибках, отчёты на почту, восстановление паролей - всё это полезно при работе с сайтом. Django предоставляет удобный способ это сделать с минимумом настроек!

Фото Добавляем поддержку медиа-файлов в Django проект

Добавляем поддержку медиа-файлов в Django проект

Современные сайты редко ограничиваются только текстом и вёрсткой. Часто в заметках красуются фотографии, а рядом с описанием товаров - их изображения.

Фото Настройка журналирования (логирования) в Python с примерами

Настройка журналирования (логирования) в Python с примерами

Во время работы программы часто нужно сохранять некоторые важные записи о процессе выполнения команды. В Python есть довольно мощный модуль для работы с логами - давайте разберёмся с тем, как его использовать.

Фото Новый оператор match-case в Python

Новый оператор match-case в Python

В новой версии Python (3.10) появится новый оператор. Новый оператор сопоставления по шаблону (match-case).

Фото Нет слов, одни... однострочники

Нет слов, одни... однострочники

На днях вышел пост со списком полезных однострочников для JavaScript программистов. Памятуя Perl-овую молодость, заглянул туда.

Фото Добавляем переменные в контекст Django шаблонов (свой контекст-процессор)

Добавляем переменные в контекст Django шаблонов (свой контекст-процессор)

В Django вы можете передавать данные в шаблоны посредством контекстов. Контекст передаётся из контроллера (view в терминах Django), однако, если одни и те же данные нужны в разных местах, лучше сделать свой контекст-процессор.

Фото Пример своей консольной команды в Django проекте

Пример своей консольной команды в Django проекте

Если вы работали с Django проектом, то, скорее всего, запускали команды из консоли (manage.py). В Django есть простой способ писать свои команды для управления проектом.