Одним из преимуществ общих библиотек и динамической компоновки является возможность переопределения функций библиотеки. Загрузчик поддерживает переменную среды
LD_PRELOAD, которая предварительно загружает символы библиотеки в исполняемый файл перед загрузкой общих библиотек, запрошенных исполняемым файлом.
Следовательно, если символ уже определен в библиотеке, указанной в LD_PRELOAD
, то он имеет приоритет перед символами, загруженными позже.
Мы можем использовать эту возможность для переопределения библиотечных функций своими, даже если код уже скомпилирован, и у нас нет доступа к исходному коду!
Данная возможность часто используется для предоставления более оптимизированных версий различных системных функций, таких как malloc. В качестве простого примера переопределим функцию printf.
Пусть у нас изначально есть файл app.asm, который использует функцию printf
для вывода некоторой строки на консоль:
global _start extern printf section .data message: db "Hello Work",10, 0 ; строка для вывода на консоль section .text _start: lea rdi, [rel message] call printf 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 -lc app.o -o app root@Eugene:~/asm# ./app Hello Work root@Eugene:~/asm#
В итоге мы получаем ожидаемый результат.
Далее определим следующий файл print.asm:
global printf:function section .data message: db "new printf test",10, 0 len equ $-message section .text printf: mov rdi, 1 lea rsi, [rel message] mov rdx, len mov rax, 1 ; системный вызов номер 1 - функция write syscall ret
Данный код с помощью системного вызова номер 1 (системная функция write) выводит строку на консоль.
Для компиляции и компановки кода этой библиотеки используем команды:
nasm -felf64 print.asm -o print.o ld -shared print.o -o print.so
Затем установим скомпилированную библиотеку для предзагрузки с помощью команды
export LD_PRELOAD=./print.so
В конце снова выполним приложение "app"
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 Work root@Eugene:~/asm# nasm -felf64 print.asm -o print.o root@Eugene:~/asm# ld -shared print.o -o print.so root@Eugene:~/asm# export LD_PRELOAD=./print.so root@Eugene:~/asm# ./app new printf test root@Eugene:~/asm#
Для удаления предзагрузки нашей библиотеки (удаления значения переменной LD_PRELOAD) следует выполнить команду
unset LD_PRELOAD