Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -120,6 +120,21 @@ Alignment = std::max(Alignment, IS->Alignment); + // On ARM/AArch64, overalign PT_TLS to 8 words to make the TLS layout + // compatible with Android Bionic. For simplicity, this overalignment is also + // done on other operating systems. However, this may cause + // p_vaddr%p_align!=0, which can cause crashes on glibc (and other ld.so + // implementations after they fix the bug). To fix that, consider two cases: + // + // 1) If .tdata exists, it will be the first section of the RW PT_LOAD + // (non-TLS sections in the segment have higher ranks due to RF_NOT_TLS) and + // it will be page aligned. p_vaddr%p_align==0 follows naturally. + // 2) If .tdata doesn't exist, .tbss will not be placed in a RW PT_LOAD. + // Overalign .tbss to ensure p_vaddr%p_align==0. + if (Type == SHT_NOBITS && (Flags & ELF::SHF_TLS) && !Config->Shared && + (Config->EMachine == EM_ARM || Config->EMachine == EM_AARCH64)) + Alignment = std::max(Alignment, Config->Wordsize * 8); + // If this section contains a table of fixed-size entries, sh_entsize // holds the element size. If it contains elements of different size we // set sh_entsize to 0. Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -2190,15 +2190,11 @@ if (P->p_type == PT_TLS && P->p_memsz) { if (!Config->Shared && (Config->EMachine == EM_ARM || Config->EMachine == EM_AARCH64)) { - // On ARM/AArch64, reserve extra space (8 words) between the thread - // pointer and an executable's TLS segment by overaligning the segment. - // This reservation is needed for backwards compatibility with Android's - // TCB, which allocates several slots after the thread pointer (e.g. - // TLS_SLOT_STACK_GUARD==5). For simplicity, this overalignment is also - // done on other operating systems. + // See the comment in OutputSection::addSection. P->p_align = std::max(P->p_align, Config->Wordsize * 8); } + // The TLS pointer goes after PT_TLS for variant 2 targets. At least glibc // will align it, so round up the size to make sure the offsets are // correct. Index: test/ELF/android-tls.s =================================================================== --- /dev/null +++ test/ELF/android-tls.s @@ -0,0 +1,17 @@ +# REQUIRES: arm +# RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-android %s -o %t.o +# RUN: ld.lld %t.o -o %t +# RUN: llvm-readelf -l %t | FileCheck --check-prefix=A32 %s + +# RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-android %s -o %t.o +# RUN: ld.lld %t.o -o %t +# RUN: llvm-readelf -l %t | FileCheck --check-prefix=A64 %s + +## Android Bionic reserves several slots after the thread pointer. Check we +## overalign the PT_TLS segment to adapt to its TLS layout. + +# A32: TLS {{.*}} 0x20 +# A64: TLS {{.*}} 0x40 + +.section .tbss,"awT",%nobits +.byte 0 Index: test/ELF/arm-tls-gd-nonpreemptible.s =================================================================== --- test/ELF/arm-tls-gd-nonpreemptible.s +++ test/ELF/arm-tls-gd-nonpreemptible.s @@ -65,7 +65,7 @@ // CHECK: Contents of section .got: // CHECK-NEXT: 12008 01000000 00000000 01000000 04000000 -// CHECK-NEXT: 12018 01000000 08000000 01000000 0c000000 +// CHECK-NEXT: 12018 01000000 20000000 01000000 24000000 // CHECK-SHARED: Contents of section .got: // CHECK-SHARED-NEXT: 2050 00000000 00000000 00000000 04000000 Index: test/ELF/arm-tls-le32.s =================================================================== --- test/ELF/arm-tls-le32.s +++ test/ELF/arm-tls-le32.s @@ -61,7 +61,7 @@ // SEC-NEXT: SHF_TLS // SEC-NEXT: SHF_WRITE // SEC-NEXT: ] -// SEC-NEXT: Address: 0x12004 +// SEC-NEXT: Address: 0x12020 // SEC: Size: 8 // SEC: Dynamic Relocations { @@ -73,6 +73,6 @@ // offset of x from Thread pointer = (TcbSize + 0x0 = 0x20) // CHECK-NEXT: 11000: 20 00 00 00 // offset of z from Thread pointer = (TcbSize + 0x8 = 0x28) -// CHECK-NEXT: 11004: 28 00 00 00 -// offset of y from Thread pointer = (TcbSize + 0x4 = 0x24) -// CHECK-NEXT: 11008: 24 00 00 00 +// CHECK-NEXT: 11004: 44 00 00 00 +// offset of y from Thread pointer = (TcbSize + 0x24 = 0x44) +// CHECK-NEXT: 11008: 40 00 00 00 Index: test/ELF/arm-tls-norelax-ie-le.s =================================================================== --- test/ELF/arm-tls-norelax-ie-le.s +++ test/ELF/arm-tls-norelax-ie-le.s @@ -37,5 +37,5 @@ .type x2, %object // CHECK: Contents of section .got: -// x1 at offset 0x20 from TP, x2 at offset 0x24 from TP. Offsets include TCB size of 0x20 -// CHECK-NEXT: 12064 20000000 24000000 +// x1 at offset 0x20 from TP, x2 at offset 0x40 from TP. Offsets include TCB size of 0x20 +// CHECK-NEXT: 12064 20000000 40000000