D53906 increased p_align of PT_TLS on ARM/AArch64 to 32/64 to make the
TLS layout compatible with Android Bionic. However, this can make glibc
ARM/AArch64 programs using {initial,local}-exec TLS models crash (see
PR41527).
The faulty PT_TLS satisfies p_vaddr%p_align != 0. The remainder is normally
0 but may be non-zero with the D53906 hack in place. The problem is that
we increase the p_align of the PT_TLS after the OutputSection's
addresses are fixed (assignAddress()). It is possible that
p_vaddr%old_p_align = 0 while p_vaddr%new_p_align != 0.
When this happens, lld and different ld.so implementations have
different opinions on the offset of the first module. glibc elf/dl-tls.c
computes an offset that satisfies: offset%p_align == p_vaddr%p_align.
This is correct as a basic ELF requirement.
lld, musl (1.1.20 ~ latest 1.1.22), FreeBSD rtld, and Bionic place the
main TLS block at a wrong offset: `alignUp(2*sizeof(void*),
main_tls_align)`. This choice doesn't take p_vaddr%p_align into account.
An approach to make both Bionic and glibc happy is to overalign SHF_TLS
instead of PT_TLS. It has several disadvantages:
- Moving the hack to the OutputSection layer makes the hack more perceivable as it has interaction with the linker script ALIGNUP command.
- It may waste up to 8*WordSize * 2 bytes of each thread (when both .tbss and .tdata exist and are overaligned). With more code, we can apply the overalignment to the first TLS output section (either .tbss or .tdata) and decrease the wastage to 8*WordSize, but that is still unsatisfactory on other platforms.
This patch keeps the hack under an option. This option may be deleted
when a better fix arises, e.g. a solution that works across
ld.bfd/gold/lld is to add a dummy .tdata (1-sized 64-aligned if Bionic
aligns the end of the TLS block; 48-sized 1-aligned if Bionic aligns the
start of the TLS block) in Android's crtbegin_{dynamic,static}.o . A
R_{ARM,AARCH64}_NONE relocation reference from _start is required to
make the .tdata survive --gc-sections.
Currently, however, Bionic has an alignment check
__bionic_check_tls_alignment that collides with this fix and it may be
too late due to deployment issues. Ideally the vaddr%p_align != 0 case
should also be fixed.