Index: lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h =================================================================== --- lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h +++ lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h @@ -21,9 +21,15 @@ class ARMTargetRelocationHandler final : public TargetRelocationHandler { public: + ARMTargetRelocationHandler(ARMTargetLayout &layout) + : _armLayout(layout) {} + std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &, const lld::AtomLayout &, const Reference &) const override; + +private: + ARMTargetLayout &_armLayout; }; } // end namespace elf Index: lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp =================================================================== --- lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp +++ lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp @@ -82,6 +82,8 @@ switch (kindValue) { case R_ARM_ABS32: case R_ARM_REL32: + case R_ARM_TLS_IE32: + case R_ARM_TLS_LE32: return (int32_t)read32le(location); case R_ARM_PREL31: return (int32_t)(read32le(location) & 0x7FFFFFFF); @@ -382,6 +384,34 @@ return relocR_ARM_THM_MOV(location, arg); } +/// \brief R_ARM_TLS_IE32 - GOT(S) + A - P => S + A - P +static void relocR_ARM_TLS_IE32(uint8_t *location, uint64_t P, uint64_t S, + int64_t A) { + uint32_t result = (uint32_t)(S + A - P); + + DEBUG_WITH_TYPE( + "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; + llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); + llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); + llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); + llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); + applyArmReloc(location, result); +} + +/// \brief R_ARM_TLS_LE32 - S + A - tp => S + A + tpoff +static void relocR_ARM_TLS_LE32(uint8_t *location, uint64_t P, uint64_t S, + int64_t A, uint64_t tpoff) { + uint32_t result = (uint32_t)(S + A + tpoff); + + DEBUG_WITH_TYPE( + "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; + llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); + llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); + llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); + llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); + applyArmReloc(location, result); +} + std::error_code ARMTargetRelocationHandler::applyRelocation( ELFWriter &writer, llvm::FileOutputBuffer &buf, const lld::AtomLayout &atom, const Reference &ref) const { @@ -455,6 +485,13 @@ relocR_ARM_PREL31(location, relocVAddress, targetVAddress, addend, addressesThumb); break; + case R_ARM_TLS_IE32: + relocR_ARM_TLS_IE32(location, relocVAddress, targetVAddress, addend); + break; + case R_ARM_TLS_LE32: + relocR_ARM_TLS_LE32(location, relocVAddress, targetVAddress, addend, + _armLayout.getTPOffset()); + break; default: return make_unhandled_reloc_error(); } Index: lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp =================================================================== --- lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp +++ lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp @@ -28,11 +28,10 @@ using namespace lld::elf; using namespace llvm::ELF; -namespace { // ARM B/BL instructions of static relocation veneer. // TODO: consider different instruction set for archs below ARMv5 // (one as for Thumb may be used though it's less optimal). -const uint8_t Veneer_ARM_B_BL_StaticAtomContent[8] = { +static const uint8_t Veneer_ARM_B_BL_StaticAtomContent[8] = { 0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc, #-4] 0x00, 0x00, 0x00, 0x00 // }; @@ -40,12 +39,16 @@ // Thumb B/BL instructions of static relocation veneer. // TODO: consider different instruction set for archs above ARMv5 // (one as for ARM may be used since it's more optimal). -const uint8_t Veneer_THM_B_BL_StaticAtomContent[8] = { +static const uint8_t Veneer_THM_B_BL_StaticAtomContent[8] = { 0x78, 0x47, // bx pc 0x00, 0x00, // nop 0xfe, 0xff, 0xff, 0xea // b }; +// .got values +static const uint8_t ARMGotAtomContent[4] = {0}; + +namespace { /// \brief Atoms that hold veneer code. class VeneerAtom : public SimpleELFDefinedAtom { StringRef _section; @@ -104,6 +107,18 @@ } }; +/// \brief Atoms that are used by ARM dynamic linking +class ARMGOTAtom : public GOTAtom { +public: + ARMGOTAtom(const File &f, StringRef secName) : GOTAtom(f, secName) {} + + ArrayRef rawContent() const override { + return llvm::makeArrayRef(ARMGotAtomContent); + } + + Alignment alignment() const override { return Alignment(2); } +}; + class ELFPassFile : public SimpleFile { public: ELFPassFile(const ELFLinkingContext &eti) : SimpleFile("ELFPassFile") { @@ -129,6 +144,9 @@ case R_ARM_THM_JUMP24: static_cast(this)->handleVeneer(atom, ref); break; + case R_ARM_TLS_IE32: + static_cast(this)->handleTLSIE32(ref); + break; } } @@ -136,7 +154,7 @@ std::error_code handleVeneer(const DefinedAtom &atom, const Reference &ref) { // Target symbol and relocated place should have different // instruction sets in order a veneer to be generated in between. - const auto *target = dyn_cast_or_null(ref.target()); + const auto *target = dyn_cast(ref.target()); if (!target || target->codeModel() == atom.codeModel()) return std::error_code(); @@ -183,6 +201,32 @@ return std::error_code(); } + std::error_code handleTLSIE32(const Reference &ref) { + if (const auto *target = dyn_cast(ref.target())) { + const_cast(ref).setTarget( + static_cast(this)->getTLSTPOFF32(target)); + return std::error_code(); + } + llvm_unreachable("R_ARM_TLS_IE32 reloc targets wrong atom type"); + } + + /// \brief Create a GOT entry for TLS with reloc type and addend specified. + template + const GOTAtom *getGOTTLSEntry(const DefinedAtom *da) { + auto got = _gotMap.find(da); + if (got != _gotMap.end()) + return got->second; + auto g = new (_file._alloc) ARMGOTAtom(_file, ".got"); + g->addReferenceELF_ARM(R_ARM_TLS, 0, da, A); +#ifndef NDEBUG + g->_name = "__got_tls_"; + g->_name += da->name(); +#endif + _gotMap[da] = g; + _gotVector.push_back(g); + return g; + } + public: ARMRelocationPass(const ELFLinkingContext &ctx) : _file(ctx), _ctx(ctx) {} @@ -230,6 +274,10 @@ // Add all created atoms to the link. uint64_t ordinal = 0; + for (auto &got : _gotVector) { + got->setOrdinal(ordinal++); + mf->addAtom(*got); + } for (auto &veneer : _veneerVector) { veneer->setOrdinal(ordinal++); mf->addAtom(*veneer); @@ -241,9 +289,15 @@ ELFPassFile _file; const ELFLinkingContext &_ctx; + /// \brief Map Atoms to their GOT entries. + llvm::DenseMap _gotMap; + /// \brief Map Atoms to their veneers. llvm::DenseMap _veneerMap; + /// \brief the list of GOT/PLT atoms + std::vector _gotVector; + /// \brief the list of veneer atoms. std::vector _veneerVector; }; @@ -297,6 +351,11 @@ _veneerVector.push_back(v); return v; } + + /// \brief Create a GOT entry for R_ARM_TLS_TPOFF32 reloc. + const GOTAtom *getTLSTPOFF32(const DefinedAtom *da) { + return getGOTTLSEntry(da); + } }; } // end of anon namespace Index: lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h =================================================================== --- lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h +++ lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h @@ -29,6 +29,26 @@ public: ARMTargetLayout(ARMLinkingContext &context) : TargetLayout(context) {} + + uint64_t getTPOffset() { + if (_tpOff.hasValue()) + return *_tpOff; + + for (const auto &phdr : *this->_programHeader) { + if (phdr->p_type == llvm::ELF::PT_TLS) { + _tpOff = llvm::RoundUpToAlignment(TCB_SIZE, phdr->p_align); + return *_tpOff; + } + } + llvm_unreachable("TLS segment not found"); + } + +private: + // TCB block size of the TLS. + enum { TCB_SIZE = 0x8 }; + + // Cached value of the TLS offset from the $tp pointer. + llvm::Optional _tpOff; }; class ARMTargetHandler final : public DefaultTargetHandler { Index: lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp =================================================================== --- lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp +++ lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp @@ -18,7 +18,8 @@ ARMTargetHandler::ARMTargetHandler(ARMLinkingContext &context) : _context(context), _armTargetLayout( new ARMTargetLayout(context)), - _armRelocationHandler(new ARMTargetRelocationHandler()) {} + _armRelocationHandler(new ARMTargetRelocationHandler( + *_armTargetLayout.get())) {} void ARMTargetHandler::registerRelocationNames(Registry ®istry) { registry.addKindTable(Reference::KindNamespace::ELF, Reference::KindArch::ARM, Index: test/elf/ARM/rel-tls-ie32.test =================================================================== --- /dev/null +++ test/elf/ARM/rel-tls-ie32.test @@ -0,0 +1,109 @@ +# Check handling of R_ARM_TLS_IE32 relocation. +# RUN: yaml2obj -format=elf -docnum 1 %s > %t-tls.o +# RUN: yaml2obj -format=elf -docnum 2 %s > %t-tlsv.o +# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \ +# RUN: --noinhibit-exec %t-tls.o %t-tlsv.o -o %t +# RUN: llvm-objdump -s -t %t | FileCheck %s + +# CHECK: Contents of section .got: +# CHECK: 401008 08000000 0c000000 +# tp_off(i) = 0x08 ^^ ^^ tp_off(j) = 0x0c +# tp_off(i) + sizeof(i) = tp_off(j) +# 0x08 + 0x04 = 0x0c +# CHECK: SYMBOL TABLE: +# CHECK: 00400094 g F .text {{[0-9a-f]+}} main +# CHECK: 00000000 g .tdata 00000004 i +# sizeof(i) = 0x04 ^^ +# CHECK: 00000004 g .tdata 00000004 j + +# tls.o +--- +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_ARM + Flags: [ EF_ARM_EABI_VER5 ] +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x0000000000000004 + Content: 80B400AF0C4B7B441B681DEE702FD2580A4B7B441B681DEE701FCB581A44084B7B441B681DEE701FCB585B0013441846BD465DF8047B70472E000000260000001C000000 + - Name: .rel.text + Type: SHT_REL + Link: .symtab + AddressAlign: 0x0000000000000004 + Info: .text + Relocations: + - Offset: 0x0000000000000038 + Symbol: i + Type: R_ARM_TLS_IE32 + - Offset: 0x000000000000003C + Symbol: i + Type: R_ARM_TLS_IE32 + - Offset: 0x0000000000000040 + Symbol: j + Type: R_ARM_TLS_IE32 + - Name: .data + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x0000000000000001 + Content: '' + - Name: .bss + Type: SHT_NOBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x0000000000000001 + Content: '' +Symbols: + Global: + - Name: main + Type: STT_FUNC + Section: .text + Value: 0x0000000000000001 + - Name: i + Type: STT_TLS + - Name: j + Type: STT_TLS + +# tlsv.o +--- +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_ARM + Flags: [ EF_ARM_EABI_VER5 ] +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x0000000000000001 + Content: '' + - Name: .data + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x0000000000000001 + Content: '' + - Name: .bss + Type: SHT_NOBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x0000000000000001 + Content: '' + - Name: .tdata + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ] + AddressAlign: 0x0000000000000004 + Content: 05000000FBFFFFFF +Symbols: + Global: + - Name: i + Type: STT_TLS + Section: .tdata + Size: 0x0000000000000004 + - Name: j + Type: STT_TLS + Section: .tdata + Value: 0x0000000000000004 + Size: 0x0000000000000004 +... Index: test/elf/ARM/rel-tls-le32.test =================================================================== --- /dev/null +++ test/elf/ARM/rel-tls-le32.test @@ -0,0 +1,61 @@ +# Check handling of R_ARM_TLS_LE32 relocation. +# RUN: yaml2obj -format=elf %s > %t-o.o +# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \ +# RUN: --noinhibit-exec %t-o.o -o %t +# RUN: llvm-objdump -s -t %t | FileCheck %s + +# CHECK: Contents of section .text: +# CHECK: 4000b4 {{[0-9a-f]+}} 08000000 +# tp_off = 0x000008 ^^ +# CHECK: SYMBOL TABLE: +# CHECK: 00400094 g F .text {{[0-9a-f]+}} main +# CHECK: 00000000 g .tdata 00000004 i + +--- +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_ARM + Flags: [ EF_ARM_EABI_VER5 ] +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x0000000000000004 + Content: 04B02DE500B08DE2703F1DEE10209FE5023093E70300A0E100D04BE204B09DE41EFF2FE100000000 + - Name: .rel.text + Type: SHT_REL + Link: .symtab + AddressAlign: 0x0000000000000004 + Info: .text + Relocations: + - Offset: 0x0000000000000024 + Symbol: i + Type: R_ARM_TLS_LE32 + Addend: 0 + - Name: .data + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x0000000000000001 + Content: '' + - Name: .bss + Type: SHT_NOBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x0000000000000001 + Content: '' + - Name: .tdata + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ] + AddressAlign: 0x0000000000000004 + Content: '05000000' +Symbols: + Global: + - Name: i + Type: STT_TLS + Section: .tdata + Size: 0x0000000000000004 + - Name: main + Type: STT_FUNC + Section: .text +...