Операционная система Linux имеет ряд встроенных общих библиотек, в частности, библиотеки языка Си, которые мы можем использовать в приложении ассемблере. Например, мы можем подключить функцию printf, какие-то другие функции, чтобы использовать их функционал в приложении.
По умолчанию разделяемые библиотеки начинаются с префикса lib имеют расширение .so. По умолчанию они расположены в папке usr/lib. В частности, библиотеки языка Си на архитектуре x86-64 можно найти в папке /usr/lib/x86_64-linux-gnu. Здесь нас прежде всего будет интересовать библиотека libc.so, которая содержит базовый функционал стандартной библиотеки языка Си и в частности функцию printf
Например, определим файл app.asm со следующим кодом:
global _start extern printf ; подключаем функцию printf section .data message: db "Hello METANIT.COM",10, 0 section .text _start: lea rdi, [rel message] ; 1-й параметр функции printf - адрес строки call printf ; вызываем функцию printf mov rax, 60 syscall
В данном случае используем библиотечную функцию printf для вывода на консоль строки message.
Для подключения разделяемых библиотек компоновщику передается флаг -l, после которого указывается имя библиотеки без
приставки "lib" и расширения ".so". Так, функция printf
находится в библиотеке libc.so, поэтому, чтобы ее подключить, примется флаг -l c
или -lc
.
Итак, скомпилируем файл "app.asm" в объектный файл
nasm -felf64 app.asm -o app.o
Затем скомпонуем приложение в исполняемый файл "app":
ld --dynamic-linker=/lib64/ld-linux-x86-64.so.2 -lc app.o -o app
Опять же для загрузки библитеки и приложения устанавливается динамический загрузчик "/lib64/ld-linux-x86-64.so" Затем мы сможем запустить скомпонованное приложение:
root@Eugene:~/asm# nasm -felf64 app.asm -o app.o root@Eugene:~/asm# ld --dynamic-linker=/lib64/ld-linux-x86-64.so.2 -lc app.o -o app root@Eugene:~/asm# ./app Hello METANIT.COM root@Eugene:~/asm#
Мы можем проверить с помощью утилиты ldd список зависимостей приложения и увидеть в нем libc.so:
root@Eugene:~/asm# ldd app linux-vdso.so.1 (0x00007ffd23eac000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6091e00000) /lib64/ld-linux-x86-64.so.2 (0x00007f609209e000) root@Eugene:~/asm#
В данном случае содавалось стандартное исполняемое приложение. Если же мы создаем приложение, независимое от позиции (PIE), то при обращении к функциям библиотек применяется выражение
call функция wrt ..plt
А для обращения к глобальным объектам применяется выражение
call объект wrt ..got
То есть применяется адресация относительно таблиц PLT и GOT. Например, изменим код app.asm следующим образом:
global _start extern printf section .data message: db "Hello METANIT.COM",10, 0 section .text _start: lea rdi, [rel message] call printf wrt ..plt ; адресация относительно PLT mov rax, 60 syscall
Далее скомпонуем приложение с использованием флага -pie:
root@Eugene:~/asm# nasm -felf64 app.asm -o app.o root@Eugene:~/asm# ld --dynamic-linker=/lib64/ld-linux-x86-64.so.2 -pie -lc app.o -o app root@Eugene:~/asm# ./app Hello METANIT.COM root@Eugene:~/asm#
Или другой пример - используем стандартную библиотечную функцию fprintf, которая имеет следующую сигнатуру:
int fprintf(FILE *stream, const char *format, ...)
В качестве первого параметра передается поток вывода, а далее параметры как у функции printf
. По умолчанию библиотека Си предоставляет глобальный объект
стандартного вывода на консоль - объект stdout. Для его использования определим следующую программу:
global _start extern fprintf ; подключаем глобальную функцию fprintf extern stdout ; глобальный объект section .data message: db "Hello Work",10, 0 section .text _start: mov rdi, [rel stdout wrt ..got] ; загружаем адрес объекта stdout mov rdi, [rdi] ; загружаем сам объект stdout lea rsi, [rel message] ; второй параметр функции fprintf - выводимая строка call fprintf wrt ..plt ; вызываем функцию fprintf mov rax, 60 syscall
Пример компиляции и работы программы:
root@Eugene:~/asm# nasm -felf64 app.asm -o app.o root@Eugene:~/asm# ld --dynamic-linker=/lib64/ld-linux-x86-64.so.2 -pie -lc app.o -o app root@Eugene:~/asm# ./app Hello Work root@Eugene:~/asm#