[PATCH] D19778: [sanitizers] [SystemZ] Add __tls_get_offset interceptor.

Marcin Koƛcielnicki via llvm-commits llvm-commits at lists.llvm.org
Sun May 1 13:04:58 PDT 2016


koriakin created this revision.
koriakin added reviewers: kcc, eugenis, uweigand.
koriakin added a subscriber: llvm-commits.
koriakin set the repository for this revision to rL LLVM.
koriakin added a project: Sanitizers.
Herald added a subscriber: kubabrecka.

s390 is special again - instead of __tls_get_addr, it has __tls_get_offset
with special calling conventions: the result is TP relative, and
the argument is GOT-relative.  Since we need to get address of the caller's
GOT, which is in %r12, we have to use assembly like glibc does.

Aside of __tls_get_offset, glibc also implements a slightly saner
__tls_get_addr_internal, which takes a pointer as argument, but still
returns a TP-relative offset.  It is used for dlsym() called on TLS
symbols, so we have to intercept it was well.  Our __tls_get_offset
is also implemented by delegating to it.

Repository:
  rL LLVM

http://reviews.llvm.org/D19778

Files:
  lib/sanitizer_common/sanitizer_common_interceptors.inc

Index: lib/sanitizer_common/sanitizer_common_interceptors.inc
===================================================================
--- lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -4373,26 +4373,72 @@
 #endif
 
 #if SANITIZER_INTERCEPT_TLS_GET_ADDR
+#if SANITIZER_S390
+// On s390, we have to intercept two functions here:
+// - __tls_get_addr_internal, which is a glibc-internal function that is like
+//   the usual __tls_get_addr, but returns a TP-relative offset instead of
+//   a proper pointer.  It is used by dlsym for TLS symbols.
+// - __tls_get_offset, which is like the above, but also takes a GOT-relative
+//   descriptor offset as an argument instead of a pointer.  GOT address
+//   is passed in r12, so it's necessary to write it in assembly.  This is
+//   the function used by the compiler.
+#define __tls_get_addr __tls_get_addr_internal
+#endif
 #define INIT_TLS_GET_ADDR COMMON_INTERCEPT_FUNCTION(__tls_get_addr)
 // If you see any crashes around this functions, there are 2 known issues with
 // it: 1. __tls_get_addr can be called with mis-aligned stack due to:
 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58066
 // 2. It can be called recursively if sanitizer code uses __tls_get_addr
 // to access thread local variables (it should not happen normally,
 // because sanitizers use initial-exec tls model).
-INTERCEPTOR(void *, __tls_get_addr, void *arg) {
+INTERCEPTOR(uptr, __tls_get_addr, void *arg) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, __tls_get_addr, arg);
-  void *res = REAL(__tls_get_addr)(arg);
+  uptr res = REAL(__tls_get_addr)(arg);
+#if SANITIZER_S390
+  uptr tp = reinterpret_cast<uptr>(__builtin_thread_pointer());
+  void *ptr = reinterpret_cast<void *>(res + tp);
+#else
+  void *ptr = reinterpret_cast<void *>(res);
+#endif
   uptr tls_begin, tls_end;
   COMMON_INTERCEPTOR_GET_TLS_RANGE(&tls_begin, &tls_end);
-  DTLS::DTV *dtv = DTLS_on_tls_get_addr(arg, res, tls_begin, tls_end);
+  DTLS::DTV *dtv = DTLS_on_tls_get_addr(arg, ptr, tls_begin, tls_end);
   if (dtv) {
     // New DTLS block has been allocated.
     COMMON_INTERCEPTOR_INITIALIZE_RANGE((void *)dtv->beg, dtv->size);
   }
   return res;
 }
+#if SANITIZER_S390
+// We need a protected symbol aliasing the above, so that we can jump
+// directly to it from the assembly below.
+extern "C" __attribute__((alias("__interceptor___tls_get_addr_internal"),
+                          visibility("protected")))
+uptr __interceptor___tls_get_addr_internal_protected(void *arg);
+// Now carefully intercept __tls_get_offset.
+asm(
+  ".text\n"
+  ".global __tls_get_offset\n"
+  "__tls_get_offset:\n"
+// The __intercept_ version has to exist, so that gen_dynamic_list.py
+// exports our symbol.
+  ".global __interceptor___tls_get_offset\n"
+  "__interceptor___tls_get_offset:\n"
+#ifdef __s390x__
+  "la %r2, 0(%r2,%r12)\n"
+  "jg __interceptor___tls_get_addr_internal_protected\n"
+#else
+  "basr %r3,0\n"
+  "0: la %r2,0(%r2,%r12)\n"
+  "l %r4,1f-0b(%r3)\n"
+  "b 0(%r4,%r3)\n"
+  "1: .long __interceptor___tls_get_addr_internal_protected - 0b\n"
+#endif
+  ".type __tls_get_offset, @function\n"
+  ".size __tls_get_offset, .-__tls_get_offset\n"
+);
+#endif // SANITIZER_S390
 #else
 #define INIT_TLS_GET_ADDR
 #endif


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D19778.55758.patch
Type: text/x-patch
Size: 3308 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20160501/1c9277ac/attachment.bin>


More information about the llvm-commits mailing list