[LLVMdev] Implement implicit TLS on Windows - need advice

Michael Spencer bigcheesegs at gmail.com
Mon Dec 5 16:22:59 PST 2011


On Sun, Dec 4, 2011 at 9:18 AM, Kai <kai at redstar.de> wrote:
> Hi!
>
> LLVM currently does not implement the implicit TLS model on Windows. This
> model is easy:
>
> - a thread local variable ends up in the .tls section
> - to access a thread local variable, you have to do
>  (1) load pointer to thread local storage from TEB
>      On x86_64, this is gs:0x58, on x86 it is fs:0x2C.
>  (2) load pointer to thread local state. In general, the index is stored in
> variable _tls_index. For a .exe, _tls_index is always 0.
>  (3) load offset of variable to start of .tls section.
>  (4) the thread local variable can now accessed with the add of step 2 and
> 3.
>
> For x86_64, something like the following should be generated for the tls1.ll
> test case:
>
> (1)     mov     rdx, qword [gs:abs 58H]
> (2)     mov     ecx, dword [rel _tls_index]
>        mov     rcx, qword [rdx+rcx*8]
> (3)     mov     eax, .tls$:i
> (4)     mov     eax, dword [rax+rcx]
>        ret
>
> (See the PECOFF spec, chapter 5.7 and http://www.nynaeve.net/?p=185 for
> reference.)
>
> I tried to implement this. With the attached patch tls1.patch, a thread
> local variable ends up in the .tls section. This looks fine.
> With the second patch tls2.patch I try to implement the code sequence. Here
> I have a couple of questions:
>
> - To get the offset to start of .tls section, I have created a new
> MachineOperand flag. Is this the right approach? If yes then I need a hint
> where to implement this in the WinCOFFObjectWriter.
> - How can I code the load of variable _tls_index in SelectionDAG? I have
> some trouble using DAG.getExternalSymbol and then loading the value.
>
> Thanks for your help.
>
> Kai

Thanks for working on this!

The first patch looks fine except that it's emitting to .tls when it
should be .tls$. Also, you need to add tests.

As for the second patch, that's not how MSVC 2010 emits code (and it
needs tests).

thread_local.c:

#ifdef _MSC_VER
#define __thread __declspec(thread)
#endif
__thread int i = 0;

int foo() {
  return i++;
}

thread_local.asm:

PUBLIC	_i
_TLS	SEGMENT
_i	DD	00H
_TLS	ENDS
PUBLIC	_foo
EXTRN	__tls_array:DWORD
EXTRN	__tls_index:DWORD
; Function compile flags: /Ogtpy
_TEXT	SEGMENT
_foo	PROC
; File c:\users\mspencer\projects\llvm-project\test\thread_local.c
; Line 7
	mov	eax, DWORD PTR __tls_index
	mov	ecx, DWORD PTR fs:__tls_array
	mov	ecx, DWORD PTR [ecx+eax*4]
	mov	eax, DWORD PTR _i[ecx]
	lea	edx, DWORD PTR [eax+1]
	mov	DWORD PTR _i[ecx], edx
; Line 8
	ret	0
_foo	ENDP
_TEXT	ENDS
END

llvm-objdump -d -r -s thread_local.obj:

Disassembly of section .text:
_foo:
       0:       a1 00 00 00 00                                  movl    0, %eax
                               1: IMAGE_REL_I386_DIR32  __tls_index
       5:       64 8b 0d 00 00 00 00                            movl
 %fs:0, %ecx
                               8: IMAGE_REL_I386_DIR32  __tls_array
       c:       8b 0c 81                                        movl
 (%ecx,%eax,4), %ecx
       f:       8b 81 00 00 00 00                               movl
 (%ecx), %eax
                              11: IMAGE_REL_I386_SECREL _i
      15:       8d 50 01                                        leal
 1(%eax), %edx
      18:       89 91 00 00 00 00                               movl
 %edx, (%ecx)
                              1a: IMAGE_REL_I386_SECREL _i
      1e:       c3                                              ret

Contents of section .tls$:
 0000 00000000                             ....
Contents of section .text:
 0000 a1000000 00648b0d 00000000 8b0c818b  .....d..........
 0010 81000000 008d5001 89910000 0000c3    ......P........

- Michael Spencer




More information about the llvm-dev mailing list