diff options
45 files changed, 2911 insertions, 0 deletions
diff --git a/test/tls/Makefile b/test/tls/Makefile new file mode 100644 index 000000000..223ad7a87 --- /dev/null +++ b/test/tls/Makefile @@ -0,0 +1,107 @@ +# uClibc TLS tests +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + +TESTS := tst-tls1 tst-tls2 tst-tls3 tst-tls4 tst-tls5 tst-tls6 tst-tls7 \ + tst-tls8 tst-tls9 tst-tls10 tst-tls11 tst-tls12 tst-tls13 \ + tst-tls14 tst-tls15 tst-tls16 tst-tls1-static tst-tls2-static \ + tst-tls9-static +TESTS_DISABLED := tst-tls1-static tst-tls2-static tst-tls9-static + +include ../Test.mak + +TARGET_ARCH := $(strip $(subst ",, $(strip $(TARGET_ARCH)))) +PTDIR := $(top_builddir)libpthread/nptl + +EXTRA_CFLAGS := -DNOT_IN_libc=1 \ + -std=gnu99 -I. -I$(PTDIR) \ + -I$(PTDIR)/sysdeps/unix/sysv/linux/$(TARGET_ARCH) \ + -I$(PTDIR)/sysdeps/$(TARGET_ARCH) \ + -I$(PTDIR)/sysdeps/unix/sysv/linux \ + -I$(PTDIR)/sysdeps/pthread \ + -I$(PTDIR)/sysdeps/pthread/bits \ + -I$(PTDIR)/sysdeps/generic \ + -I$(top_builddir)ldso/include \ + -I$(top_builddir)ldso/ldso/$(TARGET_ARCH) \ + -include $(top_builddir)include/libc-symbols.h + +CFLAGS_tst-tlsmod1.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod2.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod3.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod4.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod5.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod6.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod7.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod8.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod9.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod10.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod11.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod12.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod13.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod13a.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod14a.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod14b.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod15a.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod15b.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod16.so := -fPIC -DSHARED -shared + +LDFLAGS_tst-tlsmod1.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod2.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod3.so := -shared -static-libgcc -L$(top_builddir)lib \ + tst-tlsmod2.so +LDFLAGS_tst-tlsmod4.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod5.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod6.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod7.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod8.so := -shared -static-libgcc -L$(top_builddir)lib \ + tst-tlsmod7.so +LDFLAGS_tst-tlsmod9.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod10.so := -shared -static-libgcc -L$(top_builddir)lib \ + tst-tlsmod9.so +LDFLAGS_tst-tlsmod11.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod12.so := -shared -static-libgcc -L$(top_builddir)lib \ + tst-tlsmod11.so +LDFLAGS_tst-tlsmod13.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod13a.so := -shared -static-libgcc -L$(top_builddir)lib \ + tst-tlsmod13.so +LDFLAGS_tst-tlsmod14a.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod14b.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod15a.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod15b.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod16.so := -shared -static-libgcc -L$(top_builddir)lib + +LDFLAGS_tst-tls3 := tst-tlsmod1.so +LDFLAGS_tst-tls4 := -ldl +LDFLAGS_tst-tls5 := -ldl +LDFLAGS_tst-tls6 := -ldl +LDFLAGS_tst-tls7 := -ldl +LDFLAGS_tst-tls8 := -ldl +LDFLAGS_tst-tls9 := -ldl +LDFLAGS_tst-tls10 := -Wl,-rpath-link=. tst-tlsmod8.so +LDFLAGS_tst-tls11 := -Wl,-rpath-link=. tst-tlsmod10.so +LDFLAGS_tst-tls12 := -Wl,-rpath-link=. tst-tlsmod12.so +LDFLAGS_tst-tls13 := -ldl -Wl,-rpath-link=. +LDFLAGS_tst-tls14 := -ldl -Wl,-rpath-link=. tst-tlsmod14a.so +LDFLAGS_tst-tls15 := -ldl -Wl,-rpath-link=. +LDFLAGS_tst-tls16 := tst-tlsmod16.so + +tst-tls3: tst-tlsmod1.so +tst-tls4: tst-tlsmod2.so +tst-tls5: tst-tlsmod2.so +tst-tls6: tst-tlsmod2.so +tst-tls7: tst-tlsmod2.so tst-tlsmod3.so +tst-tls8: tst-tlsmod2.so tst-tlsmod3.so tst-tlsmod4.so +tst-tls9: tst-tlsmod5.so tst-tlsmod6.so +tst-tls10: tst-tlsmod7.so tst-tlsmod8.so +tst-tls11: tst-tlsmod9.so tst-tlsmod10.so +tst-tls12: tst-tlsmod11.so tst-tlsmod12.so +tst-tls13: tst-tlsmod13.so tst-tlsmod13a.so +tst-tls14: tst-tlsmod14a.so tst-tlsmod14b.so +tst-tls15: tst-tlsmod15a.so tst-tlsmod15b.so +tst-tls16: tst-tlsmod16.so + +RET_tst-tls13 := 1 +ifeq ($(TARGET_ARCH),mips) +RET_tst-tls15 := 1 +endif + +WRAPPER := env LD_LIBRARY_PATH="$$PWD:.:$(LD_LIBRARY_PATH)" diff --git a/test/tls/README b/test/tls/README new file mode 100644 index 000000000..06c9eb743 --- /dev/null +++ b/test/tls/README @@ -0,0 +1,8 @@ +These tests were imported from 'glibc/elf' and are responsible for testing +the TLS functionality of the dynamic loader. The file 'tls-macros-mips.h' +is a copy of 'glibc/sysdeps/mips/tls-macros.h'. Dependency and link orders +are critical and should NOT be changed. Even if you think you know what +you are doing, do not touch the Makefile without posting to the uClibc +development mailing list. + +-Steve <sjhill@uclibc.org> diff --git a/test/tls/tls-macros-arm.h b/test/tls/tls-macros-arm.h new file mode 100644 index 000000000..13d0f9752 --- /dev/null +++ b/test/tls/tls-macros-arm.h @@ -0,0 +1,51 @@ +#define TLS_LE(x) \ + ({ int *__result; \ + void *tp = __builtin_thread_pointer (); \ + __asm__ ("ldr %0, 1f; " \ + "add %0, %1, %0; " \ + "b 2f; " \ + "1: .word " #x "(tpoff); " \ + "2: " \ + : "=&r" (__result) : "r" (tp)); \ + __result; }) + +#define TLS_IE(x) \ + ({ int *__result; \ + void *tp = __builtin_thread_pointer (); \ + __asm__ ("ldr %0, 1f; " \ + "3: ldr %0, [pc, %0];" \ + "add %0, %1, %0; " \ + "b 2f; " \ + "1: .word " #x "(gottpoff) + (. - 3b - 8); " \ + "2: " \ + : "=&r" (__result) : "r" (tp)); \ + __result; }) + +#define TLS_LD(x) \ + ({ char *__result; \ + int __offset; \ + extern void *__tls_get_addr (void *); \ + __asm__ ("ldr %0, 2f; " \ + "1: add %0, pc, %0; " \ + "b 3f; " \ + "2: .word " #x "(tlsldm) + (. - 1b - 8); " \ + "3: " \ + : "=r" (__result)); \ + __result = (char *)__tls_get_addr (__result); \ + __asm__ ("ldr %0, 1f; " \ + "b 2f; " \ + "1: .word " #x "(tlsldo); " \ + "2: " \ + : "=r" (__offset)); \ + (int *) (__result + __offset); }) + +#define TLS_GD(x) \ + ({ int *__result; \ + extern void *__tls_get_addr (void *); \ + __asm__ ("ldr %0, 2f; " \ + "1: add %0, pc, %0; " \ + "b 3f; " \ + "2: .word " #x "(tlsgd) + (. - 1b - 8); " \ + "3: " \ + : "=r" (__result)); \ + (int *)__tls_get_addr (__result); }) diff --git a/test/tls/tls-macros-mips.h b/test/tls/tls-macros-mips.h new file mode 100644 index 000000000..0db383032 --- /dev/null +++ b/test/tls/tls-macros-mips.h @@ -0,0 +1,88 @@ +/* Macros to support TLS testing in times of missing compiler support. */ + +#if _MIPS_SIM != _ABI64 + +/* These versions are for o32 and n32. */ + +# define TLS_GD(x) \ + ({ void *__result; \ + extern void *__tls_get_addr (void *); \ + __asm__ ("addiu %0, $28, %%tlsgd(" #x ")" \ + : "=r" (__result)); \ + (int *)__tls_get_addr (__result); }) +#else +# define TLS_GD(x) \ + ({ void *__result; \ + extern void *__tls_get_addr (void *); \ + __asm__ ("daddiu %0, $28, %%tlsgd(" #x ")" \ + : "=r" (__result)); \ + (int *)__tls_get_addr (__result); }) +#endif + +#if _MIPS_SIM != _ABI64 +# define TLS_LD(x) \ + ({ void *__result; \ + extern void *__tls_get_addr (void *); \ + __asm__ ("addiu %0, $28, %%tlsldm(" #x ")" \ + : "=r" (__result)); \ + __result = __tls_get_addr (__result); \ + __asm__ ("lui $3,%%dtprel_hi(" #x ")\n\t" \ + "addiu $3,$3,%%dtprel_lo(" #x ")\n\t" \ + "addu %0,%0,$3" \ + : "+r" (__result) : : "$3"); \ + __result; }) +# define TLS_IE(x) \ + ({ void *__result; \ + __asm__ (".set push\n\t.set mips32r2\n\t" \ + "rdhwr\t%0,$29\n\t.set pop" \ + : "=v" (__result)); \ + __asm__ ("lw $3,%%gottprel(" #x ")($28)\n\t" \ + "addu %0,%0,$3" \ + : "+r" (__result) : : "$3"); \ + __result; }) +# define TLS_LE(x) \ + ({ void *__result; \ + __asm__ (".set push\n\t.set mips32r2\n\t" \ + "rdhwr\t%0,$29\n\t.set pop" \ + : "=v" (__result)); \ + __asm__ ("lui $3,%%tprel_hi(" #x ")\n\t" \ + "addiu $3,$3,%%tprel_lo(" #x ")\n\t" \ + "addu %0,%0,$3" \ + : "+r" (__result) : : "$3"); \ + __result; }) + +#else + +/* These versions are for n64. */ + +# define TLS_LD(x) \ + ({ void *__result; \ + extern void *__tls_get_addr (void *); \ + __asm__ ("daddiu %0, $28, %%tlsldm(" #x ")" \ + : "=r" (__result)); \ + __result = __tls_get_addr (__result); \ + __asm__ ("lui $3,%%dtprel_hi(" #x ")\n\t" \ + "daddiu $3,$3,%%dtprel_lo(" #x ")\n\t" \ + "daddu %0,%0,$3" \ + : "+r" (__result) : : "$3"); \ + __result; }) +# define TLS_IE(x) \ + ({ void *__result; \ + __asm__ (".set push\n\t.set mips32r2\n\t" \ + "rdhwr\t%0,$29\n\t.set pop" \ + : "=v" (__result)); \ + __asm__ ("ld $3,%%gottprel(" #x ")($28)\n\t" \ + "daddu %0,%0,$3" \ + : "+r" (__result) : : "$3"); \ + __result; }) +# define TLS_LE(x) \ + ({ void *__result; \ + __asm__ (".set push\n\t.set mips32r2\n\t" \ + "rdhwr\t%0,$29\n\t.set pop" \ + : "=v" (__result)); \ + __asm__ ("lui $3,%%tprel_hi(" #x ")\n\t" \ + "daddiu $3,$3,%%tprel_lo(" #x ")\n\t" \ + "daddu %0,%0,$3" \ + : "+r" (__result) : : "$3"); \ + __result; }) +#endif diff --git a/test/tls/tls-macros-thumb.h b/test/tls/tls-macros-thumb.h new file mode 100644 index 000000000..dfa6582a5 --- /dev/null +++ b/test/tls/tls-macros-thumb.h @@ -0,0 +1,57 @@ +#define TLS_LE(x) \ + ({ int *__result; \ + void *tp = __builtin_thread_pointer (); \ + __asm__ ("ldr %0, 1f; " \ + "add %0, %1, %0; " \ + "b 2f; " \ + ".align 2; " \ + "1: .word " #x "(tpoff); " \ + "2: " \ + : "=&r" (__result) : "r" (tp)); \ + __result; }) + +#define TLS_IE(x) \ + ({ int *__result; \ + int tmp; \ + void *tp = __builtin_thread_pointer (); \ + __asm__ ("ldr %0, 1f; " \ + "adr %1, 1f; " \ + "ldr %0, [%1, %0]; " \ + "add %0, %2, %0; " \ + "b 2f; " \ + ".align 2; " \ + "1: .word " #x "(gottpoff); " \ + "2: " \ + : "=&r" (__result), "=&r"(tmp) : "r" (tp)); \ + __result; }) + +#define TLS_LD(x) \ + ({ char *__result; \ + int __offset; \ + extern void *__tls_get_addr (void *); \ + __asm__ ("ldr %0, 2f; " \ + ".align 2; " \ + "1: add %0, pc, %0; " \ + "b 3f; " \ + "2: .word " #x "(tlsldm) + (. - 1b - 4); " \ + "3: " \ + : "=r" (__result)); \ + __result = (char *)__tls_get_addr (__result); \ + __asm__ ("ldr %0, 1f; " \ + "b 2f; " \ + "1: .word " #x "(tlsldo); " \ + "2: " \ + : "=r" (__offset)); \ + (int *) (__result + __offset); }) + +#define TLS_GD(x) \ + ({ int *__result; \ + extern void *__tls_get_addr (void *); \ + __asm__ ("ldr %0, 2f; " \ + ".align 2; " \ + "1: add %0, pc, %0; " \ + "b 3f; " \ + "2: .word " #x "(tlsgd) + (. - 1b - 4); " \ + "3: " \ + : "=r" (__result)); \ + (int *)__tls_get_addr (__result); }) diff --git a/test/tls/tls-macros.h b/test/tls/tls-macros.h new file mode 100644 index 000000000..29a75df95 --- /dev/null +++ b/test/tls/tls-macros.h @@ -0,0 +1,861 @@ +/* Macros to support TLS testing in times of missing compiler support. */ + +#define COMMON_INT_DEF(x) \ + __asm__ (".tls_common " #x ",4,4") +/* XXX Until we get compiler support we don't need declarations. */ +#define COMMON_INT_DECL(x) + +/* XXX This definition will probably be machine specific, too. */ +#define VAR_INT_DEF(x) \ + __asm__ (".section .tdata\n\t" \ + ".globl " #x "\n" \ + ".balign 4\n" \ + #x ":\t.long 0\n\t" \ + ".size " #x ",4\n\t" \ + ".previous") +/* XXX Until we get compiler support we don't need declarations. */ +#define VAR_INT_DECL(x) + +#ifdef __mips__ +#include <tls-macros-mips.h> +#endif + +#ifdef __arm__ +#ifdef __thumb__ +#include <tls-macros-thumb.h> +#else +#include <tls-macros-arm.h> +#endif +#endif + + /* XXX Each architecture must have its own asm for now. */ +#ifdef __i386__ +# define TLS_LE(x) \ + ({ int *__l; \ + __asm__ ("movl %%gs:0,%0\n\t" \ + "subl $" #x "@tpoff,%0" \ + : "=r" (__l)); \ + __l; }) + +# ifdef PIC +# define TLS_IE(x) \ + ({ int *__l; \ + __asm__ ("movl %%gs:0,%0\n\t" \ + "subl " #x "@gottpoff(%%ebx),%0" \ + : "=r" (__l)); \ + __l; }) +# else +# define TLS_IE(x) \ + ({ int *__l, __b; \ + __asm__ ("call 1f\n\t" \ + ".subsection 1\n" \ + "1:\tmovl (%%esp), %%ebx\n\t" \ + "ret\n\t" \ + ".previous\n\t" \ + "addl $_GLOBAL_OFFSET_TABLE_, %%ebx\n\t" \ + "movl %%gs:0,%0\n\t" \ + "subl " #x "@gottpoff(%%ebx),%0" \ + : "=r" (__l), "=&b" (__b)); \ + __l; }) +# endif + +# ifdef PIC +# define TLS_LD(x) \ + ({ int *__l, __c, __d; \ + __asm__ ("leal " #x "@tlsldm(%%ebx),%%eax\n\t" \ + "call ___tls_get_addr@plt\n\t" \ + "leal " #x "@dtpoff(%%eax), %%eax" \ + : "=a" (__l), "=&c" (__c), "=&d" (__d)); \ + __l; }) +# else +# define TLS_LD(x) \ + ({ int *__l, __b, __c, __d; \ + __asm__ ("call 1f\n\t" \ + ".subsection 1\n" \ + "1:\tmovl (%%esp), %%ebx\n\t" \ + "ret\n\t" \ + ".previous\n\t" \ + "addl $_GLOBAL_OFFSET_TABLE_, %%ebx\n\t" \ + "leal " #x "@tlsldm(%%ebx),%%eax\n\t" \ + "call ___tls_get_addr@plt\n\t" \ + "leal " #x "@dtpoff(%%eax), %%eax" \ + : "=a" (__l), "=&b" (__b), "=&c" (__c), "=&d" (__d)); \ + __l; }) +# endif + +# ifdef PIC +# define TLS_GD(x) \ + ({ int *__l, __c, __d; \ + __asm__ ("leal " #x "@tlsgd(%%ebx),%%eax\n\t" \ + "call ___tls_get_addr@plt\n\t" \ + "nop" \ + : "=a" (__l), "=&c" (__c), "=&d" (__d)); \ + __l; }) +# else +# define TLS_GD(x) \ + ({ int *__l, __b, __c, __d; \ + __asm__ ("call 1f\n\t" \ + ".subsection 1\n" \ + "1:\tmovl (%%esp), %%ebx\n\t" \ + "ret\n\t" \ + ".previous\n\t" \ + "addl $_GLOBAL_OFFSET_TABLE_, %%ebx\n\t" \ + "leal " #x "@tlsgd(%%ebx),%%eax\n\t" \ + "call ___tls_get_addr@plt\n\t" \ + "nop" \ + : "=a" (__l), "=&b" (__b), "=&c" (__c), "=&d" (__d)); \ + __l; }) +# endif + +#elif defined __x86_64__ + +# define TLS_LE(x) \ + ({ int *__l; \ + __asm__ ("movq %%fs:0,%0\n\t" \ + "leaq " #x "@tpoff(%0), %0" \ + : "=r" (__l)); \ + __l; }) + +# define TLS_IE(x) \ + ({ int *__l; \ + __asm__ ("movq %%fs:0,%0\n\t" \ + "addq " #x "@gottpoff(%%rip),%0" \ + : "=r" (__l)); \ + __l; }) + +# define TLS_LD(x) \ + ({ int *__l, __c, __d; \ + __asm__ ("leaq " #x "@tlsld(%%rip),%%rdi\n\t" \ + "call __tls_get_addr@plt\n\t" \ + "leaq " #x "@dtpoff(%%rax), %%rax" \ + : "=a" (__l), "=&c" (__c), "=&d" (__d) \ + : : "rdi", "rsi", "r8", "r9", "r10", "r11"); \ + __l; }) + +# define TLS_GD(x) \ + ({ int *__l, __c, __d; \ + __asm__ (".byte 0x66\n\t" \ + "leaq " #x "@tlsgd(%%rip),%%rdi\n\t" \ + ".word 0x6666\n\t" \ + "rex64\n\t" \ + "call __tls_get_addr@plt" \ + : "=a" (__l), "=&c" (__c), "=&d" (__d) \ + : : "rdi", "rsi", "r8", "r9", "r10", "r11"); \ + __l; }) + +#elif defined __sh__ + +# define TLS_LE(x) \ + ({ int *__l; void *__tp; \ + __asm__ ("stc gbr,%1\n\t" \ + "mov.l 1f,%0\n\t" \ + "bra 2f\n\t" \ + " add %1,%0\n\t" \ + ".align 2\n\t" \ + "1: .long " #x "@tpoff\n\t" \ + "2:" \ + : "=r" (__l), "=r" (__tp)); \ + __l; }) + +# ifdef PIC +# define TLS_IE(x) \ + ({ int *__l; void *__tp; \ + register void *__gp __asm__("r12"); \ + __asm__ ("mov.l 1f,r0\n\t" \ + "stc gbr,%1\n\t" \ + "mov.l @(r0,r12),%0\n\t" \ + "bra 2f\n\t" \ + " add %1,%0\n\t" \ + ".align 2\n\t" \ + "1: .long " #x "@gottpoff\n\t" \ + "2:" \ + : "=r" (__l), "=r" (__tp) : "r" (__gp) : "r0"); \ + __l; }) +# else +# define TLS_IE(x) \ + ({ int *__l; void *__tp; \ + __asm__ ("mov.l r12,@-r15\n\t" \ + "mova 0f,r0\n\t" \ + "mov.l 0f,r12\n\t" \ + "add r0,r12\n\t" \ + "mov.l 1f,r0\n\t" \ + "stc gbr,%1\n\t" \ + "mov.l @(r0,r12),%0\n\t" \ + "bra 2f\n\t" \ + " add %1,%0\n\t" \ + ".align 2\n\t" \ + "1: .long " #x "@gottpoff\n\t" \ + "0: .long _GLOBAL_OFFSET_TABLE_\n\t" \ + "2: mov.l @r15+,r12" \ + : "=r" (__l), "=r" (__tp) : : "r0"); \ + __l; }) +#endif + +# ifdef PIC +# define TLS_LD(x) \ + ({ int *__l; \ + register void *__gp __asm__("r12"); \ + __asm__ ("mov.l 1f,r4\n\t" \ + "mova 2f,r0\n\t" \ + "mov.l 2f,r1\n\t" \ + "add r0,r1\n\t" \ + "jsr @r1\n\t" \ + " add r12,r4\n\t" \ + "bra 4f\n\t" \ + " nop\n\t" \ + ".align 2\n\t" \ + "1: .long " #x "@tlsldm\n\t" \ + "2: .long __tls_get_addr@plt\n\t" \ + "4: mov.l 3f,%0\n\t" \ + "bra 5f\n\t" \ + " add r0,%0\n\t" \ + ".align 2\n\t" \ + "3: .long " #x "@dtpoff\n\t" \ + "5:" \ + : "=r" (__l) : "r" (__gp) : "r0", "r1", "r2", "r3", "r4", "r5", \ + "r6", "r7", "pr", "t"); \ + __l; }) +# else +# define TLS_LD(x) \ + ({ int *__l; \ + __asm__ ("mov.l r12,@-r15\n\t" \ + "mova 0f,r0\n\t" \ + "mov.l 0f,r12\n\t" \ + "add r0,r12\n\t" \ + "mov.l 1f,r4\n\t" \ + "mova 2f,r0\n\t" \ + "mov.l 2f,r1\n\t" \ + "add r0,r1\n\t" \ + "jsr @r1\n\t" \ + " add r12,r4\n\t" \ + "bra 4f\n\t" \ + " nop\n\t" \ + ".align 2\n\t" \ + "1: .long " #x "@tlsldm\n\t" \ + "2: .long __tls_get_addr@plt\n\t" \ + "0: .long _GLOBAL_OFFSET_TABLE_\n\t" \ + "4: mov.l 3f,%0\n\t" \ + "bra 5f\n\t" \ + " add r0,%0\n\t" \ + ".align 2\n\t" \ + "3: .long " #x "@dtpoff\n\t" \ + "5: mov.l @r15+,r12" \ + : "=r" (__l) : : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ + "pr", "t"); \ + __l; }) +#endif + +# ifdef PIC +# define TLS_GD(x) \ + ({ int *__l; \ + register void *__gp __asm__("r12"); \ + __asm__ ("mov.l 1f,r4\n\t" \ + "mova 2f,r0\n\t" \ + "mov.l 2f,r1\n\t" \ + "add r0,r1\n\t" \ + "jsr @r1\n\t" \ + " add r12,r4\n\t" \ + "bra 3f\n\t" \ + " mov r0,%0\n\t" \ + ".align 2\n\t" \ + "1: .long " #x "@tlsgd\n\t" \ + "2: .long __tls_get_addr@plt\n\t" \ + "3:" \ + : "=r" (__l) : "r" (__gp) : "r0", "r1", "r2", "r3", "r4", "r5", \ + "r6", "r7", "pr", "t"); \ + __l; }) +# else +# define TLS_GD(x) \ + ({ int *__l; \ + __asm__ ("mov.l r12,@-r15\n\t" \ + "mova 0f,r0\n\t" \ + "mov.l 0f,r12\n\t" \ + "add r0,r12\n\t" \ + "mov.l 1f,r4\n\t" \ + "mova 2f,r0\n\t" \ + "mov.l 2f,r1\n\t" \ + "add r0,r1\n\t" \ + "jsr @r1\n\t" \ + " add r12,r4\n\t" \ + "bra 3f\n\t" \ + " mov r0,%0\n\t" \ + ".align 2\n\t" \ + "1: .long " #x "@tlsgd\n\t" \ + "2: .long __tls_get_addr@plt\n\t" \ + "0: .long _GLOBAL_OFFSET_TABLE_\n\t" \ + "3: mov.l @r15+,r12" \ + : "=r" (__l) : : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ + "pr", "t"); \ + __l; }) +#endif + +#elif defined __alpha__ + +register void *__gp __asm__("$29"); + +# define TLS_LE(x) \ + ({ int *__l; \ + __asm__ ("call_pal 158\n\tlda $0," #x "($0)\t\t!tprel" : "=v"(__l)); \ + __l; }) + +# define TLS_IE(x) \ + ({ char *__tp; unsigned long __o; \ + __asm__ ("call_pal 158\n\tldq %1," #x "($gp)\t\t!gottprel" \ + : "=v"(__tp), "=r"(__o) : "r"(__gp)); \ + (int *)(__tp + __o); }) + +# define TLS_LD(x) \ + ({ extern void *__tls_get_addr(void *); int *__l; void *__i; \ + __asm__ ("lda %0," #x "($gp)\t\t!tlsldm" : "=r" (__i) : "r"(__gp)); \ + __i = __tls_get_addr(__i); \ + __asm__ ("lda %0, " #x "(%1)\t\t!dtprel" : "=r"(__l) : "r"(__i)); \ + __l; }) + +# define TLS_GD(x) \ + ({ extern void *__tls_get_addr(void *); void *__i; \ + __asm__ ("lda %0," #x "($gp)\t\t!tlsgd" : "=r" (__i) : "r"(__gp)); \ + (int *) __tls_get_addr(__i); }) + + +#elif defined __ia64__ + +# define TLS_LE(x) \ + ({ void *__l; \ + __asm__ ("mov r2=r13\n\t" \ + ";;\n\t" \ + "addl %0=@tprel(" #x "),r2\n\t" \ + : "=r" (__l) : : "r2" ); __l; }) + +# define TLS_IE(x) \ + ({ void *__l; \ + register long __gp __asm__ ("gp"); \ + __asm__ (";;\n\t" \ + "addl r16=@ltoff(@tprel(" #x ")),gp\n\t" \ + ";;\n\t" \ + "ld8 r17=[r16]\n\t" \ + ";;\n\t" \ + "add %0=r13,r17\n\t" \ + ";;\n\t" \ + : "=r" (__l) : "r" (__gp) : "r16", "r17" ); __l; }) + +# define __TLS_CALL_CLOBBERS \ + "r2", "r3", "r8", "r9", "r10", "r11", "r14", "r15", "r16", "r17", \ + "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", \ + "r27", "r28", "r29", "r30", "r31", \ + "p6", "p7", "p8", "p9", "p10", "p11", "p12", "p13", "p14", "p15", \ + "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \ + "b6", "b7", \ + "out0", "out1", "out2", "out3", "out4", "out5", "out6", "out7" + +# define TLS_LD(x) \ + ({ void *__l; \ + register long __gp __asm__ ("gp"); \ + __asm__ (";;\n\t" \ + "mov loc0=gp\n\t" \ + "addl r16=@ltoff(@dtpmod(" #x ")),gp\n\t" \ + "addl out1=@dtprel(" #x "),r0\n\t" \ + ";;\n\t" \ + "ld8 out0=[r16]\n\t" \ + "br.call.sptk.many b0=__tls_get_addr" \ + ";;\n\t" \ + "mov gp=loc0\n\t" \ + "mov %0=r8\n\t" \ + ";;\n\t" \ + : "=r" (__l) : "r" (__gp) : "loc0", __TLS_CALL_CLOBBERS); \ + __l; }) + +# define TLS_GD(x) \ + ({ void *__l; \ + register long __gp __asm__ ("gp"); \ + __asm__ (";;\n\t" \ + "mov loc0=gp\n\t" \ + "addl r16=@ltoff(@dtpmod(" #x ")),gp\n\t" \ + "addl r17=@ltoff(@dtprel(" #x ")),gp\n\t" \ + ";;\n\t" \ + "ld8 out0=[r16]\n\t" \ + "ld8 out1=[r17]\n\t" \ + "br.call.sptk.many b0=__tls_get_addr" \ + ";;\n\t" \ + "mov gp=loc0\n\t" \ + "mov %0=r8\n\t" \ + ";;\n\t" \ + : "=r" (__l) : "r" (__gp) : "loc0", __TLS_CALL_CLOBBERS); \ + __l; }) + +#elif defined __sparc__ && !defined __arch64__ + +# define TLS_LE(x) \ + ({ int *__l; \ + __asm__ ("sethi %%tle_hix22(" #x "), %0" : "=r" (__l)); \ + __asm__ ("xor %1, %%tle_lox10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ + __asm__ ("add %%g7, %1, %0" : "=r" (__l) : "r" (__l)); \ + __l; }) + +# ifdef __PIC__ +# define TLS_LOAD_PIC \ + ({ register long pc __asm__ ("%o7"); \ + long got; \ + __asm__ ("sethi %%hi(_GLOBAL_OFFSET_TABLE_-4), %1\n\t" \ + "call .+8\n\t" \ + "add %1, %%lo(_GLOBAL_OFFSET_TABLE_+4), %1\n\t" \ + "add %1, %0, %1\n\t" \ + : "=r" (pc), "=r" (got)); \ + got; }) +# else +# define TLS_LOAD_PIC \ + ({ long got; \ + __asm__ (".hidden _GLOBAL_OFFSET_TABLE_\n\t" \ + "sethi %%hi(_GLOBAL_OFFSET_TABLE_), %0\n\t" \ + "or %0, %%lo(_GLOBAL_OFFSET_TABLE_), %0" \ + : "=r" (got)); \ + got; }) +# endif + +# define TLS_IE(x) \ + ({ int *__l; \ + __asm__ ("sethi %%tie_hi22(" #x "), %0" : "=r" (__l)); \ + __asm__ ("add %1, %%tie_lo10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ + __asm__ ("ld [%1 + %2], %0, %%tie_ld(" #x ")" \ + : "=r" (__l) : "r" (TLS_LOAD_PIC), "r" (__l)); \ + __asm__ ("add %%g7, %1, %0, %%tie_add(" #x ")" : "=r" (__l) : "r" (__l)); \ + __l; }) + +# define TLS_LD(x) \ + ({ int *__l; register void *__o0 __asm__ ("%o0"); \ + long __o; \ + __asm__ ("sethi %%tldm_hi22(" #x "), %0" : "=r" (__l)); \ + __asm__ ("add %1, %%tldm_lo10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ + __asm__ ("add %1, %2, %0, %%tldm_add(" #x ")" \ + : "=r" (__o0) : "r" (TLS_LOAD_PIC), "r" (__l)); \ + __asm__ ("call __tls_get_addr, %%tgd_call(" #x ")\n\t" \ + " nop" \ + : "=r" (__o0) : "0" (__o0) \ + : "g1", "g2", "g3", "g4", "g5", "g6", "o1", "o2", "o3", "o4", \ + "o5", "o7", "cc"); \ + __asm__ ("sethi %%tldo_hix22(" #x "), %0" : "=r" (__o)); \ + __asm__ ("xor %1, %%tldo_lox10(" #x "), %0" : "=r" (__o) : "r" (__o)); \ + __asm__ ("add %1, %2, %0, %%tldo_add(" #x ")" : "=r" (__l) \ + : "r" (__o0), "r" (__o)); \ + __l; }) + +# define TLS_GD(x) \ + ({ int *__l; register void *__o0 __asm__ ("%o0"); \ + __asm__ ("sethi %%tgd_hi22(" #x "), %0" : "=r" (__l)); \ + __asm__ ("add %1, %%tgd_lo10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ + __asm__ ("add %1, %2, %0, %%tgd_add(" #x ")" \ + : "=r" (__o0) : "r" (TLS_LOAD_PIC), "r" (__l)); \ + __asm__ ("call __tls_get_addr, %%tgd_call(" #x ")\n\t" \ + " nop" \ + : "=r" (__o0) : "0" (__o0) \ + : "g1", "g2", "g3", "g4", "g5", "g6", "o1", "o2", "o3", "o4", \ + "o5", "o7", "cc"); \ + __o0; }) + +#elif defined __sparc__ && defined __arch64__ + +# define TLS_LE(x) \ + ({ int *__l; \ + __asm__ ("sethi %%tle_hix22(" #x "), %0" : "=r" (__l)); \ + __asm__ ("xor %1, %%tle_lox10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ + __asm__ ("add %%g7, %1, %0" : "=r" (__l) : "r" (__l)); \ + __l; }) + +# ifdef __PIC__ +# define TLS_LOAD_PIC \ + ({ long pc, got; \ + __asm__ ("sethi %%hi(_GLOBAL_OFFSET_TABLE_-4), %1\n\t" \ + "rd %%pc, %0\n\t" \ + "add %1, %%lo(_GLOBAL_OFFSET_TABLE_+4), %1\n\t" \ + "add %1, %0, %1\n\t" \ + : "=r" (pc), "=r" (got)); \ + got; }) +# else +# define TLS_LOAD_PIC \ + ({ long got; \ + __asm__ (".hidden _GLOBAL_OFFSET_TABLE_\n\t" \ + "sethi %%hi(_GLOBAL_OFFSET_TABLE_), %0\n\t" \ + "or %0, %%lo(_GLOBAL_OFFSET_TABLE_), %0" \ + : "=r" (got)); \ + got; }) +# endif + +# define TLS_IE(x) \ + ({ int *__l; \ + __asm__ ("sethi %%tie_hi22(" #x "), %0" : "=r" (__l)); \ + __asm__ ("add %1, %%tie_lo10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ + __asm__ ("ldx [%1 + %2], %0, %%tie_ldx(" #x ")" \ + : "=r" (__l) : "r" (TLS_LOAD_PIC), "r" (__l)); \ + __asm__ ("add %%g7, %1, %0, %%tie_add(" #x ")" : "=r" (__l) : "r" (__l)); \ + __l; }) + +# define TLS_LD(x) \ + ({ int *__l; register void *__o0 __asm__ ("%o0"); \ + long __o; \ + __asm__ ("sethi %%tldm_hi22(" #x "), %0" : "=r" (__l)); \ + __asm__ ("add %1, %%tldm_lo10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ + __asm__ ("add %1, %2, %0, %%tldm_add(" #x ")" \ + : "=r" (__o0) : "r" (TLS_LOAD_PIC), "r" (__l)); \ + __asm__ ("call __tls_get_addr, %%tgd_call(" #x ")\n\t" \ + " nop" \ + : "=r" (__o0) : "0" (__o0) \ + : "g1", "g2", "g3", "g4", "g5", "g6", "o1", "o2", "o3", "o4", \ + "o5", "o7", "cc"); \ + __asm__ ("sethi %%tldo_hix22(" #x "), %0" : "=r" (__o)); \ + __asm__ ("xor %1, %%tldo_lox10(" #x "), %0" : "=r" (__o) : "r" (__o)); \ + __asm__ ("add %1, %2, %0, %%tldo_add(" #x ")" : "=r" (__l) \ + : "r" (__o0), "r" (__o)); \ + __l; }) + +# define TLS_GD(x) \ + ({ int *__l; register void *__o0 __asm__ ("%o0"); \ + __asm__ ("sethi %%tgd_hi22(" #x "), %0" : "=r" (__l)); \ + __asm__ ("add %1, %%tgd_lo10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ + __asm__ ("add %1, %2, %0, %%tgd_add(" #x ")" \ + : "=r" (__o0) : "r" (TLS_LOAD_PIC), "r" (__l)); \ + __asm__ ("call __tls_get_addr, %%tgd_call(" #x ")\n\t" \ + " nop" \ + : "=r" (__o0) : "0" (__o0) \ + : "g1", "g2", "g3", "g4", "g5", "g6", "o1", "o2", "o3", "o4", \ + "o5", "o7", "cc"); \ + __o0; }) + +#elif defined __s390x__ + +# define TLS_LE(x) \ + ({ unsigned long __offset; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.quad " #x "@ntpoff\n" \ + "1:\tlg %0,0(%0)" \ + : "=a" (__offset) : : "cc" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) + +# ifdef PIC +# define TLS_IE(x) \ + ({ unsigned long __offset; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.quad " #x "@gotntpoff\n" \ + "1:\tlg %0,0(%0)\n\t" \ + "lg %0,0(%0,%%r12):tls_load:" #x \ + : "=&a" (__offset) : : "cc" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# else +# define TLS_IE(x) \ + ({ unsigned long __offset; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.quad " #x "@indntpoff\n" \ + "1:\t lg %0,0(%0)\n\t" \ + "lg %0,0(%0):tls_load:" #x \ + : "=&a" (__offset) : : "cc" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# endif + +# ifdef PIC +# define TLS_LD(x) \ + ({ unsigned long __offset, __save12; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.quad " #x "@tlsldm\n\t" \ + ".quad " #x "@dtpoff\n" \ + "1:\tlgr %1,%%r12\n\t" \ + "larl %%r12,_GLOBAL_OFFSET_TABLE_\n\t" \ + "lg %%r2,0(%0)\n\t" \ + "brasl %%r14,__tls_get_offset@plt:tls_ldcall:" #x "\n\t" \ + "lg %0,8(%0)\n\t" \ + "algr %0,%%r2\n\t" \ + "lgr %%r12,%1" \ + : "=&a" (__offset), "=&a" (__save12) \ + : : "cc", "0", "1", "2", "3", "4", "5", "14" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# else +# define TLS_LD(x) \ + ({ unsigned long __offset; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.quad " #x "@tlsldm\n\t" \ + ".quad " #x "@dtpoff\n" \ + "1:\tlarl %%r12,_GLOBAL_OFFSET_TABLE_\n\t" \ + "lg %%r2,0(%0)\n\t" \ + "brasl %%r14,__tls_get_offset@plt:tls_ldcall:" #x "\n\t" \ + "lg %0,8(%0)\n\t" \ + "algr %0,%%r2" \ + : "=&a" (__offset) \ + : : "cc", "0", "1", "2", "3", "4", "5", "12", "14" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# endif + +# ifdef PIC +# define TLS_GD(x) \ + ({ unsigned long __offset, __save12; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.quad " #x "@tlsgd\n" \ + "1:\tlgr %1,%%r12\n\t" \ + "larl %%r12,_GLOBAL_OFFSET_TABLE_\n\t" \ + "lg %%r2,0(%0)\n\t" \ + "brasl %%r14,__tls_get_offset@plt:tls_gdcall:" #x "\n\t" \ + "lgr %0,%%r2\n\t" \ + "lgr %%r12,%1" \ + : "=&a" (__offset), "=&a" (__save12) \ + : : "cc", "0", "1", "2", "3", "4", "5", "14" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# else +# define TLS_GD(x) \ + ({ unsigned long __offset; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.quad " #x "@tlsgd\n" \ + "1:\tlarl %%r12,_GLOBAL_OFFSET_TABLE_\n\t" \ + "lg %%r2,0(%0)\n\t" \ + "brasl %%r14,__tls_get_offset@plt:tls_gdcall:" #x "\n\t" \ + "lgr %0,%%r2" \ + : "=&a" (__offset) \ + : : "cc", "0", "1", "2", "3", "4", "5", "12", "14" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# endif + +#elif defined __s390__ + +# define TLS_LE(x) \ + ({ unsigned long __offset; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.long " #x "@ntpoff\n" \ + "1:\tl %0,0(%0)" \ + : "=a" (__offset) : : "cc" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) + +# ifdef PIC +# define TLS_IE(x) \ + ({ unsigned long __offset; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.long " #x "@gotntpoff\n" \ + "1:\tl %0,0(%0)\n\t" \ + "l %0,0(%0,%%r12):tls_load:" #x \ + : "=&a" (__offset) : : "cc" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# else +# define TLS_IE(x) \ + ({ unsigned long __offset; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.long " #x "@indntpoff\n" \ + "1:\t l %0,0(%0)\n\t" \ + "l %0,0(%0):tls_load:" #x \ + : "=&a" (__offset) : : "cc" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# endif + +# ifdef PIC +# define TLS_LD(x) \ + ({ unsigned long __offset, __save12; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.long _GLOBAL_OFFSET_TABLE_-0b\n\t" \ + ".long __tls_get_offset@plt-0b\n\t" \ + ".long " #x "@tlsldm\n\t" \ + ".long " #x "@dtpoff\n" \ + "1:\tlr %1,%%r12\n\t" \ + "l %%r12,0(%0)\n\t" \ + "la %%r12,0(%%r12,%0)\n\t" \ + "l %%r1,4(%0)\n\t" \ + "l %%r2,8(%0)\n\t" \ + "bas %%r14,0(%%r1,%0):tls_ldcall:" #x "\n\t" \ + "l %0,12(%0)\n\t" \ + "alr %0,%%r2\n\t" \ + "lr %%r12,%1" \ + : "=&a" (__offset), "=&a" (__save12) \ + : : "cc", "0", "1", "2", "3", "4", "5" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# else +# define TLS_LD(x) \ + ({ unsigned long __offset; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.long _GLOBAL_OFFSET_TABLE_\n\t" \ + ".long __tls_get_offset@plt\n\t" \ + ".long " #x "@tlsldm\n\t" \ + ".long " #x "@dtpoff\n" \ + "1:\tl %%r12,0(%0)\n\t" \ + "l %%r1,4(%0)\n\t" \ + "l %%r2,8(%0)\n\t" \ + "bas %%r14,0(%%r1):tls_ldcall:" #x "\n\t" \ + "l %0,12(%0)\n\t" \ + "alr %0,%%r2" \ + : "=&a" (__offset) : : "cc", "0", "1", "2", "3", "4", "5", "12" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# endif + +# ifdef PIC +# define TLS_GD(x) \ + ({ unsigned long __offset, __save12; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.long _GLOBAL_OFFSET_TABLE_-0b\n\t" \ + ".long __tls_get_offset@plt-0b\n\t" \ + ".long " #x "@tlsgd\n" \ + "1:\tlr %1,%%r12\n\t" \ + "l %%r12,0(%0)\n\t" \ + "la %%r12,0(%%r12,%0)\n\t" \ + "l %%r1,4(%0)\n\t" \ + "l %%r2,8(%0)\n\t" \ + "bas %%r14,0(%%r1,%0):tls_gdcall:" #x "\n\t" \ + "lr %0,%%r2\n\t" \ + "lr %%r12,%1" \ + : "=&a" (__offset), "=&a" (__save12) \ + : : "cc", "0", "1", "2", "3", "4", "5" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# else +# define TLS_GD(x) \ + ({ unsigned long __offset; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.long _GLOBAL_OFFSET_TABLE_\n\t" \ + ".long __tls_get_offset@plt\n\t" \ + ".long " #x "@tlsgd\n" \ + "1:\tl %%r12,0(%0)\n\t" \ + "l %%r1,4(%0)\n\t" \ + "l %%r2,8(%0)\n\t" \ + "bas %%r14,0(%%r1):tls_gdcall:" #x "\n\t" \ + "lr %0,%%r2" \ + : "=&a" (__offset) : : "cc", "0", "1", "2", "3", "4", "5", "12" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# endif + +#elif defined __powerpc__ && !defined __powerpc64__ + +#include "config.h" + +# define __TLS_CALL_CLOBBERS \ + "0", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", \ + "lr", "ctr", "cr0", "cr1", "cr5", "cr6", "cr7" + +/* PowerPC32 Local Exec TLS access. */ +# define TLS_LE(x) \ + ({ int *__result; \ + __asm__ ("addi %0,2," #x "@tprel" \ + : "=r" (__result)); \ + __result; }) + +/* PowerPC32 Initial Exec TLS access. */ +# ifdef HAVE_ASM_PPC_REL16 +# define TLS_IE(x) \ + ({ int *__result; \ + __asm__ ("bcl 20,31,1f\n1:\t" \ + "mflr %0\n\t" \ + "addis %0,%0,_GLOBAL_OFFSET_TABLE_-1b@ha\n\t" \ + "addi %0,%0,_GLOBAL_OFFSET_TABLE_-1b@l\n\t" \ + "lwz %0," #x "@got@tprel(%0)\n\t" \ + "add %0,%0," #x "@tls" \ + : "=b" (__result) : \ + : "lr"); \ + __result; }) +# else +# define TLS_IE(x) \ + ({ int *__result; \ + __asm__ ("bl _GLOBAL_OFFSET_TABLE_@local-4\n\t" \ + "mflr %0\n\t" \ + "lwz %0," #x "@got@tprel(%0)\n\t" \ + "add %0,%0," #x "@tls" \ + : "=b" (__result) : \ + : "lr"); \ + __result; }) +# endif + +/* PowerPC32 Local Dynamic TLS access. */ +# ifdef HAVE_ASM_PPC_REL16 +# define TLS_LD(x) \ + ({ int *__result; \ + __asm__ ("bcl 20,31,1f\n1:\t" \ + "mflr 3\n\t" \ + "addis 3,3,_GLOBAL_OFFSET_TABLE_-1b@ha\n\t" \ + "addi 3,3,_GLOBAL_OFFSET_TABLE_-1b@l\n\t" \ + "addi 3,3," #x "@got@tlsld\n\t" \ + "bl __tls_get_addr@plt\n\t" \ + "addi %0,3," #x "@dtprel" \ + : "=r" (__result) : \ + : __TLS_CALL_CLOBBERS); \ + __result; }) +# else +# define TLS_LD(x) \ + ({ int *__result; \ + __asm__ ("bl _GLOBAL_OFFSET_TABLE_@local-4\n\t" \ + "mflr 3\n\t" \ + "addi 3,3," #x "@got@tlsld\n\t" \ + "bl __tls_get_addr@plt\n\t" \ + "addi %0,3," #x "@dtprel" \ + : "=r" (__result) : \ + : __TLS_CALL_CLOBBERS); \ + __result; }) +# endif + +/* PowerPC32 General Dynamic TLS access. */ +# ifdef HAVE_ASM_PPC_REL16 +# define TLS_GD(x) \ + ({ register int *__result __asm__ ("r3"); \ + __asm__ ("bcl 20,31,1f\n1:\t" \ + "mflr 3\n\t" \ + "addis 3,3,_GLOBAL_OFFSET_TABLE_-1b@ha\n\t" \ + "addi 3,3,_GLOBAL_OFFSET_TABLE_-1b@l\n\t" \ + "addi 3,3," #x "@got@tlsgd\n\t" \ + "bl __tls_get_addr@plt" \ + : : \ + : __TLS_CALL_CLOBBERS); \ + __result; }) +# else +# define TLS_GD(x) \ + ({ register int *__result __asm__ ("r3"); \ + __asm__ ("bl _GLOBAL_OFFSET_TABLE_@local-4\n\t" \ + "mflr 3\n\t" \ + "addi 3,3," #x "@got@tlsgd\n\t" \ + "bl __tls_get_addr@plt" \ + : : \ + : __TLS_CALL_CLOBBERS); \ + __result; }) +# endif + +#elif defined __powerpc__ && defined __powerpc64__ + +/* PowerPC64 Local Exec TLS access. */ +# define TLS_LE(x) \ + ({ int * __result; \ + __asm__ ( \ + " addis %0,13," #x "@tprel@ha\n" \ + " addi %0,%0," #x "@tprel@l\n" \ + : "=b" (__result) ); \ + __result; \ + }) +/* PowerPC64 Initial Exec TLS access. */ +# define TLS_IE(x) \ + ({ int * __result; \ + __asm__ ( \ + " ld %0," #x "@got@tprel(2)\n" \ + " add %0,%0," #x "@tls\n" \ + : "=b" (__result) ); \ + __result; \ + }) +/* PowerPC64 Local Dynamic TLS access. */ +# define TLS_LD(x) \ + ({ int * __result; \ + __asm__ ( \ + " addi 3,2," #x "@got@tlsld\n" \ + " bl .__tls_get_addr\n" \ + " nop \n" \ + " addis %0,3," #x "@dtprel@ha\n" \ + " addi %0,%0," #x "@dtprel@l\n" \ + : "=b" (__result) : \ + : "0", "3", "4", "5", "6", "7", \ + "8", "9", "10", "11", "12", \ + "lr", "ctr", \ + "cr0", "cr1", "cr5", "cr6", "cr7"); \ + __result; \ + }) +/* PowerPC64 General Dynamic TLS access. */ +# define TLS_GD(x) \ + ({ int * __result; \ + __asm__ ( \ + " addi 3,2," #x "@got@tlsgd\n" \ + " bl .__tls_get_addr\n" \ + " nop \n" \ + " mr %0,3\n" \ + : "=b" (__result) : \ + : "0", "3", "4", "5", "6", "7", \ + "8", "9", "10", "11", "12", \ + "lr", "ctr", \ + "cr0", "cr1", "cr5", "cr6", "cr7"); \ + __result; \ + }) + +#elif !defined TLS_LE || !defined TLS_IE \ + || !defined TLS_LD || !defined TLS_GD +# error "No support for this architecture so far." +#endif diff --git a/test/tls/tst-tls1-static.c b/test/tls/tst-tls1-static.c new file mode 100644 index 000000000..a01008073 --- /dev/null +++ b/test/tls/tst-tls1-static.c @@ -0,0 +1 @@ +#include "tst-tls1.c" diff --git a/test/tls/tst-tls1.c b/test/tls/tst-tls1.c new file mode 100644 index 000000000..f5ac6d2bc --- /dev/null +++ b/test/tls/tst-tls1.c @@ -0,0 +1,92 @@ +/* glibc test for TLS in ld.so. */ +#undef _LIBC +#include <stdio.h> + +#include <tls.h> + +#ifdef USE_TLS +# include "tls-macros.h" + + +/* Two common 'int' variables in TLS. */ +COMMON_INT_DEF(foo); +COMMON_INT_DEF(bar); +#endif + + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ +#ifdef USE_TLS + int result = 0; + int *ap, *bp; + + + /* Set the variable using the local exec model. */ + puts ("set bar to 1 (LE)"); + ap = TLS_LE (bar); + *ap = 1; + + + /* Get variables using initial exec model. */ + fputs ("get sum of foo and bar (IE)", stdout); + ap = TLS_IE (foo); + bp = TLS_IE (bar); + printf (" = %d\n", *ap + *bp); + result |= *ap + *bp != 1; + if (*ap != 0) + { + printf ("foo = %d\n", *ap); + result = 1; + } + if (*bp != 1) + { + printf ("bar = %d\n", *bp); + result = 1; + } + + + /* Get variables using local dynamic model. */ + fputs ("get sum of foo and bar (LD)", stdout); + ap = TLS_LD (foo); + bp = TLS_LD (bar); + printf (" = %d\n", *ap + *bp); + result |= *ap + *bp != 1; + if (*ap != 0) + { + printf ("foo = %d\n", *ap); + result = 1; + } + if (*bp != 1) + { + printf ("bar = %d\n", *bp); + result = 1; + } + + + /* Get variables using generic dynamic model. */ + fputs ("get sum of foo and bar (GD)", stdout); + ap = TLS_GD (foo); + bp = TLS_GD (bar); + printf (" = %d\n", *ap + *bp); + result |= *ap + *bp != 1; + if (*ap != 0) + { + printf ("foo = %d\n", *ap); + result = 1; + } + if (*bp != 1) + { + printf ("bar = %d\n", *bp); + result = 1; + } + + return result; +#else + return 0; +#endif +} + + +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls10.c b/test/tls/tst-tls10.c new file mode 100644 index 000000000..fc0677072 --- /dev/null +++ b/test/tls/tst-tls10.c @@ -0,0 +1,40 @@ +#include "tst-tls10.h" + +#ifdef USE_TLS__THREAD +__thread int dummy __attribute__((visibility ("hidden"))) = 12; +__thread struct A local = { 1, 2, 3 }; +#endif + +#define CHECK(N, S) \ + p = f##N##a (); \ + if (p->a != S || p->b != S + 1 || p->c != S + 2) \ + abort () + +int +main (void) +{ + struct A *p; + if (local.a != 1 || local.b != 2 || local.c != 3) + abort (); +#ifdef USE_TLS__THREAD + if (a1.a != 4 || a1.b != 5 || a1.c != 6) + abort (); + if (a2.a != 22 || a2.b != 23 || a2.c != 24) + abort (); + if (a3.a != 10 || a3.b != 11 || a3.c != 12) + abort (); + if (a4.a != 25 || a4.b != 26 || a4.c != 27) + abort (); + check1 (); + check2 (); + if (f1a () != &a1 || f2a () != &a2 || f3a () != &a3 || f4a () != &a4) + abort (); + CHECK (5, 16); + CHECK (6, 19); + if (f7a () != &a2 || f8a () != &a4) + abort (); + CHECK (9, 28); + CHECK (10, 31); +#endif + exit (0); +} diff --git a/test/tls/tst-tls10.h b/test/tls/tst-tls10.h new file mode 100644 index 000000000..1be6adc29 --- /dev/null +++ b/test/tls/tst-tls10.h @@ -0,0 +1,38 @@ +#include <tls.h> +#include <stdlib.h> + +#if defined USE_TLS && defined HAVE___THREAD \ + && defined HAVE_TLS_MODEL_ATTRIBUTE +# define USE_TLS__THREAD + +struct A +{ + char a; + int b; + long long c; +}; + +extern __thread struct A a1, a2, a3, a4; +extern struct A *f1a (void); +extern struct A *f2a (void); +extern struct A *f3a (void); +extern struct A *f4a (void); +extern struct A *f5a (void); +extern struct A *f6a (void); +extern struct A *f7a (void); +extern struct A *f8a (void); +extern struct A *f9a (void); +extern struct A *f10a (void); +extern int f1b (void); +extern int f2b (void); +extern int f3b (void); +extern int f4b (void); +extern int f5b (void); +extern int f6b (void); +extern int f7b (void); +extern int f8b (void); +extern int f9b (void); +extern int f10b (void); +extern void check1 (void); +extern void check2 (void); +#endif diff --git a/test/tls/tst-tls11.c b/test/tls/tst-tls11.c new file mode 100644 index 000000000..816cf5cc2 --- /dev/null +++ b/test/tls/tst-tls11.c @@ -0,0 +1,27 @@ +#include "tst-tls10.h" + +#define CHECK(N, S) \ + p = f##N##a (); \ + if (p->a != S || p->b != S + 1 || p->c != S + 2) \ + abort () + +int +main (void) +{ +#ifdef USE_TLS__THREAD + struct A *p; + check1 (); + check2 (); + CHECK (1, 4); + CHECK (2, 22); + CHECK (3, 10); + CHECK (4, 25); + CHECK (5, 16); + CHECK (6, 19); + CHECK (7, 22); + CHECK (8, 25); + CHECK (9, 28); + CHECK (10, 31); +#endif + exit (0); +} diff --git a/test/tls/tst-tls12.c b/test/tls/tst-tls12.c new file mode 100644 index 000000000..84aa7d35c --- /dev/null +++ b/test/tls/tst-tls12.c @@ -0,0 +1,18 @@ +#include "tst-tls10.h" + +#define CHECK(N, S) \ + p = &a##N; \ + if (p->a != S || p->b != S + 1 || p->c != S + 2) \ + abort () + +int +main (void) +{ +#ifdef USE_TLS__THREAD + struct A *p; + check1 (); + CHECK (1, 4); + CHECK (2, 7); +#endif + exit (0); +} diff --git a/test/tls/tst-tls13.c b/test/tls/tst-tls13.c new file mode 100644 index 000000000..55fb62e54 --- /dev/null +++ b/test/tls/tst-tls13.c @@ -0,0 +1,30 @@ +/* Check unloading modules with data in static TLS block. */ +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> + + +static int +do_test (void) +{ + int i; + for (i = 0; i < 1000;) + { + printf ("round %d\n",++i); + + void *h = dlopen ("tst-tlsmod13a.so", RTLD_LAZY); + if (h == NULL) + { + printf ("cannot load: %s\n", dlerror ()); + exit (1); + } + + dlclose (h); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#define TIMEOUT 3 +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls14.c b/test/tls/tst-tls14.c new file mode 100644 index 000000000..428fd5293 --- /dev/null +++ b/test/tls/tst-tls14.c @@ -0,0 +1,66 @@ +/* Check alignment of TLS variable. */ +#include <dlfcn.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#include <tls.h> + +#if USE_TLS && HAVE___THREAD + +#define AL 4096 +struct foo +{ + int i; +} __attribute ((aligned (AL))); + +static __thread struct foo f; +static struct foo g; + + +extern int in_dso1 (void); + + +static int +do_test (void) +{ + int result = 0; + + int fail = (((uintptr_t) &f) & (AL - 1)) != 0; + printf ("&f = %p %s\n", &f, fail ? "FAIL" : "OK"); + result |= fail; + + fail = (((uintptr_t) &g) & (AL - 1)) != 0; + printf ("&g = %p %s\n", &g, fail ? "FAIL" : "OK"); + result |= fail; + + result |= in_dso1 (); + + void *h = dlopen ("tst-tlsmod14b.so", RTLD_LAZY); + if (h == NULL) + { + printf ("cannot open tst-tlsmod14b.so: %m\n"); + exit (1); + } + + int (*fp) (void) = (int (*) (void)) dlsym (h, "in_dso2"); + if (fp == NULL) + { + puts ("cannot find in_dso2"); + exit (1); + } + + result |= fp (); + + return result; +} + +#define TEST_FUNCTION do_test () + +#else + +#define TEST_FUNCTION 0 + +#endif + +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls15.c b/test/tls/tst-tls15.c new file mode 100644 index 000000000..2c2df251b --- /dev/null +++ b/test/tls/tst-tls15.c @@ -0,0 +1,33 @@ +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> + +static int +do_test (void) +{ + void *h = dlopen ("tst-tlsmod15a.so", RTLD_NOW); + if (h != NULL) + { + puts ("unexpectedly succeeded to open tst-tlsmod15a.so"); + exit (1); + } + + h = dlopen ("tst-tlsmod15b.so", RTLD_NOW); + if (h == NULL) + { + puts ("failed to open tst-tlsmod15b.so"); + exit (1); + } + + int (*fp) (void) = (int (*) (void)) dlsym (h, "in_dso"); + if (fp == NULL) + { + puts ("cannot find in_dso"); + exit (1); + } + + return fp (); +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls16.c b/test/tls/tst-tls16.c new file mode 100644 index 000000000..53aece181 --- /dev/null +++ b/test/tls/tst-tls16.c @@ -0,0 +1,21 @@ +#include <stdio.h> +#include <stdlib.h> +#include <tls.h> + +#define TLS_VAR_INIT_VALUE 99 + +#ifdef USE_TLS +extern __thread int tls_var; +#endif + +int main(void) +{ + int ret = EXIT_SUCCESS; +#ifdef USE_TLS + if (tls_var != TLS_VAR_INIT_VALUE) { + printf("tls_var = %d - Expected value = %d\n", tls_var, TLS_VAR_INIT_VALUE); + ret = EXIT_FAILURE; + } +#endif + return ret; +} diff --git a/test/tls/tst-tls2-static.c b/test/tls/tst-tls2-static.c new file mode 100644 index 000000000..55ffa5744 --- /dev/null +++ b/test/tls/tst-tls2-static.c @@ -0,0 +1 @@ +#include "tst-tls2.c" diff --git a/test/tls/tst-tls2.c b/test/tls/tst-tls2.c new file mode 100644 index 000000000..417489968 --- /dev/null +++ b/test/tls/tst-tls2.c @@ -0,0 +1,91 @@ +/* glibc test for TLS in ld.so. */ +#include <stdio.h> + +#include <tls.h> + +#ifdef USE_TLS +# include "tls-macros.h" + + +/* Two 'int' variables in TLS. */ +VAR_INT_DEF(foo); +VAR_INT_DEF(bar); +#endif + + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ +#ifdef USE_TLS + int result = 0; + int *ap, *bp; + + + /* Set the variable using the local exec model. */ + puts ("set bar to 1 (LE)"); + ap = TLS_LE (bar); + *ap = 1; + + + /* Get variables using initial exec model. */ + fputs ("get sum of foo and bar (IE)", stdout); + ap = TLS_IE (foo); + bp = TLS_IE (bar); + printf (" = %d\n", *ap + *bp); + result |= *ap + *bp != 1; + if (*ap != 0) + { + printf ("foo = %d\n", *ap); + result = 1; + } + if (*bp != 1) + { + printf ("bar = %d\n", *bp); + result = 1; + } + + + /* Get variables using local dynamic model. */ + fputs ("get sum of foo and bar (LD)", stdout); + ap = TLS_LD (foo); + bp = TLS_LD (bar); + printf (" = %d\n", *ap + *bp); + result |= *ap + *bp != 1; + if (*ap != 0) + { + printf ("foo = %d\n", *ap); + result = 1; + } + if (*bp != 1) + { + printf ("bar = %d\n", *bp); + result = 1; + } + + + /* Get variables using generic dynamic model. */ + fputs ("get sum of foo and bar (GD)", stdout); + ap = TLS_GD (foo); + bp = TLS_GD (bar); + printf (" = %d\n", *ap + *bp); + result |= *ap + *bp != 1; + if (*ap != 0) + { + printf ("foo = %d\n", *ap); + result = 1; + } + if (*bp != 1) + { + printf ("bar = %d\n", *bp); + result = 1; + } + + return result; +#else + return 0; +#endif +} + + +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls3.c b/test/tls/tst-tls3.c new file mode 100644 index 000000000..84be43575 --- /dev/null +++ b/test/tls/tst-tls3.c @@ -0,0 +1,76 @@ +/* glibc test for TLS in ld.so. */ +#include <stdio.h> + +#include <tls.h> + +#ifdef USE_TLS +# include "tls-macros.h" + + +/* One define int variable, two externs. */ +COMMON_INT_DECL(foo); +VAR_INT_DECL(bar); +VAR_INT_DEF(baz); +#endif + + +extern int in_dso (void); + + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ +#ifdef USE_TLS + int result = 0; + int *ap, *bp, *cp; + + + /* Set the variable using the local exec model. */ + puts ("set baz to 3 (LE)"); + ap = TLS_LE (baz); + *ap = 3; + + + /* Get variables using initial exec model. */ + puts ("set variables foo and bar (IE)"); + ap = TLS_IE (foo); + *ap = 1; + bp = TLS_IE (bar); + *bp = 2; + + + /* Get variables using local dynamic model. */ + fputs ("get sum of foo, bar (GD) and baz (LD)", stdout); + ap = TLS_GD (foo); + bp = TLS_GD (bar); + cp = TLS_LD (baz); + printf (" = %d\n", *ap + *bp + *cp); + result |= *ap + *bp + *cp != 6; + if (*ap != 1) + { + printf ("foo = %d\n", *ap); + result = 1; + } + if (*bp != 2) + { + printf ("bar = %d\n", *bp); + result = 1; + } + if (*cp != 3) + { + printf ("baz = %d\n", *cp); + result = 1; + } + + + result |= in_dso (); + + return result; +#else + return 0; +#endif +} + + +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls4.c b/test/tls/tst-tls4.c new file mode 100644 index 000000000..f92ee53ce --- /dev/null +++ b/test/tls/tst-tls4.c @@ -0,0 +1,56 @@ +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> + +#include <tls.h> + + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ +#ifdef USE_TLS + static const char modname[] = "tst-tlsmod2.so"; + int result = 0; + int *foop; + int (*fp) (int, int *); + void *h; + + h = dlopen (modname, RTLD_LAZY); + if (h == NULL) + { + printf ("cannot open '%s': %s\n", modname, dlerror ()); + exit (1); + } + + fp = dlsym (h, "in_dso"); + if (fp == NULL) + { + printf ("cannot get symbol 'in_dso': %s\n", dlerror ()); + exit (1); + } + + result |= fp (0, NULL); + + foop = dlsym (h, "foo"); + if (foop == NULL) + { + printf ("cannot get symbol 'foo' the second time: %s\n", dlerror ()); + exit (1); + } + if (*foop != 16) + { + puts ("foo != 16"); + result = 1; + } + + dlclose (h); + + return result; +#else + return 0; +#endif +} + + +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls5.c b/test/tls/tst-tls5.c new file mode 100644 index 000000000..a571d2cd3 --- /dev/null +++ b/test/tls/tst-tls5.c @@ -0,0 +1,72 @@ +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> + +#include <tls.h> + + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ +#ifdef USE_TLS + static const char modname[] = "tst-tlsmod2.so"; + int result = 0; + int *foop; + int *foop2; + int (*fp) (int, int *); + void *h; + + h = dlopen (modname, RTLD_LAZY); + if (h == NULL) + { + printf ("cannot open '%s': %s\n", modname, dlerror ()); + exit (1); + } + + foop = dlsym (h, "foo"); + if (foop == NULL) + { + printf ("cannot get symbol 'foo': %s\n", dlerror ()); + exit (1); + } + + *foop = 42; + + fp = dlsym (h, "in_dso"); + if (fp == NULL) + { + printf ("cannot get symbol 'in_dso': %s\n", dlerror ()); + exit (1); + } + + result |= fp (42, foop); + + foop2 = dlsym (h, "foo"); + if (foop2 == NULL) + { + printf ("cannot get symbol 'foo' the second time: %s\n", dlerror ()); + exit (1); + } + + if (foop != foop2) + { + puts ("address of 'foo' different the second time"); + result = 1; + } + else if (*foop != 16) + { + puts ("foo != 16"); + result = 1; + } + + dlclose (h); + + return result; +#else + return 0; +#endif +} + + +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls6.c b/test/tls/tst-tls6.c new file mode 100644 index 000000000..5733aa587 --- /dev/null +++ b/test/tls/tst-tls6.c @@ -0,0 +1,108 @@ +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> + +#include <tls.h> +#include <link.h> +#ifdef __UCLIBC__ +#include "dl-elf.h" +#include "dl-hash.h" +#endif + + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ +#ifdef USE_TLS + static const char modname[] = "tst-tlsmod2.so"; + int result = 0; + int *foop; + int *foop2; + int (*fp) (int, int *); + void *h; + int i; + int modid = -1; + + for (i = 0; i < 10; ++i) + { + h = dlopen (modname, RTLD_LAZY); + if (h == NULL) + { + printf ("cannot open '%s': %s\n", modname, dlerror ()); + exit (1); + } + + /* Dirty test code here: we peek into a private data structure. + We make sure that the module gets assigned the same ID every + time. The value of the first round is used. */ +#ifdef __UCLIBC__ + if (modid == -1) + modid = ((struct link_map *)((struct dyn_elf *)h)->dyn)->l_tls_modid; + else if (((struct link_map *)((struct dyn_elf *)h)->dyn)->l_tls_modid + != (size_t) modid) + { + printf ("round %d: modid now %zu, initially %d\n", + i, + ((struct link_map *)((struct dyn_elf *)h)->dyn)->l_tls_modid, + modid); + result = 1; + } +#else + if (modid == -1) + modid = ((struct link_map *) h)->l_tls_modid; + else if (((struct link_map *) h)->l_tls_modid != modid) + { + printf ("round %d: modid now %zd, initially %d\n", + i, ((struct link_map *) h)->l_tls_modid, modid); + result = 1; + } +#endif + + foop = dlsym (h, "foo"); + if (foop == NULL) + { + printf ("cannot get symbol 'foo': %s\n", dlerror ()); + exit (1); + } + + *foop = 42 + i; + + fp = dlsym (h, "in_dso"); + if (fp == NULL) + { + printf ("cannot get symbol 'in_dso': %s\n", dlerror ()); + exit (1); + } + + result |= fp (42 + i, foop); + + foop2 = dlsym (h, "foo"); + if (foop2 == NULL) + { + printf ("cannot get symbol 'foo' the second time: %s\n", dlerror ()); + exit (1); + } + + if (foop != foop2) + { + puts ("address of 'foo' different the second time"); + result = 1; + } + else if (*foop != 16) + { + puts ("foo != 16"); + result = 1; + } + + dlclose (h); + } + + return result; +#else + return 0; +#endif +} + + +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls7.c b/test/tls/tst-tls7.c new file mode 100644 index 000000000..41da2708d --- /dev/null +++ b/test/tls/tst-tls7.c @@ -0,0 +1,79 @@ +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> + +#include <tls.h> +#include <link.h> +#ifdef __UCLIBC__ +#include "dl-elf.h" +#include "dl-hash.h" +#endif + + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ +#ifdef USE_TLS + static const char modname[] = "tst-tlsmod3.so"; + int result = 0; + int (*fp) (void); + void *h; + int i; + int modid = -1; + + for (i = 0; i < 10; ++i) + { + h = dlopen (modname, RTLD_LAZY); + if (h == NULL) + { + printf ("cannot open '%s': %s\n", modname, dlerror ()); + exit (1); + } + + /* Dirty test code here: we peek into a private data structure. + We make sure that the module gets assigned the same ID every + time. The value of the first round is used. */ +#ifdef __UCLIBC__ + if (modid == -1) + modid = ((struct link_map *)((struct dyn_elf *)h)->dyn)->l_tls_modid; + else if (((struct link_map *)((struct dyn_elf *)h)->dyn)->l_tls_modid + != (size_t) modid) + { + printf ("round %d: modid now %zu, initially %d\n", + i, + ((struct link_map *)((struct dyn_elf *)h)->dyn)->l_tls_modid, + modid); + result = 1; + } +#else + if (modid == -1) + modid = ((struct link_map *) h)->l_tls_modid; + else if (((struct link_map *) h)->l_tls_modid != (size_t) modid) + { + printf ("round %d: modid now %zu, initially %d\n", + i, ((struct link_map *) h)->l_tls_modid, modid); + result = 1; + } +#endif + + fp = dlsym (h, "in_dso2"); + if (fp == NULL) + { + printf ("cannot get symbol 'in_dso2': %s\n", dlerror ()); + exit (1); + } + + result |= fp (); + + dlclose (h); + } + + return result; +#else + return 0; +#endif +} + + +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls8.c b/test/tls/tst-tls8.c new file mode 100644 index 000000000..2541609f1 --- /dev/null +++ b/test/tls/tst-tls8.c @@ -0,0 +1,230 @@ +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> + +#include <tls.h> +#include <link.h> +#ifdef __UCLIBC__ +#include "dl-elf.h" +#include "dl-hash.h" +#endif + + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ +#ifdef USE_TLS + static const char modname1[] = "tst-tlsmod3.so"; + static const char modname2[] = "tst-tlsmod4.so"; + int result = 0; + int (*fp1) (void); + int (*fp2) (int, int *); + void *h1; + void *h2; + int i; + size_t modid1 = (size_t) -1; + size_t modid2 = (size_t) -1; + int *bazp; + + for (i = 0; i < 10; ++i) + { + h1 = dlopen (modname1, RTLD_LAZY); + if (h1 == NULL) + { + printf ("cannot open '%s': %s\n", modname1, dlerror ()); + exit (1); + } + + /* Dirty test code here: we peek into a private data structure. + We make sure that the module gets assigned the same ID every + time. The value of the first round is used. */ +#ifdef __UCLIBC__ + if (modid1 == (size_t) -1) + modid1 = ((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid; + else if (((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid + != (size_t) modid1) + { + printf ("round %d: modid now %zd, initially %zd\n", + i, + ((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid, + modid1); + result = 1; + } +#else + if (modid1 == (size_t) -1) + modid1 = ((struct link_map *) h1)->l_tls_modid; + else if (((struct link_map *) h1)->l_tls_modid != modid1) + { + printf ("round %d: modid now %zd, initially %zd\n", + i, ((struct link_map *) h1)->l_tls_modid, modid1); + result = 1; + } +#endif + + fp1 = dlsym (h1, "in_dso2"); + if (fp1 == NULL) + { + printf ("cannot get symbol 'in_dso2' in %s\n", modname1); + exit (1); + } + + result |= fp1 (); + + + + h2 = dlopen (modname2, RTLD_LAZY); + if (h2 == NULL) + { + printf ("cannot open '%s': %s\n", modname2, dlerror ()); + exit (1); + } + + /* Dirty test code here: we peek into a private data structure. + We make sure that the module gets assigned the same ID every + time. The value of the first round is used. */ +#ifdef __UCLIBC__ + if (modid2 == (size_t) -1) + modid2 = ((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid; + else if (((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid + != (size_t) modid2) + { + printf ("round %d: modid now %zd, initially %zd\n", + i, + ((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid, + modid2); + result = 1; + } +#else + if (modid2 == (size_t) -1) + modid2 = ((struct link_map *) h1)->l_tls_modid; + else if (((struct link_map *) h1)->l_tls_modid != modid2) + { + printf ("round %d: modid now %zd, initially %zd\n", + i, ((struct link_map *) h1)->l_tls_modid, modid2); + result = 1; + } +#endif + + bazp = dlsym (h2, "baz"); + if (bazp == NULL) + { + printf ("cannot get symbol 'baz' in %s\n", modname2); + exit (1); + } + + *bazp = 42 + i; + + fp2 = dlsym (h2, "in_dso"); + if (fp2 == NULL) + { + printf ("cannot get symbol 'in_dso' in %s\n", modname2); + exit (1); + } + + result |= fp2 (42 + i, bazp); + + dlclose (h1); + dlclose (h2); + + + h1 = dlopen (modname1, RTLD_LAZY); + if (h1 == NULL) + { + printf ("cannot open '%s': %s\n", modname1, dlerror ()); + exit (1); + } + + /* Dirty test code here: we peek into a private data structure. + We make sure that the module gets assigned the same ID every + time. The value of the first round is used. */ +#ifdef __UCLIBC__ + if (((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid + != modid1) + { + printf ("round %d: modid now %zd, initially %zd\n", + i, + ((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid, + modid1); + result = 1; + } +#else + if (((struct link_map *) h1)->l_tls_modid != modid1) + { + printf ("round %d: modid now %zd, initially %zd\n", + i, ((struct link_map *) h1)->l_tls_modid, modid1); + result = 1; + } +#endif + + fp1 = dlsym (h1, "in_dso2"); + if (fp1 == NULL) + { + printf ("cannot get symbol 'in_dso2' in %s\n", modname1); + exit (1); + } + + result |= fp1 (); + + + + h2 = dlopen (modname2, RTLD_LAZY); + if (h2 == NULL) + { + printf ("cannot open '%s': %s\n", modname2, dlerror ()); + exit (1); + } + + /* Dirty test code here: we peek into a private data structure. + We make sure that the module gets assigned the same ID every + time. The value of the first round is used. */ +#ifdef __UCLIBC__ + if (((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid + != modid2) + { + printf ("round %d: modid now %zd, initially %zd\n", + i, + ((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid, + modid2); + result = 1; + } +#else + if (((struct link_map *) h1)->l_tls_modid != modid2) + { + printf ("round %d: modid now %zd, initially %zd\n", + i, ((struct link_map *) h1)->l_tls_modid, modid2); + result = 1; + } +#endif + + bazp = dlsym (h2, "baz"); + if (bazp == NULL) + { + printf ("cannot get symbol 'baz' in %s\n", modname2); + exit (1); + } + + *bazp = 62 + i; + + fp2 = dlsym (h2, "in_dso"); + if (fp2 == NULL) + { + printf ("cannot get symbol 'in_dso' in %s\n", modname2); + exit (1); + } + + result |= fp2 (62 + i, bazp); + + /* This time the dlclose calls are in reverse order. */ + dlclose (h2); + dlclose (h1); + } + + return result; +#else + return 0; +#endif +} + + +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls9-static.c b/test/tls/tst-tls9-static.c new file mode 100644 index 000000000..51812ccc7 --- /dev/null +++ b/test/tls/tst-tls9-static.c @@ -0,0 +1 @@ +#include "tst-tls9.c" diff --git a/test/tls/tst-tls9.c b/test/tls/tst-tls9.c new file mode 100644 index 000000000..e317696df --- /dev/null +++ b/test/tls/tst-tls9.c @@ -0,0 +1,42 @@ +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> + +#include <link.h> +#include <tls.h> + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ +#ifdef USE_TLS + static const char modname1[] = "tst-tlsmod5.so"; + static const char modname2[] = "tst-tlsmod6.so"; + int result = 0; + + void *h1 = dlopen (modname1, RTLD_LAZY); + if (h1 == NULL) + { + printf ("cannot open '%s': %s\n", modname1, dlerror ()); + result = 1; + } + void *h2 = dlopen (modname2, RTLD_LAZY); + if (h2 == NULL) + { + printf ("cannot open '%s': %s\n", modname2, dlerror ()); + result = 1; + } + + if (h1 != NULL) + dlclose (h1); + if (h2 != NULL) + dlclose (h2); + + return result; +#else + return 0; +#endif +} + + +#include "../test-skeleton.c" diff --git a/test/tls/tst-tlsmod1.c b/test/tls/tst-tlsmod1.c new file mode 100644 index 000000000..b4954ca3e --- /dev/null +++ b/test/tls/tst-tlsmod1.c @@ -0,0 +1,68 @@ +#include <stdio.h> + +#include <tls.h> + +#ifdef USE_TLS +#include "tls-macros.h" + + +/* One define int variable, two externs. */ +COMMON_INT_DEF(foo); +VAR_INT_DEF(bar); +VAR_INT_DECL(baz); +#endif + +extern int in_dso (void); + +int +in_dso (void) +{ + int result = 0; +#ifdef USE_TLS + int *ap, *bp, *cp; + + /* Get variables using initial exec model. */ + fputs ("get sum of foo and bar (IE)", stdout); + __asm__ ("" ::: "memory"); + ap = TLS_IE (foo); + bp = TLS_IE (bar); + printf (" = %d\n", *ap + *bp); + result |= *ap + *bp != 3; + if (*ap != 1) + { + printf ("foo = %d\n", *ap); + result = 1; + } + if (*bp != 2) + { + printf ("bar = %d\n", *bp); + result = 1; + } + + + /* Get variables using generic dynamic model. */ + fputs ("get sum of foo and bar and baz (GD)", stdout); + ap = TLS_GD (foo); + bp = TLS_GD (bar); + cp = TLS_GD (baz); + printf (" = %d\n", *ap + *bp + *cp); + result |= *ap + *bp + *cp != 6; + if (*ap != 1) + { + printf ("foo = %d\n", *ap); + result = 1; + } + if (*bp != 2) + { + printf ("bar = %d\n", *bp); + result = 1; + } + if (*cp != 3) + { + printf ("baz = %d\n", *cp); + result = 1; + } +#endif + + return result; +} diff --git a/test/tls/tst-tlsmod10.c b/test/tls/tst-tlsmod10.c new file mode 100644 index 000000000..32e54f3c0 --- /dev/null +++ b/test/tls/tst-tlsmod10.c @@ -0,0 +1 @@ +#include "tst-tlsmod8.c" diff --git a/test/tls/tst-tlsmod11.c b/test/tls/tst-tlsmod11.c new file mode 100644 index 000000000..9938b5753 --- /dev/null +++ b/test/tls/tst-tlsmod11.c @@ -0,0 +1,6 @@ +#include "tst-tls10.h" + +#ifdef USE_TLS__THREAD +__thread struct A a1 = { 4, 5, 6 }; +__thread struct A a2 = { 7, 8, 9 }; +#endif diff --git a/test/tls/tst-tlsmod12.c b/test/tls/tst-tlsmod12.c new file mode 100644 index 000000000..4602709a1 --- /dev/null +++ b/test/tls/tst-tlsmod12.c @@ -0,0 +1,14 @@ +#include "tst-tls10.h" + +#ifdef USE_TLS__THREAD +extern __thread struct A a2 __attribute__((tls_model("initial-exec"))); + +void +check1 (void) +{ + if (a1.a != 4 || a1.b != 5 || a1.c != 6) + abort (); + if (a2.a != 7 || a2.b != 8 || a2.c != 9) + abort (); +} +#endif diff --git a/test/tls/tst-tlsmod13.c b/test/tls/tst-tlsmod13.c new file mode 100644 index 000000000..beca89f6f --- /dev/null +++ b/test/tls/tst-tlsmod13.c @@ -0,0 +1,14 @@ +#include <tls.h> + +#if defined USE_TLS && defined HAVE___THREAD \ + && defined HAVE_TLS_MODEL_ATTRIBUTE +__thread int a[2] __attribute__ ((tls_model ("initial-exec"))); +#else +int a[2]; +#endif + +int +foo (void) +{ + return a[0]; +} diff --git a/test/tls/tst-tlsmod13a.c b/test/tls/tst-tlsmod13a.c new file mode 100644 index 000000000..14b12b032 --- /dev/null +++ b/test/tls/tst-tlsmod13a.c @@ -0,0 +1,16 @@ +#include <tls.h> + +#if defined USE_TLS && defined HAVE___THREAD \ + && defined HAVE_TLS_MODEL_ATTRIBUTE +__thread int b[2] __attribute__ ((tls_model ("initial-exec"))); +#else +int b[2]; +#endif + +extern int foo (void); + +int +bar (void) +{ + return foo () + b[0]; +} diff --git a/test/tls/tst-tlsmod14a.c b/test/tls/tst-tlsmod14a.c new file mode 100644 index 000000000..0bb393d9c --- /dev/null +++ b/test/tls/tst-tlsmod14a.c @@ -0,0 +1,41 @@ +#include <stdint.h> +#include <stdio.h> + +#include <tls.h> + +#if USE_TLS && HAVE___THREAD + +#define AL 4096 +struct foo +{ + int i; +} __attribute ((aligned (AL))); + +static __thread struct foo f; +static struct foo g; + + +#ifndef FCT +# define FCT in_dso1 +#endif + + +int +FCT (void) +{ + puts (__func__); + + int result = 0; + + int fail = (((uintptr_t) &f) & (AL - 1)) != 0; + printf ("&f = %p %s\n", &f, fail ? "FAIL" : "OK"); + result |= fail; + + fail = (((uintptr_t) &g) & (AL - 1)) != 0; + printf ("&g = %p %s\n", &g, fail ? "FAIL" : "OK"); + result |= fail; + + return result; +} + +#endif diff --git a/test/tls/tst-tlsmod14b.c b/test/tls/tst-tlsmod14b.c new file mode 100644 index 000000000..24d9ceaf7 --- /dev/null +++ b/test/tls/tst-tlsmod14b.c @@ -0,0 +1,2 @@ +#define FCT in_dso2 +#include "tst-tlsmod14a.c" diff --git a/test/tls/tst-tlsmod15a.c b/test/tls/tst-tlsmod15a.c new file mode 100644 index 000000000..66c707129 --- /dev/null +++ b/test/tls/tst-tlsmod15a.c @@ -0,0 +1,6 @@ +extern int nonexistent_dummy_var; +int * +foo (void) +{ + return &nonexistent_dummy_var; +} diff --git a/test/tls/tst-tlsmod15b.c b/test/tls/tst-tlsmod15b.c new file mode 100644 index 000000000..4f63eab14 --- /dev/null +++ b/test/tls/tst-tlsmod15b.c @@ -0,0 +1,17 @@ +#include "tst-tls10.h" + +#ifdef USE_TLS__THREAD +__thread int mod15b_var __attribute__((tls_model("initial-exec"))); + +int +in_dso (void) +{ + return mod15b_var; +} +#else +int +in_dso (void) +{ + return 0; +} +#endif diff --git a/test/tls/tst-tlsmod16.c b/test/tls/tst-tlsmod16.c new file mode 100644 index 000000000..bd04b5081 --- /dev/null +++ b/test/tls/tst-tlsmod16.c @@ -0,0 +1,25 @@ +#include <stdio.h> +#include <tls.h> + +#define TLS_VAR_INIT_VALUE 99 + +#ifdef USE_TLS +__thread int tls_var __attribute__((tls_model("global-dynamic"))); +static __thread int local_tls_var __attribute__((tls_model("local-dynamic"))); +#endif + +void __attribute__((constructor)) libtls_ctor(void); +void libtls_ctor(void) +{ + printf("libtls: constructor!\n"); +#ifdef USE_TLS + local_tls_var = TLS_VAR_INIT_VALUE; + tls_var = local_tls_var; +#endif +} + +void __attribute__((destructor)) libtls_dtor(void); +void libtls_dtor(void) +{ + printf("libtls: destructor!\n"); +} diff --git a/test/tls/tst-tlsmod2.c b/test/tls/tst-tlsmod2.c new file mode 100644 index 000000000..4547c9716 --- /dev/null +++ b/test/tls/tst-tlsmod2.c @@ -0,0 +1,38 @@ +#include <stdio.h> + +#include <tls.h> + +#ifdef USE_TLS +#include "tls-macros.h" + + +COMMON_INT_DEF(foo); + + +int +in_dso (int n, int *caller_foop) +{ + int *foop; + int result = 0; + + puts ("foo"); /* Make sure PLT is used before macros. */ + __asm__ ("" ::: "memory"); + + foop = TLS_GD (foo); + + if (caller_foop != NULL && foop != caller_foop) + { + printf ("callers address of foo differs: %p vs %p\n", caller_foop, foop); + result = 1; + } + else if (*foop != n) + { + printf ("foo != %d\n", n); + result = 1; + } + + *foop = 16; + + return result; +} +#endif diff --git a/test/tls/tst-tlsmod3.c b/test/tls/tst-tlsmod3.c new file mode 100644 index 000000000..12505f623 --- /dev/null +++ b/test/tls/tst-tlsmod3.c @@ -0,0 +1,41 @@ +#include <stdio.h> + +#include <tls.h> + +#ifdef USE_TLS +# include "tls-macros.h" + +extern int in_dso (int n, int *caller_foop); + +COMMON_INT_DEF(comm_n); + + + + +int +in_dso2 (void) +{ + int *foop; + int result = 0; + static int n; + int *np; + + puts ("foo"); /* Make sure PLT is used before macros. */ + __asm__ ("" ::: "memory"); + + foop = TLS_GD (foo); + np = TLS_GD (comm_n); + + if (n != *np) + { + printf ("n = %d != comm_n = %d\n", n, *np); + result = 1; + } + + result |= in_dso (*foop = 42 + n++, foop); + + *foop = 16; + + return result; +} +#endif diff --git a/test/tls/tst-tlsmod4.c b/test/tls/tst-tlsmod4.c new file mode 100644 index 000000000..4893cdae7 --- /dev/null +++ b/test/tls/tst-tlsmod4.c @@ -0,0 +1,38 @@ +#include <stdio.h> + +#include <tls.h> + +#ifdef USE_TLS +# include "tls-macros.h" + + +COMMON_INT_DEF(baz); + + +int +in_dso (int n, int *caller_bazp) +{ + int *bazp; + int result = 0; + + puts ("foo"); /* Make sure PLT is used before macros. */ + __asm__ ("" ::: "memory"); + + bazp = TLS_GD (baz); + + if (caller_bazp != NULL && bazp != caller_bazp) + { + printf ("callers address of baz differs: %p vs %p\n", caller_bazp, bazp); + result = 1; + } + else if (*bazp != n) + { + printf ("baz != %d\n", n); + result = 1; + } + + *bazp = 16; + + return result; +} +#endif diff --git a/test/tls/tst-tlsmod5.c b/test/tls/tst-tlsmod5.c new file mode 100644 index 000000000..2ec69e13b --- /dev/null +++ b/test/tls/tst-tlsmod5.c @@ -0,0 +1,7 @@ +#include <tls.h> + +#ifdef USE_TLS +#include "tls-macros.h" + +COMMON_INT_DEF(foo); +#endif diff --git a/test/tls/tst-tlsmod6.c b/test/tls/tst-tlsmod6.c new file mode 100644 index 000000000..0fda51b22 --- /dev/null +++ b/test/tls/tst-tlsmod6.c @@ -0,0 +1,7 @@ +#include <tls.h> + +#ifdef USE_TLS +#include "tls-macros.h" + +COMMON_INT_DEF(bar); +#endif diff --git a/test/tls/tst-tlsmod7.c b/test/tls/tst-tlsmod7.c new file mode 100644 index 000000000..944b97f9c --- /dev/null +++ b/test/tls/tst-tlsmod7.c @@ -0,0 +1,103 @@ +#include "tst-tls10.h" + +#ifdef USE_TLS__THREAD +__thread int dummy __attribute__((visibility ("hidden"))) = 12; +__thread struct A a1 = { 4, 5, 6 }; +__thread struct A a2 = { 7, 8, 9 }; +__thread struct A a3 __attribute__((tls_model("initial-exec"))) + = { 10, 11, 12 }; +__thread struct A a4 __attribute__((tls_model("initial-exec"))) + = { 13, 14, 15 }; +static __thread struct A local1 = { 16, 17, 18 }; +static __thread struct A local2 __attribute__((tls_model("initial-exec"))) + = { 19, 20, 21 }; + +void +check1 (void) +{ + if (a1.a != 4 || a1.b != 5 || a1.c != 6) + abort (); + if (a2.a != 22 || a2.b != 23 || a2.c != 24) + abort (); + if (a3.a != 10 || a3.b != 11 || a3.c != 12) + abort (); + if (a4.a != 25 || a4.b != 26 || a4.c != 27) + abort (); + if (local1.a != 16 || local1.b != 17 || local1.c != 18) + abort (); + if (local2.a != 19 || local2.b != 20 || local2.c != 21) + abort (); +} + +struct A * +f1a (void) +{ + return &a1; +} + +struct A * +f2a (void) +{ + return &a2; +} + +struct A * +f3a (void) +{ + return &a3; +} + +struct A * +f4a (void) +{ + return &a4; +} + +struct A * +f5a (void) +{ + return &local1; +} + +struct A * +f6a (void) +{ + return &local2; +} + +int +f1b (void) +{ + return a1.a; +} + +int +f2b (void) +{ + return a2.b; +} + +int +f3b (void) +{ + return a3.c; +} + +int +f4b (void) +{ + return a4.a; +} + +int +f5b (void) +{ + return local1.b; +} + +int +f6b (void) +{ + return local2.c; +} +#endif diff --git a/test/tls/tst-tlsmod8.c b/test/tls/tst-tlsmod8.c new file mode 100644 index 000000000..c1822fc0c --- /dev/null +++ b/test/tls/tst-tlsmod8.c @@ -0,0 +1,72 @@ +#include "tst-tls10.h" + +#ifdef USE_TLS__THREAD +__thread long long dummy __attribute__((visibility ("hidden"))) = 12; +__thread struct A a2 = { 22, 23, 24 }; +__thread struct A a4 __attribute__((tls_model("initial-exec"))) + = { 25, 26, 27 }; +static __thread struct A local1 = { 28, 29, 30 }; +static __thread struct A local2 __attribute__((tls_model("initial-exec"))) + = { 31, 32, 33 }; + +void +check2 (void) +{ + if (a2.a != 22 || a2.b != 23 || a2.c != 24) + abort (); + if (a4.a != 25 || a4.b != 26 || a4.c != 27) + abort (); + if (local1.a != 28 || local1.b != 29 || local1.c != 30) + abort (); + if (local2.a != 31 || local2.b != 32 || local2.c != 33) + abort (); +} + +struct A * +f7a (void) +{ + return &a2; +} + +struct A * +f8a (void) +{ + return &a4; +} + +struct A * +f9a (void) +{ + return &local1; +} + +struct A * +f10a (void) +{ + return &local2; +} + +int +f7b (void) +{ + return a2.b; +} + +int +f8b (void) +{ + return a4.a; +} + +int +f9b (void) +{ + return local1.b; +} + +int +f10b (void) +{ + return local2.c; +} +#endif diff --git a/test/tls/tst-tlsmod9.c b/test/tls/tst-tlsmod9.c new file mode 100644 index 000000000..e124144e4 --- /dev/null +++ b/test/tls/tst-tlsmod9.c @@ -0,0 +1,101 @@ +#include "tst-tls10.h" + +#ifdef USE_TLS__THREAD +__thread int dummy __attribute__((visibility ("hidden"))) = 12; +__thread struct A a1 = { 4, 5, 6 }; +__thread struct A a3 __attribute__((tls_model("initial-exec"))) + = { 10, 11, 12 }; +extern __thread struct A a4 __attribute__((tls_model("initial-exec"))); +static __thread struct A local1 = { 16, 17, 18 }; +static __thread struct A local2 __attribute__((tls_model("initial-exec"))) + = { 19, 20, 21 }; + +void +check1 (void) +{ + if (a1.a != 4 || a1.b != 5 || a1.c != 6) + abort (); + if (a2.a != 22 || a2.b != 23 || a2.c != 24) + abort (); + if (a3.a != 10 || a3.b != 11 || a3.c != 12) + abort (); + if (a4.a != 25 || a4.b != 26 || a4.c != 27) + abort (); + if (local1.a != 16 || local1.b != 17 || local1.c != 18) + abort (); + if (local2.a != 19 || local2.b != 20 || local2.c != 21) + abort (); +} + +struct A * +f1a (void) +{ + return &a1; +} + +struct A * +f2a (void) +{ + return &a2; +} + +struct A * +f3a (void) +{ + return &a3; +} + +struct A * +f4a (void) +{ + return &a4; +} + +struct A * +f5a (void) +{ + return &local1; +} + +struct A * +f6a (void) +{ + return &local2; +} + +int +f1b (void) +{ + return a1.a; +} + +int +f2b (void) +{ + return a2.b; +} + +int +f3b (void) +{ + return a3.c; +} + +int +f4b (void) +{ + return a4.a; +} + +int +f5b (void) +{ + return local1.b; +} + +int +f6b (void) +{ + return local2.c; +} +#endif |