__emutls_v & __emutls_t

Timo Sintonen t.sintonen at luukku.com
Sun Dec 22 04:54:54 PST 2013


On Sunday, 22 December 2013 at 10:51:19 UTC, Mike wrote:
> On Sunday, 22 December 2013 at 10:00:28 UTC, Johannes Pfau 
> wrote:
>>> If I declare global variables in D as...
>>> 
>>> __gshared int GlobalDataVar = 2;
>>> __gshared int GlobalBssVar;
>>> 
>>> ... these get put in .data and .bss respectively, and I know 
>>> what to do in my startup procedure:
>>> 
>>> However if I declare thread local variables in D as...
>>> 
>>> int TLSDataVar = 1;
>>> int TLSBssVar;
>>> 
>>> ... two symbols for each variable are created: one in the 
>>> section ".rodata.__emutls_t" and the other in section 
>>> ".data.__emutls_v"
>>> 
>>> I know this may be more specific to GCC than GDC, but if you 
>>> know something about these sections, please let me know, or 
>>> point me to some resource that will help me understand them.
>>> 
>>> Thanks,
>>> Mike
>>
>> I wrote a long answer here and managed to crash the newsreader 
>> before
>> it was sent so here's a short summary:
>
> Damn! Such valuable information lost... but I understand.
>
>>
>> The emutls code is here:
>> https://github.com/D-Programming-GDC/GDC/blob/master/libphobos/libdruntime/gcc/emutls.d
>>
>> The compiler calls __emutls_get_address, every symbol gets a
>> emutls_object_t.
>>
>> If you have only one thread you could to reimplement emutls.d 
>> to
>> avoid dynamic allocation. But the better solution is probably 
>> to add a
>> --single-thread-only option to GDC which rewrites TLS 
>> variables to
>> normal variables.
>
> That's making a lot of sense, my memory.map file looks like 
> this:
>
>  .rodata.__emutls_t._D5start9TLSBssVari
>                 0x0800006c        0x4 start.o
>  .rodata.__emutls_t._D5start10TLSDataVari
>                 0x08000070        0x4 start.o
>
> .data.__emutls_v._D5start9TLSBssVari
>                 0x08000080       0x10
>  .data.__emutls_v._D5start9TLSBssVari
>                 0x08000080       0x10 start.o
>                 0x08000080                
> __emutls_v._D5start9TLSBssVari
>
> .data.__emutls_v._D5start10TLSDataVari
>                 0x08000090       0x10
>  .data.__emutls_v._D5start10TLSDataVari
>                 0x08000090       0x10 start.o
>                 0x08000090                
> __emutls_v._D5start10TLSDataVari
>
>
> In emutls.d, emutls_object_t is exactly 16 bytes, and each 
> symbol in .data.__emutls_v is also 16 bytes.  So, I'm assuming 
> .data.__emutls_v sections contain the emutls_object_t object.
>
> Therefore, given the following TLS variables:
>
> int TLSDataVar = 1;
> int TLSBssVar;
>
> ... and the memory.map information above, examining 0x0800006c 
> and 0x08000070 in gdb yields the following:
>
> (gdb) x 0x08000070
> 0x8000070 <__emutls_t._D5start10TLSDataVari>:   0x00000001
> (gdb) x 0x0800006c
> 0x800006c <__emutls_t._D5start9TLSBssVari>:     0x00000000
>
> So, these must be the initial values each of the variables.
>
> Now that I have some hypothesis as to what these sections are, 
> I guess I just need to figure out what to do with these in the 
> startup routine.  Timo, any ideas?

Had a quick look at emutls.d.
Yes, the rodata section  have the initial values of variables. 
This should be copied to the tls area of the current thread as I 
wrote earlier.
The data section does not contain data, but those emutls objects. 
They contain the pointer to the data and the size of data, among 
others. This section should be in rom and copied to ram within 
other data sections.

This paragraf is again a guess.
The compiler knows which object belongs to which variable. It 
fills the structures for those variables that are in rodata. For 
big uninitialized data like structs and arrays the emutls object 
contains initially a null pointer. Only when referencing this 
object first time, the data is allocated with malloc.


When addressing the actual variable, the offset is picked from 
the corresponding emutls object and added to the tls start 
address which is gotten from the thread library. This adds one 
extra level of indirection, but there is one advantage: because 
there is only one tls, all threads have all tls data from all 
modules. Emutls only allocates the data that really is used in 
that thread and the initial tls size is much smaller.

Anyway, this is not for us minimalists. The original emutls code 
has calls to  libpthread and so is not usable. It might be 
possible to make an own __emutls_get_address and I may have a 
look at it.

For now I recommend the minlib way or just get rid of all this by 
using --single-thread-only



More information about the D.gnu mailing list