Создание разделяемой библиотеки

Последнее обновление: 29.09.2023

В дополнение к имеющимся в системе общим библиотекам мы можем создавать свои общие библиотеки. К примеру, пусть у нас определен файл ten.s с кодом функции, которая умножает некоторое число на 10:

.globl ten

.text
# Функция возвращает число умноженное на 10
# Параметр:
# %rdi - число, для умножения на 10
# Результат функции возвращается через регистр %rax
ten:
    movq $10, %rax      # результат в %rax
    mulq %rdi          # %rax = %rax *%rdi
    ret

Через регистр %rdi функция получает число и умножает его на 10. Результат возвращается через регистр %rax (в этот регистр по умолчанию помещается результат инструкции mul).

И пусть у нас есть файл hello.s, который использует эту функцию:

.globl main
 
.data
message: .asciz "%d * 10 = %d\n"  # строка форматирования
num: .quad 5
.text
main:
    subq $8, %rsp           # выравнивание должно быть по 16 байтам

    movq num, %rdi          # параметр функции ten
    call ten                # вызываем функцию ten

    movq $message, %rdi    # первый параметр функции printf - строка форматирования
    movq num, %rsi          # второй параметр функции printf - первый аргумент строки форматирования
    movq %rax, %rdx         # третий параметр функции printf - второй аргумент строки форматирования
    call printf

    addq $8, %rsp
    ret

Здесь сначала вызываем функцию ten, передавая ей переменную num через регистр %rdi. Затем вызываем библиотечную функцию printf и выводим результат на консоль.

Если бы мы использовали статические библиотеки языка Си, то мы могли бы скомпилировать оба файла в единую программу с помощью следующей команды:

gcc -static ten.s hello.s -o hello

Но в данном случае сделаем из файла ten.s общую библиотеку. Пусть она будет называться libten.so. И для этого выполним следующую команду:

gcc -shared ten.s -o libten.so

Затем скомпилируем главный файл программы hello.s в приложение, которое использует библиотеку libten.so. В общем случае мы можем это сделать с помошью следующей команды:

gcc hello.s -lten -L . -o hello

Однако конкрентно в нашем случае при компиляции может потребоваться установить опцию -no-pie

gcc hello.s -no-pie -lten -L . -o hello

Аргумент -lten указывает компоновщику скомпоновать приложение с библиотекой "libten.so" (компоновщик автоматически добавляет префикс lib и расширение .so к названию библиотеки - ten). А опция -L указывает добавить текущий каталог для поиска библиотек.

Зачем нужна опция -no-pie, будет рассмотрено в следующей теме. Но в итоге приложение успешно скомпилируется.

Но несмотря на успешную компиляцию при выполнении программы мы столкнемся с ошибкой следующего вида:

root@Eugene:~/asm# ./hello
./hello: error while loading shared libraries: libten.so: cannot open shared object file: No such file or directory
root@Eugene:~/asm#

Дело в том, что загрузчик не знает, где искать библиотеку libexp.so. А флаг -L указывает каталог для поиска библиотек только компилятору GCC, но не загрузчику. И чтобы указать загрузчику каталог для поиска, надо установить переменную окружения LD_LIBRARY_PATH - она должна указывать на текущий каталог. Для этого в консоли выполним следующую команду:

export LD_LIBRARY_PATH=.

Полный пример:

root@Eugene:~/asm# gcc hello.s -no-pie -lten -L . -o hello
root@Eugene:~/asm# ./hello
./hello: error while loading shared libraries: libten.so: cannot open shared object file: No such file or directory
root@Eugene:~/asm# export  LD_LIBRARY_PATH=.
root@Eugene:~/asm# ./hello
5 * 10 = 50
root@Eugene:~/asm#

В качестве глобального решения можно поместить нашу библиотеку в папку /usr/lib. Тогда компоновщик будет понаходить ее автоматически.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850