Tl:dr: Если вам нужно продолжать использовать несколько версий libc, как это делают многие из нас, то ключевой утилитой для использования является PatchElf.
Обычно, если все, что вам нужно, это принудительно использовать собственную версию интерпретатора программы при создании собственной программы, все, что вам нужно сделать, это скомпилировать следующие параметры:
gcc -Wl,-dynamic-linker,/my/lib/ld-linux.so.2 ...
Но это не работает со сторонними утилитами и с некоторыми общими объектами, которые, тем не менее, выполняются сами по себе, поэтому вы вызываете patchelf для данной программы ELF следующим образом:
patchelf --set-interpreter /my/lib/my-ld-linux.so.2 someprogram
Причина, по которой это не просто вопрос редактирования с помощью шестнадцатеричного редактора старого исполняемого файла и замены старого адреса интерпретатора новым, заключается в том, что эти два значения не обязательно должны быть одинаковой длины; patchelf заботится о расширении вашего исполняемого файла для вас.
Вы также можете изменить переменную rpath следующим образом:
patchelf --set-rpath /my_libs:$LD_LIBRARY_PATH someprogram
Я считаю, что это намного удобнее, чем использование обычных оболочек для команд с LD_LIBRARY_PATH.
Что касается execve, это должен быть почти самый фундаментальный системный вызов в Unix: execve(имя файла) выполняет заданное имя файла. Например, ваша оболочка выполняет команду с помощью вызова семейства execve: сначала она разветвляется, а затем дочерний процесс генерирует команду execve (ls, cd, ... вы ее называете). Большинству программ нужны динамически связанные библиотеки, например, для ls:
$ ldd $(which ls)
linux-vdso.so.1 => (0x00007ffe3b0e7000)
libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f1423dda000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1423a11000)
libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f14237a0000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f142359c000)
/lib64/ld-linux-x86-64.so.2 (0x0000563800043000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f142337f000)
Когда вы загружаете ls, сначала используется не двоичная обычная точка входа, а вместо этого ld-linux : он заботится о загрузке всех неразрешенных необходимых библиотек, а затем передает управление реальному приложению, в этом случае ls дело. Это делается путем выполнения файла программы.
Я не могу сказать, почему именно ваша программа дает сбой. Но я бы попробовал проверить, что для всех вызываемых программ требуется один и тот же программный интерпретатор; Вы делаете это, проверяя вывод:
$ readelf -l /bin/ls
Elf file type is EXEC (Executable file)
Entry point 0x4049a0
There are 9 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040
0x00000000000001f8 0x00000000000001f8 R E 8
INTERP 0x0000000000000238 0x0000000000400238 0x0000000000400238
0x000000000000001c 0x000000000000001c R 1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
...........................
(акцент мой ...).
РЕДАКТИРОВАТЬ: отличное обсуждение одним из авторов системного вызова execveat можно найти здесь, а соответствующий код ядра здесь. Код показывает, что системная переменная не читается, и процедура load_elf_binary просматривает интерпретатор программы PT_INTERP.