Index: lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp =================================================================== --- lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp +++ lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp @@ -399,6 +399,58 @@ write32le(location, result | read32le(location)); } +/// \brief R_AARCH64_TLSDESC_ADR_PAGE21 - Page(G(GTLSDESC(S+A))) - Page(P) +static std::error_code relocR_AARCH64_TLSDESC_ADR_PAGE21(uint8_t *location, + uint64_t P, uint64_t S, + int64_t A) { + int64_t result = page(S + A) - page(P); + if (!isInt<32>(result)) + return make_out_of_range_reloc_error(); + result = result >> 12; + uint32_t immlo = result & 0x3; + uint32_t immhi = result & 0x1FFFFC; + immlo = immlo << 29; + immhi = immhi << 3; + DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; + llvm::dbgs() << " S: " << Twine::utohexstr(S); + llvm::dbgs() << " A: " << Twine::utohexstr(A); + llvm::dbgs() << " P: " << Twine::utohexstr(P); + llvm::dbgs() << " immhi: " << Twine::utohexstr(immhi); + llvm::dbgs() << " immlo: " << Twine::utohexstr(immlo); + llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n"); + write32le(location, immlo | immhi | read32le(location)); + return std::error_code(); +} + +/// \brief R_AARCH64_TLSDESC_LD64_LO12_NC - G(GTLSDESC(S+A)) -> S + A +static void relocR_AARCH64_TLSDESC_LD64_LO12_NC(uint8_t *location, uint64_t P, + uint64_t S, int64_t A) { + int32_t result = S + A; + DEBUG(llvm::dbgs() << " S: " << Twine::utohexstr(S); + llvm::dbgs() << " A: " << Twine::utohexstr(A); + llvm::dbgs() << " P: " << Twine::utohexstr(P); + llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n"); + //if ((result & 0x7) != 0) + // return make_unaligned_range_reloc_error(); + result &= 0xFF8; + result <<= 7; + write32le(location, result | read32le(location)); + //return std::error_code(); +} + +/// \brief R_AARCH64_TLSDESC_ADD_LO12_NC - G(GTLSDESC(S+A)) -> S + A +static void relocR_AARCH64_TLSDESC_ADD_LO12_NC(uint8_t *location, uint64_t P, + uint64_t S, int64_t A) { + int32_t result = (int32_t)((S + A) & 0xFFF); + result <<= 10; + DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; + llvm::dbgs() << " S: " << Twine::utohexstr(S); + llvm::dbgs() << " A: " << Twine::utohexstr(A); + llvm::dbgs() << " P: " << Twine::utohexstr(P); + llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n"); + write32le(location, result | read32le(location)); +} + std::error_code AArch64TargetRelocationHandler::applyRelocation( ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom, const Reference &ref) const { @@ -428,13 +480,6 @@ return relocR_AARCH64_PREL32(loc, reloc, target, addend); case R_AARCH64_PREL16: return relocR_AARCH64_PREL16(loc, reloc, target, addend); - // Runtime only relocations. Ignore here. - case R_AARCH64_RELATIVE: - case R_AARCH64_IRELATIVE: - case R_AARCH64_JUMP_SLOT: - case R_AARCH64_GLOB_DAT: - case R_AARCH64_TLS_TPREL64: - break; case R_AARCH64_ADR_PREL_PG_HI21: return relocR_AARCH64_ADR_PREL_PG_HI21(loc, reloc, target, addend); case R_AARCH64_ADR_PREL_LO21: @@ -484,6 +529,25 @@ relocR_AARCH64_TLSLE_ADD_TPREL_LO12_NC(loc, reloc, target + tpoffset, addend); } break; + case R_AARCH64_TLSDESC_ADR_PAGE21: + return relocR_AARCH64_TLSDESC_ADR_PAGE21(loc, reloc, target, addend); + case R_AARCH64_TLSDESC_LD64_LO12_NC: + relocR_AARCH64_TLSDESC_LD64_LO12_NC(loc, reloc, target, addend); + break; + case R_AARCH64_TLSDESC_ADD_LO12_NC: + relocR_AARCH64_TLSDESC_ADD_LO12_NC(loc, reloc, target, addend); + break; + case R_AARCH64_TLSDESC_CALL: + // Relaxation only to optimize TLS access. Ignore for now. + break; + // Runtime only relocations. Ignore here. + case R_AARCH64_RELATIVE: + case R_AARCH64_IRELATIVE: + case R_AARCH64_JUMP_SLOT: + case R_AARCH64_GLOB_DAT: + case R_AARCH64_TLS_TPREL64: + case R_AARCH64_TLSDESC: + break; default: return make_unhandled_reloc_error(); } Index: lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp =================================================================== --- lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp +++ lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp @@ -31,6 +31,13 @@ // .got values static const uint8_t AArch64GotAtomContent[8] = {0}; +// tls descriptor .got values, the layout is: +// struct tlsdesc { +// ptrdiff_t (*entry) (struct tlsdesc *); +// void *arg; +// }; +static const uint8_t AArch64TlsdescGotAtomContent[16] = {0}; + // .plt value (entry 0) static const uint8_t AArch64Plt0AtomContent[32] = { 0xf0, 0x7b, 0xbf, 0xa9, // stp x16, x30, [sp,#-16]! @@ -51,6 +58,18 @@ 0x20, 0x02, 0x1f, 0xd6 // br x17 }; +// .plt tlsdesc values +static const uint8_t AArch64PltTlsdescAtomContent[32] = { + 0xe2, 0x0f, 0xbf, 0xa9, // stp x2, x3, [sp, #-16] + 0x02, 0x00, 0x00, 0x90, // adpr x2, 0 + 0x03, 0x00, 0x00, 0x90, // adpr x3, 0 + 0x42, 0x00, 0x40, 0xf9, // ldr x2, [x2, #0] + 0x63, 0x00, 0x00, 0x91, // add x3, x3, 0 + 0x40, 0x00, 0x1f, 0xd6, // br x2 + 0x1f, 0x20, 0x03, 0xd5, // nop + 0x1f, 0x20, 0x03, 0xd5 // nop +}; + namespace { /// \brief Atoms that are used by AArch64 dynamic linking @@ -72,6 +91,16 @@ AArch64GOTPLTAtom(const File &f) : AArch64GOTAtom(f, ".got.plt") {} }; +class AArch64TLSDESCGOTAtom : public AArch64GOTPLTAtom { +public: + AArch64TLSDESCGOTAtom(const File &f) : AArch64GOTPLTAtom(f) {} + + ArrayRef rawContent() const override { + return ArrayRef(AArch64TlsdescGotAtomContent, 16); + } +}; + + class AArch64PLT0Atom : public PLT0Atom { public: AArch64PLT0Atom(const File &f) : PLT0Atom(f) {} @@ -89,6 +118,15 @@ } }; +class AArch64PLTTLSDESCAtom : public PLTAtom { +public: + AArch64PLTTLSDESCAtom(const File &f) : PLTAtom(f, ".plt") {} + + ArrayRef rawContent() const override { + return ArrayRef(AArch64PltTlsdescAtomContent, 32); + } +}; + class ELFPassFile : public SimpleFile { public: ELFPassFile(const ELFLinkingContext &eti) : SimpleFile("ELFPassFile") { @@ -153,6 +191,11 @@ case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: static_cast(this)->handleGOTTPREL(ref); break; + case R_AARCH64_TLSDESC_ADR_PAGE21: + case R_AARCH64_TLSDESC_LD64_LO12_NC: + case R_AARCH64_TLSDESC_ADD_LO12_NC: + static_cast(this)->handleTLSDESC(ref); + break; } } @@ -212,8 +255,41 @@ /// \brief Create a GOT TPREL entry and change the relocation to a PC32 to /// the GOT. std::error_code handleGOTTPREL(const Reference &ref) { - if (isa(ref.target())) { + if (isa(ref.target())) const_cast(ref).setTarget(getGOTTPREL(ref.target())); + return std::error_code(); + } + + /// \brief Generates a double GOT entry with R_AARCH64_TLSDESC dynamic + /// relocation reference. Since the dynamic relocation is resolved + /// lazily so the GOT associated should be in .got.plt. + const GOTAtom *getTLSDESCPLTEntry(const Atom *da) { + auto got = _gotMap.find(da); + if (got != _gotMap.end()) + return got->second; + auto ga = new (_file._alloc) AArch64TLSDESCGOTAtom(_file); + ga->addReferenceELF_AArch64(R_AARCH64_TLSDESC, 0, da, 0); + auto pa = new (_file._alloc) AArch64PLTTLSDESCAtom(_file); + pa->addReferenceELF_AArch64(R_AARCH64_ADR_PREL_PG_HI21, 4, ga, 0); + pa->addReferenceELF_AArch64(R_AARCH64_ADR_PREL_PG_HI21, 8, ga, 0); + pa->addReferenceELF_AArch64(R_AARCH64_LDST64_ABS_LO12_NC, 12, ga, 0); + pa->addReferenceELF_AArch64(R_AARCH64_ADD_ABS_LO12_NC, 16, ga, 0); +#ifndef NDEBUG + ga->_name = "__got_tlsdesc_"; + ga->_name += da->name(); + pa->_name = "__plt_tlsdesc_"; + pa->_name += da->name(); +#endif + _gotMap[da] = ga; + _pltMap[da] = pa; + _tlsdescVector.push_back(ga); + _pltVector.push_back(pa); + return ga; + } + + std::error_code handleTLSDESC(const Reference &ref) { + if (isa(ref.target())) { + const_cast(ref).setTarget(getTLSDESCPLTEntry(ref.target())); } return std::error_code(); } @@ -315,6 +391,11 @@ obj->setOrdinal(ordinal++); mf.addAtom(*obj); } + // Add any tlsdesc GOT relocation after default PLT and iFUNC entries. + for (auto &tlsdesc : _tlsdescVector) { + tlsdesc->setOrdinal(ordinal++); + mf.addAtom(*tlsdesc); + } return std::error_code(); } @@ -335,6 +416,7 @@ /// \brief the list of GOT/PLT atoms std::vector _gotVector; + std::vector _tlsdescVector; std::vector _pltVector; std::vector _objectVector; Index: lib/ReaderWriter/ELF/AArch64/AArch64SectionChunks.cpp =================================================================== --- lib/ReaderWriter/ELF/AArch64/AArch64SectionChunks.cpp +++ lib/ReaderWriter/ELF/AArch64/AArch64SectionChunks.cpp @@ -27,7 +27,8 @@ if (r->kindNamespace() != Reference::KindNamespace::ELF) continue; assert(r->kindArch() == Reference::KindArch::AArch64); - if (r->kindValue() == R_AARCH64_TLS_TPREL64) + if ((r->kindValue() == R_AARCH64_TLS_TPREL64) || + (r->kindValue() == R_AARCH64_TLSDESC)) _tlsMap[r->target()] = _tlsMap.size(); } Index: test/elf/AArch64/Inputs/general-dyn-tls-0.yaml =================================================================== --- /dev/null +++ test/elf/AArch64/Inputs/general-dyn-tls-0.yaml @@ -0,0 +1,65 @@ +--- +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + OSABI: ELFOSABI_GNU + Type: ET_REL + Machine: EM_AARCH64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x0000000000000004 + Content: FF4300D1E00F00B900040011E103002A48D03BD50801009108010091000100B9E10B00B9FF430091C0035FD6 + - Name: .rela.text + Type: SHT_RELA + Link: .symtab + AddressAlign: 0x0000000000000008 + Info: .text + Relocations: + - Offset: 0x0000000000000014 + Symbol: var + Type: R_AARCH64_TLSLE_ADD_TPREL_HI12 + - Offset: 0x0000000000000018 + Symbol: var + Type: R_AARCH64_TLSLE_ADD_TPREL_LO12_NC + - Name: .data + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x0000000000000004 + Content: '' + - Name: .bss + Type: SHT_NOBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x0000000000000004 + Content: '' + - Name: .tbss + Type: SHT_NOBITS + Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ] + AddressAlign: 0x0000000000000004 + Content: 00636C61 + - Name: .note.GNU-stack + Type: SHT_PROGBITS + AddressAlign: 0x0000000000000001 + Content: '' +Symbols: + Local: +# - Name: test_tls.c +# Type: STT_FILE + - Name: '$d.1' + Section: .tbss + - Name: '$x.0' + Section: .text + - Name: .tbss + Type: STT_TLS + Section: .tbss + Global: + - Name: foo + Type: STT_FUNC + Section: .text + Size: 0x000000000000002C + - Name: var + Type: STT_TLS + Section: .tbss + Size: 0x0000000000000004 +... Index: test/elf/AArch64/general-dyn-tls-0.test =================================================================== --- /dev/null +++ test/elf/AArch64/general-dyn-tls-0.test @@ -0,0 +1,104 @@ +# Check for correct offsets when handling relocations for general dynamic TLS +# access in executable binaries. +# +# The test case was generated from following code snippet: +# +# == test_tls.c == +# +# __thread int var; +# void foo (int x) { +# var = x + 1; +# } +# +# == test_main.c == +# #include +# +# extern __thread int var; +# extern void foo (int); +# +# int main () { +# foo (10); +# return var; +# } +# +# The objects are compiled with -fpic. + +#RUN: yaml2obj -format=elf %p/Inputs/general-dyn-tls-0.yaml -o=%t-t1.o +#RUN: yaml2obj -format=elf %s -o %t-t0.o +#RUN: lld -flavor gnu -target arm64 --noinhibit-exec -o %t.exe %t-t0.o %t-t1.o +#RUN: llvm-readobj -relocations %t.exe | FileCheck %s -check-prefix=CHECKRELOCATION +#RUN: llvm-objdump -s -t %t.exe | FileCheck %s + +#CHECKRELOCATION: Relocations [ +#CHECKRELOCATION: .rela.dyn { +#CHECKRELOCATION: 0x401090 R_AARCH64_TLSDESC - 0x0 +#CHECKRELOCATION: } + +#CHECK: Contents of section .text: +#CHECK: 400230 a8c31fb8 40018052 0b000094 000000b0 ....@..R........ +# \_ adrp x0, 401000 <_DYNAMIC> (R_AARCH64_TLSDESC_ADR_PAGE21) +#CHECK-NEXT: 400240 014840f9 00400291 20003fd6 49d03bd5 .H@..@.. .?.I.;. +# \_ | | ldr x1, [x0,#144] (R_AARCH64_TLSDESC_LD64_LO12_NC) +# \_ | add x0, x0, #0x90 (R_AARCH64_TLSDESC_ADD_LO12_NC) +# \_ blr x1 (R_AARCH64_TLSDESC_CALL) + +--- +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + OSABI: ELFOSABI_GNU + Type: ET_REL + Machine: EM_AARCH64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x0000000000000004 + Content: FD7BBFA9FD030091FF4300D1E8031F2AA8C31FB8400180520000009400000090010040F90000009120003FD649D03BD5286960B8E003082ABF030091FD7BC1A8C0035FD6 + - Name: .rela.text + Type: SHT_RELA + Link: .symtab + AddressAlign: 0x0000000000000008 + Info: .text + Relocations: + - Offset: 0x0000000000000018 + Symbol: foo + Type: R_AARCH64_CALL26 + - Offset: 0x000000000000001C + Symbol: var + Type: R_AARCH64_TLSDESC_ADR_PAGE21 + - Offset: 0x0000000000000020 + Symbol: var + Type: R_AARCH64_TLSDESC_LD64_LO12_NC + - Offset: 0x0000000000000024 + Symbol: var + Type: R_AARCH64_TLSDESC_ADD_LO12_NC + - Offset: 0x0000000000000028 + Symbol: var + Type: R_AARCH64_TLSDESC_CALL + - Name: .data + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x0000000000000004 + Content: '' + - Name: .bss + Type: SHT_NOBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x0000000000000004 + Content: '' + - Name: .note.GNU-stack + Type: SHT_PROGBITS + AddressAlign: 0x0000000000000001 + Content: '' +Symbols: + Local: + - Name: '$x.0' + Section: .text + Global: + - Name: foo + - Name: main + Type: STT_FUNC + Section: .text + Size: 0x0000000000000044 + - Name: var + Type: STT_TLS