Index: lib/sanitizer_common/sanitizer_linux_libcdep.cc =================================================================== --- lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -166,11 +166,15 @@ # define DL_INTERNAL_FUNCTION #endif -#if defined(__mips__) +#if defined(__mips__) || defined(__powerpc64__) // TlsPreTcbSize includes size of struct pthread_descr and size of tcb // head structure. It lies before the static tls blocks. static uptr TlsPreTcbSize() { - const uptr kTcbHead = 16; +# if defined(__mips__) + const uptr kTcbHead = 16; // sizeof (tcbhead_t) +# elif defined(__powerpc64__) + const uptr kTcbHead = 88; // sizeof (tcbhead_t) +# endif const uptr kTlsAlign = 16; const uptr kTlsPreTcbSize = (ThreadDescriptorSize() + kTcbHead + kTlsAlign - 1) & ~(kTlsAlign - 1); @@ -201,9 +205,9 @@ } #if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) \ - || defined(__aarch64__)) \ + || defined(__aarch64__) || defined(__powerpc64__)) \ && SANITIZER_LINUX && !SANITIZER_ANDROID -// sizeof(struct thread) from glibc. +// sizeof(struct pthread) from glibc. static atomic_uintptr_t kThreadDescriptorSize; uptr ThreadDescriptorSize() { @@ -218,7 +222,7 @@ char *end; int minor = internal_simple_strtoll(buf + 8, &end, 10); if (end != buf + 8 && (*end == '\0' || *end == '.')) { - /* sizeof(struct thread) values from various glibc versions. */ + /* sizeof(struct pthread) values from various glibc versions. */ if (SANITIZER_X32) val = 1728; // Assume only one particular version for x32. else if (minor <= 3) @@ -254,6 +258,10 @@ val = 1776; atomic_store(&kThreadDescriptorSize, val, memory_order_relaxed); return val; +#elif defined(__powerpc64__) + val = 1776; // from glibc.ppc64le 2.20-8.fc21 + atomic_store(&kThreadDescriptorSize, val, memory_order_relaxed); + return val; #endif return 0; } @@ -285,6 +293,15 @@ descr_addr = thread_pointer - kTlsTcbOffset - TlsPreTcbSize(); # elif defined(__aarch64__) descr_addr = reinterpret_cast(__builtin_thread_pointer()); +# elif defined(__powerpc64__) + // PPC64LE uses TLS variant I. The thread pointer (in GPR 13) + // points to the end of the TCB + 0x7000. The pthread_descr structure is + // immediately in front of the TCB. TlsPreTcbSize() includes the size of the + // TCB and the size of pthread_descr. + const uptr kTlsTcbOffset = 0x7000; + uptr thread_pointer; + asm("addi %0,13,%1" : "=r"(thread_pointer) : "I"(-kTlsTcbOffset)); + descr_addr = thread_pointer - TlsPreTcbSize(); # else # error "unsupported CPU arch" # endif @@ -320,7 +337,7 @@ *size = GetTlsSize(); *addr -= *size; *addr += ThreadDescriptorSize(); -# elif defined(__mips__) || defined(__aarch64__) +# elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__) *addr = ThreadSelf(); *size = GetTlsSize(); # else Index: lib/sanitizer_common/sanitizer_tls_get_addr.cc =================================================================== --- lib/sanitizer_common/sanitizer_tls_get_addr.cc +++ lib/sanitizer_common/sanitizer_tls_get_addr.cc @@ -78,6 +78,15 @@ DTLS_Deallocate(dtls.dtv, s); } +#if defined(__powerpc64__) +// This is glibc's TLS_DTV_OFFSET: +// "Dynamic thread vector pointers point 0x8000 past the start of each +// TLS block." +static const uptr kDtvOffset = 0x8000; +#else +static const uptr kDtvOffset = 0; +#endif + DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res, uptr static_tls_begin, uptr static_tls_end) { if (!common_flags()->intercept_tls_get_addr) return 0; @@ -87,7 +96,7 @@ DTLS_Resize(dso_id + 1); if (dtls.dtv[dso_id].beg) return 0; uptr tls_size = 0; - uptr tls_beg = reinterpret_cast(res) - arg->offset; + uptr tls_beg = reinterpret_cast(res) - arg->offset - kDtvOffset; VPrintf(2, "__tls_get_addr: %p {%p,%p} => %p; tls_beg: %p; sp: %p " "num_live_dtls %zd\n", arg, arg->dso_id, arg->offset, res, tls_beg, &tls_beg, Index: test/asan/TestCases/Linux/static_tls.cc =================================================================== --- test/asan/TestCases/Linux/static_tls.cc +++ test/asan/TestCases/Linux/static_tls.cc @@ -9,7 +9,7 @@ // CHECK: __tls_get_addr: static tls // CHECK: after -// XFAIL: powerpc64, aarch64 +// XFAIL: aarch64 #ifndef SHARED #include