Tl: dr : Se você precisar continuar usando várias versões do libc , como muitos de nós, então um utilitário chave para usar é PatchElf .
Normalmente, se tudo o que você quer é forçar sua própria versão do interpretador de programas ao criar seu próprio programa, tudo o que você precisa fazer é compilar com as seguintes opções:
gcc -Wl,-dynamic-linker,/my/lib/ld-linux.so.2 ...
Mas isso não funciona com utilitários de terceiros e com alguns objetos compartilhados que, no entanto, são executáveis por si sós, portanto, você invoca patchelf em um determinado programa ELF da seguinte forma:
patchelf --set-interpreter /my/lib/my-ld-linux.so.2 someprogram
A razão pela qual isso não é apenas uma questão de editar com um editor hex o antigo executável e sobrescrever o antigo endereço do intérprete com o novo, é que os dois não precisam ter o mesmo comprimento; patchelf cuida de ampliar seu executável para você.
Você também pode alterar a variável rpath , da seguinte forma:
patchelf --set-rpath /my_libs:$LD_LIBRARY_PATH someprogram
Acho isso muito mais prático do que usar os invólucros comuns em torno de comandos com LD_LIBRARY_PATH .
Quanto a execve , ele deve ser praticamente a chamada mais fundamental do sistema no Unix: execve (filename) executa o nome do arquivo dado. Por exemplo, seu shell executa um comando por meio de uma chamada da família execve : primeiro forks, então o processo filho gerou execve o comando ( > ls, cd, , ... o nome dele). A maioria dos programas precisa de bibliotecas vinculadas dinamicamente, por exemplo, para 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)
Quando você carrega ls , é não o ponto de entrada normal binário que é usado inicialmente, mas ld-linux em vez disso: cuida de carregar todas as bibliotecas necessárias não resolvidas e, em seguida, transfere o controle para o aplicativo real, ls nesse caso. Isso é feito por execve usando o arquivo do programa.
Eu sou incapaz de dizer por que exatamente o seu programa trava, mas eu tentaria verificar se todos os programas invocados requerem o mesmo interpretador de programa; você faz isso verificando a saída de:
$ 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] ...........................
(a ênfase é minha ...).
EDIT : uma excelente discussão por um dos autores da chamada do sistema execveat pode ser encontrada aqui , e o código do kernel relevante é aqui . O código mostra que nenhuma variável do sistema é lida, e a rotina load_elf_binary examina o interpretador de programas PT_INTERP .