|
From: Tom H. <th...@cy...> - 2003-11-18 00:10:42
|
In message <106...@ix...>
Jeremy Fitzhardinge <je...@go...> wrote:
> There's the kernel mechanism for setting up a thread-local storage area,
> using the set_thread_area syscall. The argument to this is a segment
> descriptor, like the one used for set_ldt. This segment descriptor is
> assigned to one of the 3 TLS entries in the GDT. On thread context
> switch, the kernel reassigns the GDT entries to the thread's TLS
> segment. The thread itself assigns that descriptor to one of its
> segment registers, and uses %seg:0 as the pointer to its TLS area.
>
> This is easy for us to implement, since Julian has already done the hard
> work. We can store a per-thread "GDT" containing only these entries as
> part of each Thread structure. In VG_(do_useg)() we just look for the
> GDT (vs LDT) bit in the segment selector and do the appropriate thing.
Indeed, and that's the bit that I have working.
> All this is to support the new TLS extensions to the ABI. These are
> described in detail in http://people.redhat.com/drepper/tls.pdf. I've
> read this once, but I still don't understand the details.
I did look at it a while ago, but I seem to recall finding it
similarly difficult to grasp fully at first reading.
> The essential point is that ELF files can now have a PT_TLS segment
> which is used as a prototype segment for thread-local variables. When a
> new thread is created, it effectively gets a new copy of the contents of
> the PT_TLS segment attached to its own thread area (pointed to via
> %gs). This is does lazily, so only the TLS segments which the thread
> actually uses are copied for it.
There can actually be mutiple TLS segments in the ELF file - there
are typically .tdata and .tbss from what I can see.
In fact only the base executable seems to use direct %gs references. For
example, when xxx is a thread local variables, this code:
xxx++;
is compiled to the following code in the object file:
10: 8d 04 1d 00 00 00 00 lea 0x0(,%ebx,1),%eax
17: e8 fc ff ff ff call 18 <thread_main+0x18>
1c: ff 00 incl (%eax)
but when linked into an executable the linker turns that into:
8048540: 65 a1 00 00 00 00 mov %gs:0x0,%eax
8048546: 81 e8 04 00 00 00 sub $0x4,%eax
804854c: ff 00 incl (%eax)
in a shared object the linker leaves it more or less alone, other
than applying relocations:
8c4: 8d 04 1d 2c 00 00 00 lea 0x2c(,%ebx,1),%eax
8cb: e8 f8 fe ff ff call 7c8 <_init+0x88>
8d0: ff 00 incl (%eax)
The function being called is ___tls_get_addr and the lea is setting
up some sort of index into the TLS segment.
> This means that there's cooperation between the dynamic linker and
> libpthread. Since we control the one but not the other, we need to make
> our libpthread compatible with the dynamic linker's TLS implementation.
> The ABI documents some of this, but unfortunately it only documents the
> compiler interface to this goo, but not the internal interfaces between
> libpthread and the ld.so. The easy part of this is making sure that new
> threads get their own new TLS areas (which the glibc libpthread does by
> passing CLONE_SETTLS to clone(), which is the equivalent of doing
> set_thread_area() in the new thread). Trickier is getting the details
> of all the other structures right. And since they're internal to glibc,
> there's no certainty they won't change from release to release...
Even the cloning is hard because although we have the pointer to
the thread area for the original thread we have no idea how big
that area is because ld.so seems to set it up with a size of -1 so
the area is effectively unlimited.
In fact I believe the address passed to the kernel as the thread
area pointer is a pointer to the thread descriptor structure, with
the TLS data for the main executable just below it so that negative
offsets from %gs will find it. Other TLS data is found from the
thread descriptor somehow by the __tls_get_addr function.
Trying to emulate the whole thing would be horrible, but given
the incestuous links between ld.so, libc and libpthread it's hard
to see how else it can be done. It would also be a maintenance
nightmare of course, as you say.
> BTW, this is completely independent of NPTL. The TLS stuff is an
> extension to the ABI which is also supported by the pre-NPTL threads
> library (though I'm not sure how they make do without the
> set_thread_area syscall).
I don't think they do make do without it, which is why valgrind
falls over if you try and load any program or library with a TLS
section in the ELF file. Setting LD_ASSUME_KERNEL causes ld.so to
use a glibc built without using TLS segments.
Tom
--
Tom Hughes (th...@cy...)
Software Engineer, Cyberscience Corporation
http://www.cyberscience.com/
|