8

I'm just studying how TLS (thread-local storage) is implemented on Linux systems. The document ELF Handling for Thread-Local Storage explains how a program's requirements for thread-local variables can be encoded in an ELF binary, and how the "runtime" should handle such binaries.

However, it's not clear to me whether in practice the "runtime" which sets up the TLS area(s) will be the Linux kernel (and its code for loading ELF binaries) or some initialization code in libc. Could someone explain briefly?

(Background: I'm trying to statically-link and run an application, but it segfaults on start. In gdb, I can see the segfaulting code is some init code from libc. It's trying to read a static variable using an address relative to GS, but GS is zero.)

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Alex D
  • 29,755
  • 7
  • 80
  • 126
  • 2
    glibc and musl are open source; you can check the source code for them. – Colonel Thirty Two May 21 '15 at 14:45
  • 3
    Are you discussing TLS (thread-local storage) or TLS (transport layer security)? Content suggests thread-local storage; tag [tag:ssl] suggests the latter. Were you synonymized? I've removed [tag:ssl] and added [tag:thread-local-storage], though [tag:tls] did not self-evidently get mapped to [tag:ssl]. – Jonathan Leffler May 21 '15 at 14:58
  • @JonathanLeffler, I added tls, meaning thread-local-storage. Thanks for correcting the mistake. – Alex D May 21 '15 at 15:24
  • I've checked; [tag:tls] is a synonym for [tag:ssl]. – Jonathan Leffler May 22 '15 at 02:22

1 Answers1

5

Thread-local storage initialisation is part of the libc-provided start-up code. When statically linking, your linker should add the TLS initialisation to the start-up code linked into your program.

For example, glibc has __libc_setup_tls and _dl_tls_setup (among other, related things) in libc.a, which will be added to the initialisation code of your program if you link via, say, gcc -static. (For dynamically-linked programs the _dl_... functions are part of the ELF dynamic linker-loader, ld-linux.so, which isn't used to run a statically-linked program.)

Proper TLS initialisation in a statically-linked executable is, therefore, a result of collaboration between your C library (which provides the code) and your toolchain (which has to understand how to properly link in all the necessary start-up code).

The kernel's involvement in TLS initialisation is minor. (Basically, it just has to ensure that the .tdata section is available to libc for initialisation.) See ELF file TLS and LOAD program sections for details.

Community
  • 1
  • 1
user3113526
  • 196
  • 4
  • This doesn't answer the crucial question on how the GS segment gets setup to point the TLS section. That's something that only the kernel can do. – Ross Ridge May 27 '15 at 23:33
  • I haven't looked at `glibc` yet, but I just checked `musl`. It initializes the TLS on startup (as you said), but then also uses a `set_thread_area` syscall to make an entry in the process' LDT which points to the space allocated for TLS. Then libc sets the `%gs` register so that it refers to the LDT entry for TLS. (This is on x86-32 -- x86-64 uses a different segment register.) – Alex D May 28 '15 at 06:48