problem with __thread on linux/x86_64

Hi,

On Ubuntu Linux/x86_64, I get:

$ cat t.c
#include <stdio.h>
__thread int i = 7;
int main() { printf("%d\n", i); }
$ clang -o t t.c
$ ./t
Segmentation fault

(gdb) disas
Dump of assembler code for function main:
   0x0000000000400560 <+0>: push %rbp
   0x0000000000400561 <+1>: mov %rsp,%rbp
   0x0000000000400564 <+4>: sub $0x10,%rsp
   0x0000000000400568 <+8>: movl $0x0,-0x4(%rbp)
=> 0x000000000040056f <+15>: mov %fs:0x402034,%esi
   0x0000000000400577 <+23>: xor %al,%al
   0x0000000000400579 <+25>: mov $0x40066c,%edi
   0x000000000040057e <+30>: callq 0x4006e0 <printf@plt>
   0x0000000000400583 <+35>: mov %eax,-0x8(%rbp)
   0x0000000000400586 <+38>: mov -0x4(%rbp),%eax
   0x0000000000400589 <+41>: add $0x10,%rsp
   0x000000000040058d <+45>: pop %rbp
   0x000000000040058e <+46>: retq
End of assembler dump.
(gdb) p $fs
$1 = 0
(gdb) p *(int*)0x402034
$2 = 0

I don't really understand why it's segfaulting here, but presumably
it's something to do with thread-local storage not being set up
properly?

I'm using Clang and LLVM from svn trunk, updated a few minutes ago.

Thanks,
Jay.

The problem seems to be with Clang's assembler:

$ clang -S -o t.s t.c
$ clang -c -o bad.o t.s
$ gcc -o bad bad.o
$ ./bad
Segmentation fault
$ gcc -c -o good.o t.s
$ gcc -o good good.o
$ ./good
7

The only difference here is whether t.s was assembled by clang or by gcc.

Delving a bit deeper, the difference seems to be that symbol "i" in
the assembler source:

        .type i,@object # @i
        .section .tdata,"awT",@progbits
        .globl i
        .align 4
i:
        .long 7 # 0x7
        .size i, 4

... is given ELF symbol type STT_TLS by gcc's assembler, but
STT_OBJECT by clang's assembler.

I think this used to work, a few weeks ago. Has anything changed in
this are recently?

Thanks,
Jay.

The .type directive should probably specify type "tls_object" rather
than just "object". But I think gas infers that this is a TLS symbol
anyway, because it is mentioned in TLS-related relocations. See this
thread and follow-ups:

http://www.cygwin.com/ml/binutils/2002-11/msg00409.html

Jay.

Delving a bit deeper, the difference seems to be that symbol "i" in
the assembler source:

   \.type   i,@object               \# @i
   \.section        \.tdata,&quot;awT&quot;,@progbits
   \.globl  i
   \.align  4

i:
.long 7 # 0x7
.size i, 4

... is given ELF symbol type STT_TLS by gcc's assembler, but
STT_OBJECT by clang's assembler.

The .type directive should probably specify type "tls_object" rather
than just "object".

The attached patch fixes this, and it makes my favourite (proprietary)
app work on Linux when compiled with clang.

But I think gas infers that this is a TLS symbol
anyway, because it is mentioned in TLS-related relocations.

I still think clang's assembler needs to do something like this, if it
wants to be able to assembler .s files generated by GCC.

Jay.

typetls.diff (919 Bytes)

I still think clang's assembler needs to do something like this, if it
wants to be able to assembler .s files generated by GCC.

Working on it.

Jay.

Cheers,
Rafael

Working on it.

Looks like gas actually uses the fact that it is defined in a tls
section, so I copied that behavior.

Cheers,
Rafael