Quando/in che modo Linux carica le librerie condivise nello spazio degli indirizzi?

Quando/in che modo Linux carica le librerie condivise nello spazio degli indirizzi?


La mia domanda è la seguente:


Quando viene specificato l'indirizzo degli oggetti condivisi nei programmi? Durante il collegamento? Caricamento in corso? Se volessi trovare l'indirizzo di memoria del system comando all'interno di libc all'interno del mio programma potrei trovarlo facilmente in gdb , ma cosa succede se non voglio portare il programma in un debugger?


Questo indirizzo potrebbe cambiare da run a run? Esistono altri strumenti di analisi statica che consentiranno di visualizzare dove le librerie o le funzioni verranno caricate nello spazio di memoria di questo programma durante l'esecuzione?


EDIT:voglio queste informazioni al di fuori del programma (ad esempio usando utilità come objdump per raccogliere informazioni)


Risposte:


Le librerie vengono caricate da ld.so (linker dinamico o linker runtime alias rtld, ld-linux.so.2 o ld-linux.so.* in caso di Linux; parte di glibc). Viene dichiarato "interprete" (INTERP; .interp sezione) di tutti i binari ELF collegati dinamici. Quindi, quando avvii il programma, Linux avvierà un ld.so (carica in memoria e salta al suo punto di ingresso), quindi ld.so caricherà il tuo programma in memoria, lo preparerà e poi lo eseguirà. Puoi anche avviare un programma dinamico con


 /lib/ld-linux.so.2 ./your_program your_prog_params

ld.so fa un vero open e mmap di tutti i file ELF necessari, sia il file ELF del tuo programma che i file ELF di tutte le librerie necessarie. Inoltre, riempie le tabelle GOT e PLT e risolve i trasferimenti (scrive gli indirizzi delle funzioni dalle librerie ai siti di chiamata, in molti casi con chiamate indirette).


Il tipico indirizzo di caricamento di alcune librerie che puoi ottenere con ldd utilità. In realtà è uno script bash, che imposta una variabile di ambiente di debug di ld.so (in realtà LD_TRACE_LOADED_OBJECTS=1 in caso di glibc's rtld) e avvia un programma. Puoi anche farlo da solo senza bisogno dello script, ad es. con l'utilizzo di bash facile modifica delle variabili di ambiente per una singola esecuzione:


 LD_TRACE_LOADED_OBJECTS=1 /bin/echo

Il ld.so vedrà questa variabile e risolverà tutte le librerie necessarie e ne stamperà gli indirizzi di caricamento. Ma con questa variabile impostata, ld.so in realtà non avvierà un programma (non sono sicuro dei costruttori statici di programmi o librerie). Se la funzione ASLR è disabilitata, l'indirizzo di caricamento sarà lo stesso la maggior parte delle volte. I moderni Linux spesso hanno ASLR abilitato, quindi per disabilitarlo, usa echo 0 | sudo tee /proc/sys/kernel/randomize_va_space .


Puoi trovare l'offset di system funzione all'interno del libc.so con nm utilità da binutils. Penso che dovresti usare nm -D /lib/libc.so o objdump -T /lib/libc.so e grep output.