2015-05-21 38 views
7

Sto solo studiando come TLS (thread-local storage) è implementato su sistemi Linux. Il documento ELF Handling for Thread-Local Storage spiega come i requisiti di un programma per le variabili locali del thread possono essere codificati in un binario ELF e in che modo il "runtime" deve gestire tali binari.Su Linux, TLS è impostato dal kernel o da libc (o altro linguaggio runtime)?

Tuttavia, non è chiaro se in pratica il "tempo di esecuzione", che imposta l'area TLS (s) sarà il kernel di Linux (e il suo codice per i binari di carico ELF) o qualche codice di inizializzazione in libc. Qualcuno potrebbe spiegarci brevemente?

(Sfondo: sto cercando di collegare ed eseguire un'applicazione in modo statico, ma segfaults all'avvio. In gdb, posso vedere che il codice segfaulting è un codice init di libc. Sta cercando di leggere una variabile statica utilizzando un indirizzo relativo a GS, ma GS è zero.)

+2

glibc e musl sono open source; puoi controllare il codice sorgente per loro. –

+3

Stai discutendo di TLS (thread-local storage) o TLS (transport layer security)? Il contenuto suggerisce l'archiviazione locale del thread; tag [tag: ssl] suggerisce quest'ultimo. Eri sinonimo? Ho rimosso [tag: ssl] e aggiunto [tag: thread-local-storage], anche se [tag: tls] non è stato auto-evidentemente mappato a [tag: ssl]. –

+0

@JonathanLeffler, ho aggiunto tls, che significa thread-local-storage. Grazie per aver corretto l'errore. –

risposta

4

L'inizializzazione di memorizzazione locale del thread fa parte del codice di avvio fornito da libc. Durante il collegamento statico, il tuo linker dovrebbe aggiungere l'inizializzazione TLS al codice di avvio collegato al tuo programma.

Per esempio, glibc ha __libc_setup_tls e _dl_tls_setup (tra le altre, cose relative) in libc.a, che saranno aggiunti al codice di inizializzazione del programma se ci si collega tramite, ad esempio, gcc -static. (Per i programmi collegati dinamicamente le funzioni _dl_ ... fanno parte del caricatore di collegamento dinamico ELF, ld-linux.so, che non viene utilizzato per eseguire un programma collegato staticamente.)

Inizializzazione TLS corretta in un collegamento statico l'eseguibile è, quindi, il risultato della collaborazione tra la tua libreria C (che fornisce il codice) e la tua toolchain (che deve capire come collegare correttamente in tutto il codice di avvio necessario).

Il coinvolgimento del kernel nell'inizializzazione TLS è minore. (Fondamentalmente, è sufficiente assicurarsi che la sezione .tdata sia disponibile per libc per l'inizializzazione.) Per i dettagli vedere ELF file TLS and LOAD program sections.

+0

Questo non risponde alla domanda cruciale su come il segmento GS viene impostato per puntare alla sezione TLS. È qualcosa che solo il kernel può fare. –

+0

Non ho ancora visto 'glibc', ma ho appena controllato' musl'. Inizializza il TLS all'avvio (come hai detto), ma utilizza anche un syscall 'set_thread_area' per creare una voce nel processo 'LDT che punta allo spazio allocato per TLS. Quindi libc imposta il registro '% gs' in modo che faccia riferimento alla voce LDT per TLS. (Questo è su x86-32 - x86-64 utilizza un registro di segmento diverso.) –