В дополнение к имеющимся в системе общим библиотекам мы можем создавать свои общие библиотеки. К примеру, пусть у нас определен файл 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. Тогда компоновщик будет понаходить ее автоматически.