diff options
-rw-r--r-- | lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp | 37 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h | 6 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp | 67 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp | 3 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h | 20 | ||||
-rw-r--r-- | lld/test/elf/ARM/rel-tls-ie32.test | 109 | ||||
-rw-r--r-- | lld/test/elf/ARM/rel-tls-le32.test | 61 |
7 files changed, 298 insertions, 5 deletions
diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp b/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp index 04ab7ab8327..d24fdf0fa41 100644 --- a/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp +++ b/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp @@ -82,6 +82,8 @@ static Reference::Addend readAddend(const uint8_t *location, 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 @@ static void relocR_ARM_THM_MOVT_ABS(uint8_t *location, uint64_t P, uint64_t S, 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 @@ std::error_code ARMTargetRelocationHandler::applyRelocation( 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(); } diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h b/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h index 2f43b852280..227d68617bf 100644 --- a/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h +++ b/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h @@ -21,9 +21,15 @@ template <class ELFT> class ARMTargetLayout; class ARMTargetRelocationHandler final : public TargetRelocationHandler { public: + ARMTargetRelocationHandler(ARMTargetLayout<ARMELFType> &layout) + : _armLayout(layout) {} + std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &, const lld::AtomLayout &, const Reference &) const override; + +private: + ARMTargetLayout<ARMELFType> &_armLayout; }; } // end namespace elf diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp b/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp index 9cfae6b51af..27ec66ac555 100644 --- a/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp +++ b/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp @@ -28,11 +28,10 @@ using namespace lld; 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 // <target_symbol_address> }; @@ -40,12 +39,16 @@ const uint8_t Veneer_ARM_B_BL_StaticAtomContent[8] = { // 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 <target_symbol_address> }; +// .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 @@ public: } }; +/// \brief Atoms that are used by ARM dynamic linking +class ARMGOTAtom : public GOTAtom { +public: + ARMGOTAtom(const File &f, StringRef secName) : GOTAtom(f, secName) {} + + ArrayRef<uint8_t> 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 @@ template <class Derived> class ARMRelocationPass : public Pass { case R_ARM_THM_JUMP24: static_cast<Derived *>(this)->handleVeneer(atom, ref); break; + case R_ARM_TLS_IE32: + static_cast<Derived *>(this)->handleTLSIE32(ref); + break; } } @@ -136,7 +154,7 @@ protected: 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<DefinedAtom>(ref.target()); + const auto *target = dyn_cast<DefinedAtom>(ref.target()); if (!target || target->codeModel() == atom.codeModel()) return std::error_code(); @@ -183,6 +201,32 @@ protected: return std::error_code(); } + std::error_code handleTLSIE32(const Reference &ref) { + if (const auto *target = dyn_cast<DefinedAtom>(ref.target())) { + const_cast<Reference &>(ref).setTarget( + static_cast<Derived *>(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 <Reference::KindValue R_ARM_TLS, Reference::Addend A = 0> + 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 @@ public: // 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 @@ protected: ELFPassFile _file; const ELFLinkingContext &_ctx; + /// \brief Map Atoms to their GOT entries. + llvm::DenseMap<const Atom *, GOTAtom *> _gotMap; + /// \brief Map Atoms to their veneers. llvm::DenseMap<const Atom *, VeneerAtom *> _veneerMap; + /// \brief the list of GOT/PLT atoms + std::vector<GOTAtom *> _gotVector; + /// \brief the list of veneer atoms. std::vector<VeneerAtom *> _veneerVector; }; @@ -297,6 +351,11 @@ public: _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<R_ARM_TLS_LE32>(da); + } }; } // end of anon namespace diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp b/lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp index 5a2f32aa00e..de90f490f62 100644 --- a/lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp +++ b/lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp @@ -18,7 +18,8 @@ using namespace elf; ARMTargetHandler::ARMTargetHandler(ARMLinkingContext &context) : _context(context), _armTargetLayout( new ARMTargetLayout<ARMELFType>(context)), - _armRelocationHandler(new ARMTargetRelocationHandler()) {} + _armRelocationHandler(new ARMTargetRelocationHandler( + *_armTargetLayout.get())) {} void ARMTargetHandler::registerRelocationNames(Registry ®istry) { registry.addKindTable(Reference::KindNamespace::ELF, Reference::KindArch::ARM, diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h b/lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h index 223f27d2cc9..10641954da2 100644 --- a/lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h +++ b/lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h @@ -29,6 +29,26 @@ template <class ELFT> class ARMTargetLayout : public TargetLayout<ELFT> { public: ARMTargetLayout(ARMLinkingContext &context) : TargetLayout<ELFT>(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<uint64_t> _tpOff; }; class ARMTargetHandler final : public DefaultTargetHandler<ARMELFType> { diff --git a/lld/test/elf/ARM/rel-tls-ie32.test b/lld/test/elf/ARM/rel-tls-ie32.test new file mode 100644 index 00000000000..7b65c2f194c --- /dev/null +++ b/lld/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 +... diff --git a/lld/test/elf/ARM/rel-tls-le32.test b/lld/test/elf/ARM/rel-tls-le32.test new file mode 100644 index 00000000000..d0d3d5b6821 --- /dev/null +++ b/lld/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 +... |