www.digitalmars.com         C & C++   DMDScript  

D.gnu - __emutls_v & __emutls_t

reply "Mike" <none none.com> writes:
I need to make a startup procedure for my ARM Cortex-M platform.  
In C/C++ this includs copying the .data segment to RAM and 
initializing the .bss segment to 0.

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"

minlibd's linker script 
(https://bitbucket.org/timosi/minlibd/src/c4503befb556ff3edf04eeb63c384e0ea723a6aa/tools/l
script4?at=default) 
does not deal with these sections, I'm assuming because my 
version of GDC (yesterday's 4.8.2 backport {Thanks Johannes}) has 
changes for supporting emulated TLS.

My GDC is configured with --disable-tls and --disable-threads, so 
I believe I could treat these the same as __gshared variables, 
but I need to first understand what these sections are and what 
they contain.

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
Dec 21 2013
next sibling parent "Timo Sintonen" <t.sintonen luukku.com> writes:
On Sunday, 22 December 2013 at 02:01:15 UTC, Mike wrote:
 I need to make a startup procedure for my ARM Cortex-M 
 platform.  In C/C++ this includs copying the .data segment to 
 RAM and initializing the .bss segment to 0.

 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"

 minlibd's linker script 
 (https://bitbucket.org/timosi/minlibd/src/c4503befb556ff3edf04eeb63c384e0ea723a6aa/tools/l
script4?at=default) 
 does not deal with these sections, I'm assuming because my 
 version of GDC (yesterday's 4.8.2 backport {Thanks Johannes}) 
 has changes for supporting emulated TLS.

 My GDC is configured with --disable-tls and --disable-threads, 
 so I believe I could treat these the same as __gshared 
 variables, but I need to first understand what these sections 
 are and what they contain.

 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 have not investigated this but this is my assumption: Tdata section is just like ordinary data section, but every thread has its own copy of it. Data section is copied from rom to ram when the program starts, but tdata has to be copied every time a new thread starts. The address of data section is fixed and variables are addressed with absolute address (which the linker calculates at link time) The address of tls data is not known at link time so addresses are relative to the start of current tls. In standard gcc compiler the call is __aeabi_read_tp that should return the start of current tls. Something like this in normal gcc. In minlibd I have built my own tls on top of this. Emutls seems to group tdata and tbss in one section. The initial values are stored in the rodata section and the data section is the real tdata. Rodata should be put in rom, in linker script before any other rodata (because rodata.* consumes all remaining rodata sections) and marked with start and end like tdata. As we now have only one thread, I would put the data section to a fixed address before data (again, data.* will consume all remaining data sections) and marked like tdata so that it is possible to copy the data here from rom at init. This address should be available when the compiler calls it. Look at tls.d in minlibd example.
Dec 22 2013
prev sibling parent reply Johannes Pfau <nospam example.com> writes:
Am Sun, 22 Dec 2013 02:01:09 +0000
schrieb "Mike" <none none.com>:

 I need to make a startup procedure for my ARM Cortex-M platform.  
 In C/C++ this includs copying the .data segment to RAM and 
 initializing the .bss segment to 0.
 
 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"
 
 minlibd's linker script 
 (https://bitbucket.org/timosi/minlibd/src/c4503befb556ff3edf04eeb63c384e0ea723a6aa/tools/l
script4?at=default) 
 does not deal with these sections, I'm assuming because my 
 version of GDC (yesterday's 4.8.2 backport {Thanks Johannes}) has 
 changes for supporting emulated TLS.
 
 My GDC is configured with --disable-tls and --disable-threads, so 
 I believe I could treat these the same as __gshared variables, 
 but I need to first understand what these sections are and what 
 they contain.
 
 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: 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.
Dec 22 2013
parent reply "Mike" <none none.com> writes:
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?
Dec 22 2013
parent reply "Timo Sintonen" <t.sintonen luukku.com> writes:
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
Dec 22 2013
parent Iain Buclaw <ibuclaw gdcproject.org> writes:
On 22 December 2013 12:54, Timo Sintonen <t.sintonen luukku.com> wrote:
 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.
That's actually calls to gthread, which is a small libpthread inspired wrapper library. But the meaning is implied, all thread models supported by gcc are wrappers around the platform's pthread library, with exception to win32 (uses CriticalSection) and single (just stubs). Regards Iain
Dec 22 2013