@@ -188,8 +188,80 @@ __attribute__((unused)) static bool GetLibcVersion(int *major, int *minor,
188188#endif
189189}
190190
191- // ThreadDescriptorSize() is only used by lsan to get the pointer to
192- // thread-specific data keys in the thread control block.
191+ #if SANITIZER_GLIBC && !SANITIZER_GO
192+ static uptr g_tls_size;
193+
194+ #ifdef __i386__
195+ #define CHECK_GET_TLS_STATIC_INFO_VERSION (!__GLIBC_PREREQ(2 , 27 ))
196+ #else
197+ #define CHECK_GET_TLS_STATIC_INFO_VERSION 0
198+ #endif
199+
200+ #if CHECK_GET_TLS_STATIC_INFO_VERSION
201+ #define DL_INTERNAL_FUNCTION __attribute__ ((regparm(3 ), stdcall))
202+ #else
203+ #define DL_INTERNAL_FUNCTION
204+ #endif
205+
206+ namespace {
207+ struct GetTlsStaticInfoCall {
208+ typedef void (*get_tls_func)(size_t *, size_t *);
209+ };
210+ struct GetTlsStaticInfoRegparmCall {
211+ typedef void (*get_tls_func)(size_t *, size_t *) DL_INTERNAL_FUNCTION;
212+ };
213+
214+ template <typename T>
215+ void CallGetTls (void * ptr, size_t * size, size_t * align) {
216+ typename T::get_tls_func get_tls;
217+ CHECK_EQ (sizeof (get_tls), sizeof (ptr));
218+ internal_memcpy (&get_tls, &ptr, sizeof (ptr));
219+ CHECK_NE (get_tls, 0 );
220+ get_tls (size, align);
221+ }
222+
223+ bool CmpLibcVersion (int major, int minor, int patch) {
224+ int ma;
225+ int mi;
226+ int pa;
227+ if (!GetLibcVersion (&ma, &mi, &pa))
228+ return false ;
229+ if (ma > major)
230+ return true ;
231+ if (ma < major)
232+ return false ;
233+ if (mi > minor)
234+ return true ;
235+ if (mi < minor)
236+ return false ;
237+ return pa >= patch;
238+ }
239+
240+ } // namespace
241+
242+ void InitTlsSize () {
243+ // all current supported platforms have 16 bytes stack alignment
244+ const size_t kStackAlign = 16 ;
245+ void *get_tls_static_info_ptr = dlsym (RTLD_NEXT, " _dl_get_tls_static_info" );
246+ size_t tls_size = 0 ;
247+ size_t tls_align = 0 ;
248+ // On i?86, _dl_get_tls_static_info used to be internal_function, i.e.
249+ // __attribute__((regparm(3), stdcall)) before glibc 2.27 and is normal
250+ // function in 2.27 and later.
251+ if (CHECK_GET_TLS_STATIC_INFO_VERSION && !CmpLibcVersion (2 , 27 , 0 ))
252+ CallGetTls<GetTlsStaticInfoRegparmCall>(get_tls_static_info_ptr,
253+ &tls_size, &tls_align);
254+ else
255+ CallGetTls<GetTlsStaticInfoCall>(get_tls_static_info_ptr,
256+ &tls_size, &tls_align);
257+ if (tls_align < kStackAlign )
258+ tls_align = kStackAlign ;
259+ g_tls_size = RoundUpTo (tls_size, tls_align);
260+ }
261+ #else
262+ void InitTlsSize () { }
263+ #endif // SANITIZER_GLIBC && !SANITIZER_GO
264+
193265#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) || \
194266 defined (__aarch64__) || defined(__powerpc64__) || defined(__s390__) || \
195267 defined(__arm__) || SANITIZER_RISCV64) && \
@@ -262,6 +334,13 @@ uptr ThreadDescriptorSize() {
262334 return val;
263335}
264336
337+ // The offset at which pointer to self is located in the thread descriptor.
338+ const uptr kThreadSelfOffset = FIRST_32_SECOND_64(8 , 16 );
339+
340+ uptr ThreadSelfOffset () {
341+ return kThreadSelfOffset ;
342+ }
343+
265344#if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
266345// TlsPreTcbSize includes size of struct pthread_descr and size of tcb
267346// head structure. It lies before the static tls blocks.
@@ -280,63 +359,48 @@ static uptr TlsPreTcbSize() {
280359}
281360#endif
282361
283- #if !SANITIZER_GO
284- namespace {
285- struct TlsRange {
286- uptr begin, end, align;
287- size_t tls_modid;
288- bool operator <(const TlsRange &rhs) const { return begin < rhs.begin ; }
289- };
290- } // namespace
291-
292- static int CollectStaticTlsRanges (struct dl_phdr_info *info, size_t size,
293- void *data) {
294- if (!info->dlpi_tls_data )
295- return 0 ;
296- const uptr begin = (uptr)info->dlpi_tls_data ;
297- for (unsigned i = 0 ; i != info->dlpi_phnum ; ++i)
298- if (info->dlpi_phdr [i].p_type == PT_TLS) {
299- static_cast <InternalMmapVector<TlsRange> *>(data)->push_back (
300- TlsRange{begin, begin + info->dlpi_phdr [i].p_memsz ,
301- info->dlpi_phdr [i].p_align , info->dlpi_tls_modid });
302- break ;
303- }
304- return 0 ;
362+ uptr ThreadSelf () {
363+ uptr descr_addr;
364+ #if defined(__i386__)
365+ asm (" mov %%gs:%c1,%0" : " =r" (descr_addr) : " i" (kThreadSelfOffset ));
366+ #elif defined(__x86_64__)
367+ asm (" mov %%fs:%c1,%0" : " =r" (descr_addr) : " i" (kThreadSelfOffset ));
368+ #elif defined(__mips__)
369+ // MIPS uses TLS variant I. The thread pointer (in hardware register $29)
370+ // points to the end of the TCB + 0x7000. The pthread_descr structure is
371+ // immediately in front of the TCB. TlsPreTcbSize() includes the size of the
372+ // TCB and the size of pthread_descr.
373+ const uptr kTlsTcbOffset = 0x7000 ;
374+ uptr thread_pointer;
375+ asm volatile (" .set push;\
376+ .set mips64r2;\
377+ rdhwr %0,$29;\
378+ .set pop" : " =r" (thread_pointer));
379+ descr_addr = thread_pointer - kTlsTcbOffset - TlsPreTcbSize ();
380+ #elif defined(__aarch64__) || defined(__arm__)
381+ descr_addr = reinterpret_cast <uptr>(__builtin_thread_pointer ()) -
382+ ThreadDescriptorSize ();
383+ #elif SANITIZER_RISCV64
384+ // https://github.com/riscv/riscv-elf-psabi-doc/issues/53
385+ uptr thread_pointer = reinterpret_cast <uptr>(__builtin_thread_pointer ());
386+ descr_addr = thread_pointer - TlsPreTcbSize ();
387+ #elif defined(__s390__)
388+ descr_addr = reinterpret_cast <uptr>(__builtin_thread_pointer ());
389+ #elif defined(__powerpc64__)
390+ // PPC64LE uses TLS variant I. The thread pointer (in GPR 13)
391+ // points to the end of the TCB + 0x7000. The pthread_descr structure is
392+ // immediately in front of the TCB. TlsPreTcbSize() includes the size of the
393+ // TCB and the size of pthread_descr.
394+ const uptr kTlsTcbOffset = 0x7000 ;
395+ uptr thread_pointer;
396+ asm (" addi %0,13,%1" : " =r" (thread_pointer) : " I" (-kTlsTcbOffset ));
397+ descr_addr = thread_pointer - TlsPreTcbSize ();
398+ #else
399+ #error "unsupported CPU arch"
400+ #endif
401+ return descr_addr;
305402}
306-
307- static void GetStaticTlsRange (uptr *addr, uptr *size, uptr *align) {
308- InternalMmapVector<TlsRange> ranges;
309- dl_iterate_phdr (CollectStaticTlsRanges, &ranges);
310- uptr len = ranges.size ();
311- Sort (ranges.begin (), len);
312- // Find the range with tls_modid=1. For glibc, because libc.so uses PT_TLS,
313- // this module is guaranteed to exist and is one of the initially loaded
314- // modules.
315- uptr one = 0 ;
316- while (one != len && ranges[one].tls_modid != 1 ) ++one;
317- if (one == len) {
318- // This may happen with musl if no module uses PT_TLS.
319- *addr = 0 ;
320- *size = 0 ;
321- *align = 1 ;
322- return ;
323- }
324- // Find the maximum consecutive ranges. We consider two modules consecutive if
325- // the gap is smaller than the alignment. The dynamic loader places static TLS
326- // blocks this way not to waste space.
327- uptr l = one;
328- *align = ranges[l].align ;
329- while (l != 0 && ranges[l].begin < ranges[l - 1 ].end + ranges[l - 1 ].align )
330- *align = Max (*align, ranges[--l].align );
331- uptr r = one + 1 ;
332- while (r != len && ranges[r].begin < ranges[r - 1 ].end + ranges[r - 1 ].align )
333- *align = Max (*align, ranges[r++].align );
334- *addr = ranges[l].begin ;
335- *size = ranges[r - 1 ].end - ranges[l].begin ;
336- }
337- #endif // !SANITIZER_GO
338- #endif // (x86_64 || i386 || mips || ...) && SANITIZER_LINUX &&
339- // !SANITIZER_ANDROID
403+ #endif // (x86_64 || i386 || MIPS) && SANITIZER_LINUX
340404
341405#if SANITIZER_FREEBSD
342406static void **ThreadSelfSegbase () {
@@ -408,54 +472,18 @@ static void GetTls(uptr *addr, uptr *size) {
408472 *size = 0 ;
409473 }
410474#elif SANITIZER_LINUX
411- uptr align;
412- GetStaticTlsRange (addr, size, &align);
413475#if defined(__x86_64__) || defined(__i386__) || defined(__s390__)
414- if (SANITIZER_GLIBC) {
415- #if defined(__s390__)
416- align = Max<uptr>(align, 16 );
417- #else
418- align = Max<uptr>(align, 64 );
419- #endif
420- }
421- const uptr tp = RoundUpTo (*addr + *size, align);
422-
423- // lsan requires the range to additionally cover the static TLS surplus
424- // (elf/dl-tls.c defines 1664). Otherwise there may be false positives for
425- // allocations only referenced by tls in dynamically loaded modules.
426- if (SANITIZER_GLIBC)
427- *size += 1644 ;
428-
429- // Extend the range to include the thread control block. On glibc, lsan needs
430- // the range to include pthread::{specific_1stblock,specific} so that
431- // allocations only referenced by pthread_setspecific can be scanned. This may
432- // underestimate by at most TLS_TCB_ALIGN-1 bytes but it should be fine
433- // because the number of bytes after pthread::specific is larger.
434- *addr = tp - RoundUpTo (*size, align);
435- *size = tp - *addr + ThreadDescriptorSize ();
436- #else
437- if (SANITIZER_GLIBC)
438- *size += 1664 ;
439- #if defined(__powerpc64__)
440- // TODO Figure out why *addr may be zero and use TlsPreTcbSize.
441- void *ptr = dlsym (RTLD_NEXT, " _dl_get_tls_static_info" );
442- uptr tls_size, tls_align;
443- ((void (*)(size_t *, size_t *))ptr)(&tls_size, &tls_align);
444- asm (" addi %0,13,-0x7000" : " =r" (*addr));
445- *addr -= TlsPreTcbSize ();
446- *size = RoundUpTo (tls_size + TlsPreTcbSize (), 16 );
447- #elif defined(__mips__) || SANITIZER_RISCV64
448- const uptr pre_tcb_size = TlsPreTcbSize ();
449- *addr -= pre_tcb_size;
450- *size += pre_tcb_size;
476+ *addr = ThreadSelf ();
477+ *size = GetTlsSize ();
478+ *addr -= *size;
479+ *addr += ThreadDescriptorSize ();
480+ #elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__) || \
481+ defined (__arm__) || SANITIZER_RISCV64
482+ *addr = ThreadSelf ();
483+ *size = GetTlsSize ();
451484#else
452- // arm and aarch64 reserve two words at TP, so this underestimates the range.
453- // However, this is sufficient for the purpose of finding the pointers to
454- // thread-specific data keys.
455- const uptr tcb_size = ThreadDescriptorSize ();
456- *addr -= tcb_size;
457- *size += tcb_size;
458- #endif
485+ *addr = 0 ;
486+ *size = 0 ;
459487#endif
460488#elif SANITIZER_FREEBSD
461489 void ** segbase = ThreadSelfSegbase ();
@@ -496,11 +524,17 @@ static void GetTls(uptr *addr, uptr *size) {
496524
497525#if !SANITIZER_GO
498526uptr GetTlsSize () {
499- #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
527+ #if SANITIZER_FREEBSD || SANITIZER_ANDROID || SANITIZER_NETBSD || \
500528 SANITIZER_SOLARIS
501529 uptr addr, size;
502530 GetTls (&addr, &size);
503531 return size;
532+ #elif SANITIZER_GLIBC
533+ #if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
534+ return RoundUpTo (g_tls_size + TlsPreTcbSize (), 16 );
535+ #else
536+ return g_tls_size;
537+ #endif
504538#else
505539 return 0 ;
506540#endif
@@ -523,9 +557,10 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
523557 if (!main) {
524558 // If stack and tls intersect, make them non-intersecting.
525559 if (*tls_addr > *stk_addr && *tls_addr < *stk_addr + *stk_size) {
526- if (*stk_addr + *stk_size < *tls_addr + *tls_size)
527- *tls_size = *stk_addr + *stk_size - *tls_addr;
528- *stk_size = *tls_addr - *stk_addr;
560+ CHECK_GT (*tls_addr + *tls_size, *stk_addr);
561+ CHECK_LE (*tls_addr + *tls_size, *stk_addr + *stk_size);
562+ *stk_size -= *tls_size;
563+ *tls_addr = *stk_addr + *stk_size;
529564 }
530565 }
531566#endif
0 commit comments