Вопрос или проблема
Когда я собираю свой ELF, “лучшей практикой” является компиляция его с привязкой к самой старой версии glibc, чтобы он работал как с новыми, так и со старыми версиями glibc.
Т.е. если я использую realpath, который в выводе readelf
glibc имеет как версию GLIBC_2.0, так и версию GLIBC_2.3, я хочу использовать старую версию, чтобы мой ELF работал на glibc 2.0/1/2.
Но версия GLIBC_2.3, вероятно, была разработана и обновлена с момента ее выпуска, и я предполагаю, что версия GLIBC_2.0 не изменялась с тех пор, как была опубликована glibc 2.3. Поэтому я предполагаю, что хочу, чтобы мой ELF использовал версию GLIBC_2.3, когда она доступна, а в противном случае переходил к версии GLIBC_2.0.
Это возможно? Или что я не понимаю?
Я никогда не слышал о такой практике, тем более не называл бы ее лучшей практикой. Ближайшее, что мне приходит на ум, это то, что если посмотреть на вредоносные программы ELF, они часто компилируются с привязкой к действительно старым версиям ядра Linux и старым версиям libc. Тем не менее, я не уверен, что это можно назвать “лучшей практикой”.
Я не думаю, что явный переход возможен, учитывая, как Linux загружает ELF исполняемый файл в память. Все, что делает ядро, это отображает разделы ELF-файла в память в соответствии с заголовками PT_LOAD файла. Linux также подключает “интерпретатор”, который обычно является /lib/ld-linux.so.2
или /lib64/ld-linux-x86-64.so.2
. Этот интерпретатор является частью libc и отвечает за выполнение динамической ссылки на libc.so
или любые другие разделяемые объекты.
Файл ELF связывается с любыми доступными разделяемыми объектами, именно поэтому я написал, что явный выбор версии невозможен. Все зависит от интерпретатора ELF.
Ответ или решение
Как сделать так, чтобы ваш ELF-файл работал как с новой, так и со старой версией glibc?
При разработке программного обеспечения на платформе Linux возникает необходимость скомпилировать ваши ELF-файлы (Executable and Linkable Format) таким образом, чтобы они могли работать на различных версиях библиотеки glibc (GNU C Library). Это особенно важно для обеспечения совместимости с устаревшими системами, где запущены более ранние версии glibc. Ниже представлено руководство, которое поможет добиться этой цели.
Понимание динамической линковки и версионности glibc
При компиляции ELF-файлов динамический линкер использует соглашения о версиях при загрузке библиотек. Например, в случае, если ваша программа вызывает realpath
, и в readelf
доступны версии GLIBC_2.0 и GLIBC_2.3, возникает вопрос, как обеспечить использование более старой версии, если это возможно, без потери функциональности на более новых системах.
-
Определите необходимые функции и их версии
Перед началом компиляции проверьте, какие функции вы планируете использовать и какую версию glibc они требуют. Используйтеreadelf -s <ваш_файл>
для получения информации о требуемых версиях. -
Компиляция с использованием старой версии glibc
Вы можете скомпилировать вашу программу с указанием более старой версии glibc. Для этого вам понадобится установить старую версию glibc в отдельной среде (например, в Docker или chroot). Это позволит вам указать компилятору (gcc
илиg++
), какую версию использовать. Например, командная строка может выглядеть следующим образом:gcc -o ваш_файл ваш_код.c -Wl,--start-group -lc -lgcc -Wl,--end-group
По возможности используйте флаг
-Wl,--version-script
для управления версиями экспортируемых символов. -
Использование символов при линковке
При линковке вы можете явно указать, какие версии функций использовать, но это делается не всегда. Insignts в случае GLIBC_2.3: если вы хотите, чтобы ваша программа использовала GLIBC_2.3, когда она доступна, и GLIBC_2.0 в противном случае, вам понадобится использовать wrapper-функции или условную компиляцию. -
Контрольная версия
linker
Убедитесь, что linker (ld
) может использовать нужные версии, настроивLD_PRELOAD
или создав файлы конфигурации для linker. Это позволит указать, какие версии библиотек следует загружать при запуске вашего бинарника. -
Тестирование на разных системах
После компиляции вашего ELF-файла необходимо провести тестирование на системах с различными версиями glibc, чтобы убедиться, что ваш бинарный файл функционирует должным образом. Лишь так можно гарантировать обратную совместимость.
Заключение
К сожалению, создание ELF, который бы автоматически использовал более новую версию функции, если она доступна, и падал на старую версию в противном случае (как требовалось в вашем запросе), не является тривиальной задачей из-за особенностей динамической линковки в Linux. Однако, следуя описанным шагам выше, вы можете оптимально настраивать вашу программу для работы с несколькими версиями glibc. Не забывайте, что тестирование является ключевым этапом процесса.