[PATCH] D61824: [ARM][AArch64] Overalign SHF_TLS instead of PT_TLS (Android Bionic hack) to make glibc happy

Fangrui Song via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Mon May 13 07:11:20 PDT 2019


MaskRay added a comment.

In D61824#1499796 <https://reviews.llvm.org/D61824#1499796>, @peter.smith wrote:

> I think that this will definitely fix the problem, but I'd like to understand a bit more about what glibc is doing and what assumptions it is making, there does seem to be some code that attempts to deal with a PT_TLS with p_vaddr != 0 modulo p_align. My understanding from looking at dt-tls.c _dl_determine_tlsoffset() which sets the offset of each tls block (with the executable being in slot 0). Does something like this:
>
> - offset = TLS_TCB_SIZE (hard-coded to 2 * (void*) pointers.
> - calculates firstbyte, which is derived from l_tls_firstbyte_offset which is PT_TLS p_vaddr % p_align. For the example in pr41527 this is 32 bytes
> - sets the l_tls_offset of slot 0 to alignto(offset, p_align) - firstbyte.
>
>   With an unpatched LLD we are expecting l_tls_offset to be alignto(offset, p_align).
>
>   Have I got that right, and can you point out what assumption glibc is making? I've not yet managed to convince myself what it is doing wrong? I think that this may be important in choosing between this and D61825 <https://reviews.llvm.org/D61825>. It may be that what we do now just happens to work for non-glibc but we may still not be entirely correct. If that is the case then this would favour this fix rather than D61825 <https://reviews.llvm.org/D61825>.
>
>   The other problem with D61825 <https://reviews.llvm.org/D61825> is that it forces a change to the clang driver to Android to always pass the flag through to LLD. That is something the Android toolchain folk will want to comment on.


Some background:

  GAP_ABOVE_TP = 2 * sizeof(void*)
  the offset of the main module = alignUp(GAP_ABOVE_TP, main_tls_align)
  the linker and the dynamic loader must agree upon this
  
  Android bionic: the offset of the main module must be >= 8 * sizeof(void*)
  freebsd rtld: good
  musl: if main_tls_align > GAP_ABOVE_TP, the offset of the main module was wrong before 1.1.20
  glibc: p_vaddr%p_align != 0 => wrong offset of the first module



> Have I got that right, and can you point out what assumption glibc is making?

Below is my understanding about how glibc is wrong. glibc/elf/dl-tls.c:250 (the `#elif TLS_DTV_AT_TP` part)

  // I don't know what this piece of code intended to do with non-zero firstbyte...
  off = roundup (offset, slotinfo[cnt].map->l_tls_align); // roundup(16, 64) = 64
  if (off - offset < firstbyte) // 64 - 16 ; 32
    off += slotinfo[cnt].map->l_tls_align;
  slotinfo[cnt].map->l_tls_offset = off - firstbyte; // 64 - 32 = 32, wrong, should be 64
  
  // If firstbyte is 0 (i.e. p_vaddr % l_tls_align == 0), this is simply:
  off = roundup (offset, slotinfo[cnt].map->l_tls_align);
  slotinfo[cnt].map->l_tls_offset = off;
  // and is correct

I hope Szabolcs can chime in as he is the maintainer of glibc's arm port..


Repository:
  rLLD LLVM Linker

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61824/new/

https://reviews.llvm.org/D61824





More information about the llvm-commits mailing list