diff options
Diffstat (limited to 'lld/lib/ReaderWriter/ELF/ARM')
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/ARM/ARMDynamicLibraryWriter.h | 49 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/ARM/ARMELFFile.h | 154 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/ARM/ARMELFWriters.h | 120 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h | 68 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp | 64 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h | 80 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp | 680 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h | 35 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp | 986 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h | 31 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h | 59 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp | 32 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h | 174 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/ARM/CMakeLists.txt | 12 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/ARM/TODO.rst | 21 |
15 files changed, 0 insertions, 2565 deletions
diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMDynamicLibraryWriter.h b/lld/lib/ReaderWriter/ELF/ARM/ARMDynamicLibraryWriter.h deleted file mode 100644 index da843b97abc..00000000000 --- a/lld/lib/ReaderWriter/ELF/ARM/ARMDynamicLibraryWriter.h +++ /dev/null @@ -1,49 +0,0 @@ -//===- lib/ReaderWriter/ELF/ARM/ARMDynamicLibraryWriter.h -----------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef LLD_READER_WRITER_ELF_ARM_ARM_DYNAMIC_LIBRARY_WRITER_H -#define LLD_READER_WRITER_ELF_ARM_ARM_DYNAMIC_LIBRARY_WRITER_H - -#include "DynamicLibraryWriter.h" -#include "ARMELFWriters.h" -#include "ARMLinkingContext.h" -#include "ARMTargetHandler.h" - -namespace lld { -namespace elf { - -class ARMDynamicLibraryWriter - : public ARMELFWriter<DynamicLibraryWriter<ELF32LE>> { -public: - ARMDynamicLibraryWriter(ARMLinkingContext &ctx, ARMTargetLayout &layout); - -protected: - // Add any runtime files and their atoms to the output - void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override; - -private: - ARMLinkingContext &_ctx; -}; - -ARMDynamicLibraryWriter::ARMDynamicLibraryWriter(ARMLinkingContext &ctx, - ARMTargetLayout &layout) - : ARMELFWriter(ctx, layout), _ctx(ctx) {} - -void ARMDynamicLibraryWriter::createImplicitFiles( - std::vector<std::unique_ptr<File>> &result) { - DynamicLibraryWriter::createImplicitFiles(result); - auto file = llvm::make_unique<RuntimeFile<ELF32LE>>(_ctx, "ARM dynamic file"); - file->addAbsoluteAtom(gotSymbol); - file->addAbsoluteAtom(dynamicSymbol); - result.push_back(std::move(file)); -} - -} // namespace elf -} // namespace lld - -#endif // LLD_READER_WRITER_ELF_ARM_ARM_DYNAMIC_LIBRARY_WRITER_H diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMELFFile.h b/lld/lib/ReaderWriter/ELF/ARM/ARMELFFile.h deleted file mode 100644 index 8f5477017e5..00000000000 --- a/lld/lib/ReaderWriter/ELF/ARM/ARMELFFile.h +++ /dev/null @@ -1,154 +0,0 @@ -//===--------- lib/ReaderWriter/ELF/ARM/ARMELFFile.h ----------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_ARM_ARM_ELF_FILE_H -#define LLD_READER_WRITER_ELF_ARM_ARM_ELF_FILE_H - -#include "ELFReader.h" - -namespace lld { -namespace elf { - -class ARMLinkingContext; - -class ARMELFBaseDefinedAtom : public ELFDefinedAtom<ELF32LE> { -public: - /// The values of custom content type enum must not interfere - /// with ones in base defined atom class' enum. - enum ARMContentType { - typeARMExidx = 0x1000, // Identifies ARM_EXIDX section - }; - - template <typename... T> - ARMELFBaseDefinedAtom(T &&... args) - : ELFDefinedAtom<ELF32LE>(std::forward<T>(args)...) {} - - DefinedAtom::ContentPermissions permissions() const override { - if (_permissions != DefinedAtom::permUnknown) - return _permissions; - - switch (_section->sh_type) { - case llvm::ELF::SHT_ARM_EXIDX: - return _permissions = permR__; - } - return ELFDefinedAtom::permissions(); - } - - DefinedAtom::ContentType contentType() const override { - if (_contentType != DefinedAtom::typeUnknown) - return _contentType; - - switch (_section->sh_type) { - case llvm::ELF::SHT_ARM_EXIDX: - return _contentType = (DefinedAtom::ContentType)typeARMExidx; - } - return ELFDefinedAtom::contentType(); - } -}; - -class ARMELFMappingAtom : public ARMELFBaseDefinedAtom { -public: - template <typename... T> - ARMELFMappingAtom(DefinedAtom::CodeModel model, T &&... args) - : ARMELFBaseDefinedAtom(std::forward<T>(args)...), _model(model) {} - - DefinedAtom::CodeModel codeModel() const override { return _model; } - -private: - DefinedAtom::CodeModel _model; -}; - -class ARMELFDefinedAtom : public ARMELFBaseDefinedAtom { -public: - template <typename... T> - ARMELFDefinedAtom(T &&... args) - : ARMELFBaseDefinedAtom(std::forward<T>(args)...) {} - - bool isThumbFunc() const { - const auto *symbol = _symbol; - return symbol->getType() == llvm::ELF::STT_FUNC && - (static_cast<uint64_t>(symbol->st_value) & 0x1); - } - - /// Correct st_value for symbols addressing Thumb instructions - /// by removing its zero bit. - uint64_t getSymbolValue() const override { - const auto value = static_cast<uint64_t>(_symbol->st_value); - return isThumbFunc() ? value & ~0x1 : value; - } - - DefinedAtom::CodeModel codeModel() const override { - return isThumbFunc() ? DefinedAtom::codeARMThumb : DefinedAtom::codeNA; - } -}; - -class ARMELFFile : public ELFFile<ELF32LE> { - typedef llvm::object::Elf_Rel_Impl<ELF32LE, false> Elf_Rel; - -public: - ARMELFFile(std::unique_ptr<MemoryBuffer> mb, ELFLinkingContext &ctx) - : ELFFile(std::move(mb), ctx) {} - -protected: - /// Returns initial addend; for ARM it is 0, because it is read - /// during the relocations applying - Reference::Addend getInitialAddend(ArrayRef<uint8_t>, uint64_t, - const Elf_Rel &) const override { - return 0; - } - -private: - typedef llvm::object::Elf_Sym_Impl<ELF32LE> Elf_Sym; - typedef llvm::object::Elf_Shdr_Impl<ELF32LE> Elf_Shdr; - - /// Correct st_value for symbols addressing Thumb instructions - /// by removing its zero bit. - uint64_t getSymbolValue(const Elf_Sym *symbol) const override { - const auto value = static_cast<uint64_t>(symbol->st_value); - return symbol->getType() == llvm::ELF::STT_FUNC ? value & ~0x1 : value; - } - - /// Process the Defined symbol and create an atom for it. - ELFDefinedAtom<ELF32LE> *createDefinedAtom( - StringRef symName, StringRef sectionName, const Elf_Sym *sym, - const Elf_Shdr *sectionHdr, ArrayRef<uint8_t> contentData, - unsigned int referenceStart, unsigned int referenceEnd, - std::vector<ELFReference<ELF32LE> *> &referenceList) override { - if (symName.size() >= 2 && symName[0] == '$') { - switch (symName[1]) { - case 'a': - return new (_readerStorage) - ARMELFMappingAtom(DefinedAtom::codeARM_a, *this, symName, - sectionName, sym, sectionHdr, contentData, - referenceStart, referenceEnd, referenceList); - case 'd': - return new (_readerStorage) - ARMELFMappingAtom(DefinedAtom::codeARM_d, *this, symName, - sectionName, sym, sectionHdr, contentData, - referenceStart, referenceEnd, referenceList); - case 't': - return new (_readerStorage) - ARMELFMappingAtom(DefinedAtom::codeARM_t, *this, symName, - sectionName, sym, sectionHdr, contentData, - referenceStart, referenceEnd, referenceList); - default: - // Fall through and create regular defined atom. - break; - } - } - return new (_readerStorage) ARMELFDefinedAtom( - *this, symName, sectionName, sym, sectionHdr, contentData, - referenceStart, referenceEnd, referenceList); - } -}; - -} // elf -} // lld - -#endif // LLD_READER_WRITER_ELF_ARM_ARM_ELF_FILE_H diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMELFWriters.h b/lld/lib/ReaderWriter/ELF/ARM/ARMELFWriters.h deleted file mode 100644 index a842ebe5303..00000000000 --- a/lld/lib/ReaderWriter/ELF/ARM/ARMELFWriters.h +++ /dev/null @@ -1,120 +0,0 @@ -//===- lib/ReaderWriter/ELF/ARM/ARMELFWriters.h ---------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef LLD_READER_WRITER_ELF_ARM_ARM_ELF_WRITERS_H -#define LLD_READER_WRITER_ELF_ARM_ARM_ELF_WRITERS_H - -#include "ARMLinkingContext.h" -#include "ARMSymbolTable.h" -#include "llvm/Support/ELF.h" - -namespace lld { -namespace elf { - -template <class WriterT> class ARMELFWriter : public WriterT { -public: - ARMELFWriter(ARMLinkingContext &ctx, TargetLayout<ELF32LE> &layout); - - void finalizeDefaultAtomValues() override; - - /// \brief Create symbol table. - unique_bump_ptr<SymbolTable<ELF32LE>> createSymbolTable() override; - - // Setup the ELF header. - std::error_code setELFHeader() override; - -protected: - static const char *gotSymbol; - static const char *dynamicSymbol; - -private: - ARMLinkingContext &_ctx; - TargetLayout<ELF32LE> &_armLayout; -}; - -template <class WriterT> -const char *ARMELFWriter<WriterT>::gotSymbol = "_GLOBAL_OFFSET_TABLE_"; -template <class WriterT> -const char *ARMELFWriter<WriterT>::dynamicSymbol = "_DYNAMIC"; - -template <class WriterT> -ARMELFWriter<WriterT>::ARMELFWriter(ARMLinkingContext &ctx, - TargetLayout<ELF32LE> &layout) - : WriterT(ctx, layout), _ctx(ctx), _armLayout(layout) {} - -template <class WriterT> -void ARMELFWriter<WriterT>::finalizeDefaultAtomValues() { - // Finalize the atom values that are part of the parent. - WriterT::finalizeDefaultAtomValues(); - - if (auto *gotAtom = _armLayout.findAbsoluteAtom(gotSymbol)) { - if (auto gotpltSection = _armLayout.findOutputSection(".got.plt")) - gotAtom->_virtualAddr = gotpltSection->virtualAddr(); - else if (auto gotSection = _armLayout.findOutputSection(".got")) - gotAtom->_virtualAddr = gotSection->virtualAddr(); - else - gotAtom->_virtualAddr = 0; - } - - if (auto *dynamicAtom = _armLayout.findAbsoluteAtom(dynamicSymbol)) { - if (auto dynamicSection = _armLayout.findOutputSection(".dynamic")) - dynamicAtom->_virtualAddr = dynamicSection->virtualAddr(); - else - dynamicAtom->_virtualAddr = 0; - } - - // Set required by gcc libc __ehdr_start symbol with pointer to ELF header - if (auto ehdr = _armLayout.findAbsoluteAtom("__ehdr_start")) - ehdr->_virtualAddr = this->_elfHeader->virtualAddr(); - - // Set required by gcc libc symbols __exidx_start/__exidx_end - this->updateScopeAtomValues("exidx", ".ARM.exidx"); -} - -template <class WriterT> -unique_bump_ptr<SymbolTable<ELF32LE>> -ARMELFWriter<WriterT>::createSymbolTable() { - return unique_bump_ptr<SymbolTable<ELF32LE>>(new (this->_alloc) - ARMSymbolTable(_ctx)); -} - -template <class WriterT> std::error_code ARMELFWriter<WriterT>::setELFHeader() { - if (std::error_code ec = WriterT::setELFHeader()) - return ec; - - // Set ARM-specific flags. - this->_elfHeader->e_flags(llvm::ELF::EF_ARM_EABI_VER5 | - llvm::ELF::EF_ARM_VFP_FLOAT); - - StringRef entryName = _ctx.entrySymbolName(); - if (const AtomLayout *al = _armLayout.findAtomLayoutByName(entryName)) { - if (const auto *ea = dyn_cast<DefinedAtom>(al->_atom)) { - switch (ea->codeModel()) { - case DefinedAtom::codeNA: - if (al->_virtualAddr & 0x3) { - llvm::report_fatal_error( - "Two least bits must be zero for ARM entry point"); - } - break; - case DefinedAtom::codeARMThumb: - // Fixup entry point for Thumb code. - this->_elfHeader->e_entry(al->_virtualAddr | 0x1); - break; - default: - llvm_unreachable("Wrong code model of entry point atom"); - } - } - } - - return std::error_code(); -} - -} // namespace elf -} // namespace lld - -#endif // LLD_READER_WRITER_ELF_ARM_ARM_ELF_WRITERS_H diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h b/lld/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h deleted file mode 100644 index 974dab63a12..00000000000 --- a/lld/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h +++ /dev/null @@ -1,68 +0,0 @@ -//===--------- lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h -------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#ifndef LLD_READER_WRITER_ELF_ARM_ARM_EXECUTABLE_WRITER_H -#define LLD_READER_WRITER_ELF_ARM_ARM_EXECUTABLE_WRITER_H - -#include "ExecutableWriter.h" -#include "ARMELFWriters.h" -#include "ARMLinkingContext.h" -#include "ARMTargetHandler.h" - -namespace lld { -namespace elf { - -class ARMExecutableWriter : public ARMELFWriter<ExecutableWriter<ELF32LE>> { -public: - ARMExecutableWriter(ARMLinkingContext &ctx, ARMTargetLayout &layout); - -protected: - // Add any runtime files and their atoms to the output - void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override; - - void processUndefinedSymbol(StringRef symName, - RuntimeFile<ELF32LE> &file) const override; - -private: - ARMLinkingContext &_ctx; -}; - -ARMExecutableWriter::ARMExecutableWriter(ARMLinkingContext &ctx, - ARMTargetLayout &layout) - : ARMELFWriter(ctx, layout), _ctx(ctx) {} - -void ARMExecutableWriter::createImplicitFiles( - std::vector<std::unique_ptr<File>> &result) { - ExecutableWriter::createImplicitFiles(result); - // Add default atoms for ARM. - if (_ctx.isDynamic()) { - auto file = llvm::make_unique<RuntimeFile<ELF32LE>>(_ctx, "ARM exec file"); - file->addAbsoluteAtom(gotSymbol); - file->addAbsoluteAtom(dynamicSymbol); - result.push_back(std::move(file)); - } -} - -void ARMExecutableWriter::processUndefinedSymbol( - StringRef symName, RuntimeFile<ELF32LE> &file) const { - ARMELFWriter<ExecutableWriter<ELF32LE>>::processUndefinedSymbol(symName, - file); - if (symName == gotSymbol) { - file.addAbsoluteAtom(gotSymbol); - } else if (symName.startswith("__exidx")) { - file.addAbsoluteAtom("__exidx_start"); - file.addAbsoluteAtom("__exidx_end"); - } else if (symName == "__ehdr_start") { - file.addAbsoluteAtom("__ehdr_start"); - } -} - -} // namespace elf -} // namespace lld - -#endif // LLD_READER_WRITER_ELF_ARM_ARM_EXECUTABLE_WRITER_H diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp b/lld/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp deleted file mode 100644 index 74905b47820..00000000000 --- a/lld/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp +++ /dev/null @@ -1,64 +0,0 @@ -//===--------- lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp -------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "ARMLinkingContext.h" -#include "ARMRelocationPass.h" -#include "ARMTargetHandler.h" - -namespace lld { -namespace elf { - -std::unique_ptr<ELFLinkingContext> -createARMLinkingContext(llvm::Triple triple) { - if (triple.getArch() == llvm::Triple::arm) - return llvm::make_unique<ARMLinkingContext>(triple); - return nullptr; -} - -ARMLinkingContext::ARMLinkingContext(llvm::Triple triple) - : ELFLinkingContext(triple, llvm::make_unique<ARMTargetHandler>(*this)) {} - -void ARMLinkingContext::addPasses(PassManager &pm) { - auto pass = createARMRelocationPass(*this); - if (pass) - pm.add(std::move(pass)); - ELFLinkingContext::addPasses(pm); -} - -bool isARMCode(const DefinedAtom *atom) { - return isARMCode(atom->codeModel()); -} - -bool isARMCode(DefinedAtom::CodeModel codeModel) { - return !isThumbCode(codeModel); -} - -bool isThumbCode(const DefinedAtom *atom) { - return isThumbCode(atom->codeModel()); -} - -bool isThumbCode(DefinedAtom::CodeModel codeModel) { - return codeModel == DefinedAtom::codeARMThumb || - codeModel == DefinedAtom::codeARM_t; -} - -static const Registry::KindStrings kindStrings[] = { -#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name), -#include "llvm/Support/ELFRelocs/ARM.def" -#undef ELF_RELOC - LLD_KIND_STRING_END -}; - -void ARMLinkingContext::registerRelocationNames(Registry ®istry) { - registry.addKindTable(Reference::KindNamespace::ELF, Reference::KindArch::ARM, - kindStrings); -} - -} // namespace elf -} // namespace lld diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h b/lld/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h deleted file mode 100644 index f687713b25b..00000000000 --- a/lld/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h +++ /dev/null @@ -1,80 +0,0 @@ -//===--------- lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h ---------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_ARM_ARM_LINKING_CONTEXT_H -#define LLD_READER_WRITER_ELF_ARM_ARM_LINKING_CONTEXT_H - -#include "lld/ReaderWriter/ELFLinkingContext.h" -#include "llvm/Object/ELF.h" -#include "llvm/Support/ELF.h" - -namespace lld { -namespace elf { - -class ARMLinkingContext final : public ELFLinkingContext { -public: - int getMachineType() const override { return llvm::ELF::EM_ARM; } - ARMLinkingContext(llvm::Triple); - - void addPasses(PassManager &) override; - void registerRelocationNames(Registry &r) override; - - bool isRelaOutputFormat() const override { return false; } - - uint64_t getBaseAddress() const override { - if (_baseAddress == 0) - return 0x400000; - return _baseAddress; - } - - bool isDynamicRelocation(const Reference &r) const override { - if (r.kindNamespace() != Reference::KindNamespace::ELF) - return false; - assert(r.kindArch() == Reference::KindArch::ARM); - switch (r.kindValue()) { - case llvm::ELF::R_ARM_GLOB_DAT: - case llvm::ELF::R_ARM_TLS_TPOFF32: - case llvm::ELF::R_ARM_COPY: - return true; - default: - return false; - } - } - - bool isCopyRelocation(const Reference &r) const override { - if (r.kindNamespace() != Reference::KindNamespace::ELF) - return false; - assert(r.kindArch() == Reference::KindArch::ARM); - return r.kindValue() == llvm::ELF::R_ARM_COPY; - } - - bool isPLTRelocation(const Reference &r) const override { - if (r.kindNamespace() != Reference::KindNamespace::ELF) - return false; - assert(r.kindArch() == Reference::KindArch::ARM); - switch (r.kindValue()) { - case llvm::ELF::R_ARM_JUMP_SLOT: - case llvm::ELF::R_ARM_IRELATIVE: - return true; - default: - return false; - } - } -}; - -// Special methods to check code model of atoms. -bool isARMCode(const DefinedAtom *atom); -bool isARMCode(DefinedAtom::CodeModel codeModel); -bool isThumbCode(const DefinedAtom *atom); -bool isThumbCode(DefinedAtom::CodeModel codeModel); - -} // end namespace elf -} // end namespace lld - -#endif diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp b/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp deleted file mode 100644 index 97b149133ff..00000000000 --- a/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp +++ /dev/null @@ -1,680 +0,0 @@ -//===--------- lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp ----------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "ARMTargetHandler.h" -#include "ARMLinkingContext.h" - -#include "llvm/Support/Debug.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/MathExtras.h" - -#define DEBUG_TYPE "ARM" - -using namespace lld; -using namespace lld::elf; -using namespace llvm::support::endian; - -static Reference::Addend readAddend_THM_MOV(const uint8_t *location) { - const uint16_t halfHi = read16le(location); - const uint16_t halfLo = read16le(location + 2); - - const uint16_t imm8 = halfLo & 0xFF; - const uint16_t imm3 = (halfLo >> 12) & 0x7; - - const uint16_t imm4 = halfHi & 0xF; - const uint16_t bitI = (halfHi >> 10) & 0x1; - - const auto result = int16_t((imm4 << 12) | (bitI << 11) | (imm3 << 8) | imm8); - return result; -} - -static Reference::Addend readAddend_ARM_MOV(const uint8_t *location) { - const uint32_t value = read32le(location); - - const uint32_t imm12 = value & 0xFFF; - const uint32_t imm4 = (value >> 16) & 0xF; - - const auto result = int32_t((imm4 << 12) | imm12); - return result; -} - -static Reference::Addend readAddend_THM_CALL(const uint8_t *location) { - const uint16_t halfHi = read16le(location); - const uint16_t halfLo = read16le(location + 2); - - const uint16_t imm10 = halfHi & 0x3FF; - const uint16_t bitS = (halfHi >> 10) & 0x1; - - const uint16_t imm11 = halfLo & 0x7FF; - const uint16_t bitJ2 = (halfLo >> 11) & 0x1; - const uint16_t bitI2 = (~(bitJ2 ^ bitS)) & 0x1; - const uint16_t bitJ1 = (halfLo >> 13) & 0x1; - const uint16_t bitI1 = (~(bitJ1 ^ bitS)) & 0x1; - - const auto result = int32_t((bitS << 24) | (bitI1 << 23) | (bitI2 << 22) | - (imm10 << 12) | (imm11 << 1)); - return llvm::SignExtend64<25>(result); -} - -static Reference::Addend readAddend_ARM_CALL(const uint8_t *location) { - const uint32_t value = read32le(location); - - const bool isBLX = (value & 0xF0000000) == 0xF0000000; - const uint32_t bitH = isBLX ? ((value & 0x1000000) >> 24) : 0; - - const auto result = int32_t(((value & 0xFFFFFF) << 2) | (bitH << 1)); - return llvm::SignExtend64<26>(result); -} - -static Reference::Addend readAddend_THM_JUMP11(const uint8_t *location) { - const auto value = read16le(location); - const uint16_t imm11 = value & 0x7FF; - - return llvm::SignExtend64<12>(imm11 << 1); -} - -static Reference::Addend readAddend(const uint8_t *location, - Reference::KindValue kindValue) { - switch (kindValue) { - case R_ARM_ABS32: - case R_ARM_REL32: - case R_ARM_TARGET1: - case R_ARM_GOT_BREL: - case R_ARM_BASE_PREL: - case R_ARM_TLS_IE32: - case R_ARM_TLS_LE32: - case R_ARM_TLS_TPOFF32: - return (int32_t)read32le(location); - case R_ARM_PREL31: - return llvm::SignExtend64<31>(read32le(location) & 0x7FFFFFFF); - case R_ARM_THM_CALL: - case R_ARM_THM_JUMP24: - return readAddend_THM_CALL(location); - case R_ARM_THM_JUMP11: - return readAddend_THM_JUMP11(location); - case R_ARM_CALL: - case R_ARM_JUMP24: - return readAddend_ARM_CALL(location); - case R_ARM_MOVW_ABS_NC: - case R_ARM_MOVT_ABS: - return readAddend_ARM_MOV(location); - case R_ARM_THM_MOVW_ABS_NC: - case R_ARM_THM_MOVT_ABS: - return readAddend_THM_MOV(location); - default: - return 0; - } -} - -static inline void report_unsupported_range_group_reloc_error() { - llvm::report_fatal_error( - "Negative offsets for group relocations are not implemented"); -} - -static inline std::error_code applyArmReloc(uint8_t *location, uint32_t result, - uint32_t mask = 0xFFFFFFFF) { - assert(!(result & ~mask)); - write32le(location, (read32le(location) & ~mask) | (result & mask)); - return std::error_code(); -} - -static inline std::error_code applyThumb32Reloc(uint8_t *location, - uint16_t resHi, uint16_t resLo, - uint16_t maskHi, - uint16_t maskLo = 0xFFFF) { - assert(!(resHi & ~maskHi) && !(resLo & ~maskLo)); - write16le(location, (read16le(location) & ~maskHi) | (resHi & maskHi)); - location += 2; - write16le(location, (read16le(location) & ~maskLo) | (resLo & maskLo)); - return std::error_code(); -} - -static inline std::error_code -applyThumb16Reloc(uint8_t *location, uint16_t result, uint16_t mask = 0xFFFF) { - assert(!(result & ~mask)); - write16le(location, (read16le(location) & ~mask) | (result & mask)); - return std::error_code(); -} - -/// \brief R_ARM_ABS32 - (S + A) | T -static std::error_code relocR_ARM_ABS32(uint8_t *location, uint64_t P, - uint64_t S, int64_t A, - bool addressesThumb) { - uint64_t T = addressesThumb; - uint32_t result = (uint32_t)((S + A) | T); - - DEBUG(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() << " T: 0x" << Twine::utohexstr(T); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); - return applyArmReloc(location, result); -} - -/// \brief R_ARM_REL32 - ((S + A) | T) - P -static std::error_code relocR_ARM_REL32(uint8_t *location, uint64_t P, - uint64_t S, int64_t A, - bool addressesThumb) { - uint64_t T = addressesThumb; - uint32_t result = (uint32_t)(((S + A) | T) - P); - - DEBUG(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() << " T: 0x" << Twine::utohexstr(T); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); - return applyArmReloc(location, result); -} - -/// \brief R_ARM_PREL31 - ((S + A) | T) - P -static std::error_code relocR_ARM_PREL31(uint8_t *location, uint64_t P, - uint64_t S, int64_t A, - bool addressesThumb) { - uint64_t T = addressesThumb; - uint32_t result = (uint32_t)(((S + A) | T) - P); - if (!llvm::isInt<31>((int32_t)result)) - return make_out_of_range_reloc_error(); - - const uint32_t mask = 0x7FFFFFFF; - uint32_t rel31 = result & mask; - - DEBUG(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() << " T: 0x" << Twine::utohexstr(T); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result); - llvm::dbgs() << " rel31: 0x" << Twine::utohexstr(rel31) << "\n"); - - return applyArmReloc(location, rel31, mask); -} - -/// \brief Relocate B/BL instructions. useJs defines whether J1 & J2 are used -static std::error_code relocR_ARM_THM_B_L(uint8_t *location, uint32_t result, - bool useJs) { - if ((useJs && !llvm::isInt<25>((int32_t)result)) || - (!useJs && !llvm::isInt<23>((int32_t)result))) - return make_out_of_range_reloc_error(); - - result = (result & 0x01FFFFFE) >> 1; - - const uint16_t imm10 = (result >> 11) & 0x3FF; - const uint16_t bitS = (result >> 23) & 0x1; - const uint16_t resHi = (bitS << 10) | imm10; - - const uint16_t imm11 = result & 0x7FF; - const uint16_t bitJ2 = useJs ? ((result >> 21) & 0x1) : bitS; - const uint16_t bitI2 = (~(bitJ2 ^ bitS)) & 0x1; - const uint16_t bitJ1 = useJs ? ((result >> 22) & 0x1) : bitS; - const uint16_t bitI1 = (~(bitJ1 ^ bitS)) & 0x1; - const uint16_t resLo = (bitI1 << 13) | (bitI2 << 11) | imm11; - - return applyThumb32Reloc(location, resHi, resLo, 0x7FF, 0x2FFF); -} - -/// \brief R_ARM_THM_CALL - ((S + A) | T) - P -static std::error_code relocR_ARM_THM_CALL(uint8_t *location, uint64_t P, - uint64_t S, int64_t A, bool useJs, - bool addressesThumb) { - uint64_t T = addressesThumb; - const bool switchMode = !addressesThumb; - - if (switchMode) { - P &= ~0x3; // Align(P, 4) by rounding down - } - - uint32_t result = (uint32_t)(((S + A) | T) - P); - - DEBUG(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() << " T: 0x" << Twine::utohexstr(T); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); - if (auto ec = relocR_ARM_THM_B_L(location, result, useJs)) - return ec; - - if (switchMode) { - return applyThumb32Reloc(location, 0, 0, 0, 0x1001); - } - return std::error_code(); -} - -/// \brief R_ARM_THM_JUMP24 - ((S + A) | T) - P -static std::error_code relocR_ARM_THM_JUMP24(uint8_t *location, uint64_t P, - uint64_t S, int64_t A, - bool addressesThumb) { - uint64_t T = addressesThumb; - uint32_t result = (uint32_t)(((S + A) | T) - P); - - DEBUG(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() << " T: 0x" << Twine::utohexstr(T); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); - return relocR_ARM_THM_B_L(location, result, true); -} - -/// \brief R_ARM_THM_JUMP11 - S + A - P -static std::error_code relocR_ARM_THM_JUMP11(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - uint32_t result = (uint32_t)(S + A - P); - - DEBUG(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"); - - if (!llvm::isInt<12>((int32_t)result)) - return make_out_of_range_reloc_error(); - - // we cut off first bit because it is always 1 according to p. 4.5.3 - result = (result & 0x0FFE) >> 1; - return applyThumb16Reloc(location, result, 0x7FF); -} - -/// \brief R_ARM_BASE_PREL - B(S) + A - P => S + A - P -static std::error_code relocR_ARM_BASE_PREL(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - uint32_t result = (uint32_t)(S + A - P); - DEBUG(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"); - return applyArmReloc(location, result); -} - -/// \brief R_ARM_GOT_BREL - GOT(S) + A - GOT_ORG => S + A - GOT_ORG -static std::error_code relocR_ARM_GOT_BREL(uint8_t *location, uint64_t P, - uint64_t S, int64_t A, - uint64_t GOT_ORG) { - uint32_t result = (uint32_t)(S + A - GOT_ORG); - DEBUG(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"); - return applyArmReloc(location, result); -} - -/// \brief R_ARM_CALL - ((S + A) | T) - P -static std::error_code relocR_ARM_CALL(uint8_t *location, uint64_t P, - uint64_t S, int64_t A, - bool addressesThumb) { - uint64_t T = addressesThumb; - const bool switchMode = addressesThumb; - - uint32_t result = (uint32_t)(((S + A) | T) - P); - if (!llvm::isInt<26>((int32_t)result)) - return make_out_of_range_reloc_error(); - - const uint32_t imm24 = (result & 0x03FFFFFC) >> 2; - - DEBUG(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() << " T: 0x" << Twine::utohexstr(T); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); - if (auto ec = applyArmReloc(location, imm24, 0xFFFFFF)) - return ec; - - if (switchMode) { - const uint32_t bitH = (result & 0x2) >> 1; - return applyArmReloc(location, (0xFA | bitH) << 24, 0xFF000000); - } - return std::error_code(); -} - -/// \brief R_ARM_JUMP24 - ((S + A) | T) - P -static std::error_code relocR_ARM_JUMP24(uint8_t *location, uint64_t P, - uint64_t S, int64_t A, - bool addressesThumb) { - uint64_t T = addressesThumb; - uint32_t result = (uint32_t)(((S + A) | T) - P); - if (!llvm::isInt<26>((int32_t)result)) - return make_out_of_range_reloc_error(); - - const uint32_t imm24 = (result & 0x03FFFFFC) >> 2; - - DEBUG(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() << " T: 0x" << Twine::utohexstr(T); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); - return applyArmReloc(location, imm24, 0xFFFFFF); -} - -/// \brief Relocate ARM MOVW/MOVT instructions -static std::error_code relocR_ARM_MOV(uint8_t *location, uint32_t result) { - const uint32_t imm12 = result & 0xFFF; - const uint32_t imm4 = (result >> 12) & 0xF; - - return applyArmReloc(location, (imm4 << 16) | imm12, 0xF0FFF); -} - -/// \brief R_ARM_MOVW_ABS_NC - (S + A) | T -static std::error_code relocR_ARM_MOVW_ABS_NC(uint8_t *location, uint64_t P, - uint64_t S, int64_t A, - bool addressesThumb) { - uint64_t T = addressesThumb; - uint32_t result = (uint32_t)((S + A) | T); - const uint32_t arg = result & 0x0000FFFF; - - DEBUG(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() << " T: 0x" << Twine::utohexstr(T); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); - return relocR_ARM_MOV(location, arg); -} - -/// \brief R_ARM_MOVT_ABS - S + A -static std::error_code relocR_ARM_MOVT_ABS(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - uint32_t result = (uint32_t)(S + A); - const uint32_t arg = (result & 0xFFFF0000) >> 16; - - DEBUG(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"); - return relocR_ARM_MOV(location, arg); -} - -/// \brief Relocate Thumb MOVW/MOVT instructions -static std::error_code relocR_ARM_THM_MOV(uint8_t *location, uint32_t result) { - const uint16_t imm8 = result & 0xFF; - const uint16_t imm3 = (result >> 8) & 0x7; - const uint16_t resLo = (imm3 << 12) | imm8; - - const uint16_t imm4 = (result >> 12) & 0xF; - const uint16_t bitI = (result >> 11) & 0x1; - const uint16_t resHi = (bitI << 10) | imm4; - - return applyThumb32Reloc(location, resHi, resLo, 0x40F, 0x70FF); -} - -/// \brief R_ARM_THM_MOVW_ABS_NC - (S + A) | T -static std::error_code relocR_ARM_THM_MOVW_ABS_NC(uint8_t *location, uint64_t P, - uint64_t S, int64_t A, - bool addressesThumb) { - uint64_t T = addressesThumb; - uint32_t result = (uint32_t)((S + A) | T); - const uint32_t arg = result & 0x0000FFFF; - - DEBUG(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() << " T: 0x" << Twine::utohexstr(T); - llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); - return relocR_ARM_THM_MOV(location, arg); -} - -/// \brief R_ARM_THM_MOVT_ABS - S + A -static std::error_code relocR_ARM_THM_MOVT_ABS(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - uint32_t result = (uint32_t)(S + A); - const uint32_t arg = (result & 0xFFFF0000) >> 16; - - DEBUG(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"); - return relocR_ARM_THM_MOV(location, arg); -} - -/// \brief R_ARM_TLS_IE32 - GOT(S) + A - P => S + A - P -static std::error_code 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(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"); - return applyArmReloc(location, result); -} - -/// \brief R_ARM_TLS_LE32 - S + A - tp => S + A + tpoff -static std::error_code 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(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"); - return applyArmReloc(location, result); -} - -/// \brief R_ARM_TLS_TPOFF32 - S + A - tp => S + A (offset within TLS block) -static std::error_code relocR_ARM_TLS_TPOFF32(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - uint32_t result = (uint32_t)(S + A); - - DEBUG(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"); - return applyArmReloc(location, result); -} - -template <uint32_t lshift> -static std::error_code relocR_ARM_ALU_PC_GN_NC(uint8_t *location, - uint32_t result) { - static_assert(lshift < 32 && lshift % 2 == 0, - "lshift must be even and less than word size"); - - const uint32_t rshift = 32 - lshift; - result = ((result >> lshift) & 0xFF) | ((rshift / 2) << 8); - - return applyArmReloc(location, result, 0xFFF); -} - -/// \brief R_ARM_ALU_PC_G0_NC - ((S + A) | T) - P => S + A - P -static std::error_code relocR_ARM_ALU_PC_G0_NC(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - int32_t result = (int32_t)(S + A - P); - if (result < 0) - report_unsupported_range_group_reloc_error(); - - DEBUG(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((uint32_t)result) - << "\n"); - - return relocR_ARM_ALU_PC_GN_NC<20>(location, (uint32_t)result); -} - -/// \brief R_ARM_ALU_PC_G1_NC - ((S + A) | T) - P => S + A - P -static std::error_code relocR_ARM_ALU_PC_G1_NC(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - int32_t result = (int32_t)(S + A - P); - if (result < 0) - report_unsupported_range_group_reloc_error(); - - DEBUG(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((uint32_t)result) - << "\n"); - - return relocR_ARM_ALU_PC_GN_NC<12>(location, (uint32_t)result); -} - -/// \brief R_ARM_LDR_PC_G2 - S + A - P -static std::error_code relocR_ARM_LDR_PC_G2(uint8_t *location, uint64_t P, - uint64_t S, int64_t A) { - int32_t result = (int32_t)(S + A - P); - if (result < 0) - report_unsupported_range_group_reloc_error(); - - DEBUG(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((uint32_t)result) - << "\n"); - - const uint32_t mask = 0xFFF; - return applyArmReloc(location, (uint32_t)result & mask, mask); -} - -/// \brief Fixup unresolved weak reference with NOP instruction -static bool fixupUnresolvedWeakCall(uint8_t *location, - Reference::KindValue kindValue) { - // TODO: workaround for archs without NOP instruction - switch (kindValue) { - case R_ARM_THM_CALL: - case R_ARM_THM_JUMP24: - // Thumb32 NOP.W - write32le(location, 0x8000F3AF); - break; - case R_ARM_THM_JUMP11: - // Thumb16 NOP - write16le(location, 0xBF00); - break; - case R_ARM_CALL: - case R_ARM_JUMP24: - // A1 NOP<c>, save condition bits - applyArmReloc(location, 0x320F000, 0xFFFFFFF); - break; - default: - return false; - } - - return true; -} - -std::error_code ARMTargetRelocationHandler::applyRelocation( - ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom, - const Reference &ref) const { - uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset; - uint8_t *loc = atomContent + ref.offsetInAtom(); - uint64_t target = writer.addressOfAtom(ref.target()); - uint64_t reloc = atom._virtualAddr + ref.offsetInAtom(); - - if (ref.kindNamespace() != Reference::KindNamespace::ELF) - return std::error_code(); - assert(ref.kindArch() == Reference::KindArch::ARM); - - // Fixup unresolved weak references - if (!target) { - bool isCallFixed = fixupUnresolvedWeakCall(loc, ref.kindValue()); - - if (isCallFixed) { - DEBUG(llvm::dbgs() << "\t\tFixup unresolved weak reference '"; - llvm::dbgs() << ref.target()->name() << "'"; - llvm::dbgs() << " at address: 0x" << Twine::utohexstr(reloc); - llvm::dbgs() << (isCallFixed ? "\n" : " isn't possible\n")); - return std::error_code(); - } - } - - // Calculate proper initial addend for the relocation - const Reference::Addend addend = - readAddend(loc, ref.kindValue()) + ref.addend(); - - // Flags that the relocation addresses Thumb instruction - bool thumb = false; - if (const auto *definedAtom = dyn_cast<DefinedAtom>(ref.target())) { - thumb = isThumbCode(definedAtom); - } - - switch (ref.kindValue()) { - case R_ARM_NONE: - return std::error_code(); - case R_ARM_ABS32: - return relocR_ARM_ABS32(loc, reloc, target, addend, thumb); - case R_ARM_REL32: - return relocR_ARM_REL32(loc, reloc, target, addend, thumb); - case R_ARM_TARGET1: - if (_armLayout.target1Rel()) - return relocR_ARM_REL32(loc, reloc, target, addend, thumb); - else - return relocR_ARM_ABS32(loc, reloc, target, addend, thumb); - case R_ARM_THM_CALL: - // TODO: consider adding bool variable to disable J1 & J2 for archs - // before ARMv6 - return relocR_ARM_THM_CALL(loc, reloc, target, addend, true, thumb); - case R_ARM_CALL: - return relocR_ARM_CALL(loc, reloc, target, addend, thumb); - case R_ARM_JUMP24: - return relocR_ARM_JUMP24(loc, reloc, target, addend, thumb); - case R_ARM_THM_JUMP24: - return relocR_ARM_THM_JUMP24(loc, reloc, target, addend, thumb); - case R_ARM_THM_JUMP11: - return relocR_ARM_THM_JUMP11(loc, reloc, target, addend); - case R_ARM_MOVW_ABS_NC: - return relocR_ARM_MOVW_ABS_NC(loc, reloc, target, addend, thumb); - case R_ARM_MOVT_ABS: - return relocR_ARM_MOVT_ABS(loc, reloc, target, addend); - case R_ARM_THM_MOVW_ABS_NC: - return relocR_ARM_THM_MOVW_ABS_NC(loc, reloc, target, addend, thumb); - case R_ARM_THM_MOVT_ABS: - return relocR_ARM_THM_MOVT_ABS(loc, reloc, target, addend); - case R_ARM_PREL31: - return relocR_ARM_PREL31(loc, reloc, target, addend, thumb); - case R_ARM_TLS_IE32: - return relocR_ARM_TLS_IE32(loc, reloc, target, addend); - case R_ARM_TLS_LE32: - return relocR_ARM_TLS_LE32(loc, reloc, target, addend, - _armLayout.getTPOffset()); - case R_ARM_TLS_TPOFF32: - return relocR_ARM_TLS_TPOFF32(loc, reloc, target, addend); - case R_ARM_GOT_BREL: - return relocR_ARM_GOT_BREL(loc, reloc, target, addend, - _armLayout.getGOTSymAddr()); - case R_ARM_BASE_PREL: - // GOT origin is used for NULL symbol and when explicitly specified - if (!target || ref.target()->name().equals("_GLOBAL_OFFSET_TABLE_")) { - target = _armLayout.getGOTSymAddr(); - } else { - return make_dynamic_error_code( - "Segment-base relative addressing is not supported"); - } - return relocR_ARM_BASE_PREL(loc, reloc, target, addend); - case R_ARM_ALU_PC_G0_NC: - return relocR_ARM_ALU_PC_G0_NC(loc, reloc, target, addend); - case R_ARM_ALU_PC_G1_NC: - return relocR_ARM_ALU_PC_G1_NC(loc, reloc, target, addend); - case R_ARM_LDR_PC_G2: - return relocR_ARM_LDR_PC_G2(loc, reloc, target, addend); - case R_ARM_JUMP_SLOT: - case R_ARM_GLOB_DAT: - case R_ARM_IRELATIVE: - // Runtime only relocations. Ignore here. - return std::error_code(); - case R_ARM_V4BX: - // TODO implement - return std::error_code(); - default: - return make_unhandled_reloc_error(); - } - - llvm_unreachable("All switch cases must return directly"); -} diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h b/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h deleted file mode 100644 index a1f3d091f20..00000000000 --- a/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h +++ /dev/null @@ -1,35 +0,0 @@ -//===--------- lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h ------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_ARM_ARM_RELOCATION_HANDLER_H -#define LLD_READER_WRITER_ELF_ARM_ARM_RELOCATION_HANDLER_H - -#include "lld/ReaderWriter/ELFLinkingContext.h" - -namespace lld { -namespace elf { - -class ARMTargetLayout; - -class ARMTargetRelocationHandler final : public TargetRelocationHandler { -public: - ARMTargetRelocationHandler(ARMTargetLayout &layout) : _armLayout(layout) {} - - std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &, - const AtomLayout &, - const Reference &) const override; - -private: - ARMTargetLayout &_armLayout; -}; - -} // end namespace elf -} // end namespace lld - -#endif // LLD_READER_WRITER_ELF_ARM_ARM_RELOCATION_HANDLER_H diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp b/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp deleted file mode 100644 index a47f0771c91..00000000000 --- a/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp +++ /dev/null @@ -1,986 +0,0 @@ -//===--------- lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp -------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// \brief Defines the relocation processing pass for ARM. This includes -/// GOT and PLT entries, TLS, COPY, and ifunc. -/// -/// This also includes additional behavior that gnu-ld and gold implement but -/// which is not specified anywhere. -/// -//===----------------------------------------------------------------------===// - -#include "ARMRelocationPass.h" -#include "ARMLinkingContext.h" -#include "Atoms.h" -#include "lld/Core/Simple.h" -#include "llvm/ADT/MapVector.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/Support/Debug.h" - -using namespace lld; -using namespace lld::elf; -using namespace llvm::ELF; - -namespace { -// ARM B/BL instructions of absolute relocation veneer. -// TODO: consider different instruction set for archs below ARMv5 -// (one as for Thumb may be used though it's less optimal). -static const uint8_t Veneer_ARM_B_BL_Abs_a_AtomContent[4] = { - 0x04, 0xf0, 0x1f, 0xe5 // ldr pc, [pc, #-4] -}; -static const uint8_t Veneer_ARM_B_BL_Abs_d_AtomContent[4] = { - 0x00, 0x00, 0x00, 0x00 // <target_symbol_address> -}; - -// Thumb B/BL instructions of absolute relocation veneer. -// TODO: consider different instruction set for archs above ARMv5 -// (one as for ARM may be used since it's more optimal). -static const uint8_t Veneer_THM_B_BL_Abs_t_AtomContent[4] = { - 0x78, 0x47, // bx pc - 0x00, 0x00 // nop -}; -static const uint8_t Veneer_THM_B_BL_Abs_a_AtomContent[4] = { - 0xfe, 0xff, 0xff, 0xea // b <target_symbol_address> -}; - -// .got values -static const uint8_t ARMGotAtomContent[4] = {0}; - -// .plt value (entry 0) -static const uint8_t ARMPlt0_a_AtomContent[16] = { - 0x04, 0xe0, 0x2d, 0xe5, // push {lr} - 0x04, 0xe0, 0x9f, 0xe5, // ldr lr, [pc, #4] - 0x0e, 0xe0, 0x8f, 0xe0, // add lr, pc, lr - 0x00, 0xf0, 0xbe, 0xe5 // ldr pc, [lr, #0]! -}; -static const uint8_t ARMPlt0_d_AtomContent[4] = { - 0x00, 0x00, 0x00, 0x00 // <got1_symbol_address> -}; - -// .plt values (other entries) -static const uint8_t ARMPltAtomContent[12] = { - 0x00, 0xc0, 0x8f, 0xe2, // add ip, pc, #offset[G0] - 0x00, 0xc0, 0x8c, 0xe2, // add ip, ip, #offset[G1] - 0x00, 0xf0, 0xbc, 0xe5 // ldr pc, [ip, #offset[G2]]! -}; - -// Veneer for switching from Thumb to ARM code for PLT entries. -static const uint8_t ARMPltVeneerAtomContent[4] = { - 0x78, 0x47, // bx pc - 0x00, 0x00 // nop -}; - -// Determine proper names for mapping symbols. -static std::string getMappingAtomName(DefinedAtom::CodeModel model, - const std::string &part) { - switch (model) { - case DefinedAtom::codeARM_a: - return part.empty() ? "$a" : "$a." + part; - case DefinedAtom::codeARM_d: - return part.empty() ? "$d" : "$d." + part; - case DefinedAtom::codeARM_t: - return part.empty() ? "$t" : "$t." + part; - default: - llvm_unreachable("Wrong code model of mapping atom"); - } -} - -/// \brief Atoms that hold veneer code. -class VeneerAtom : public SimpleELFDefinedAtom { - StringRef _section; - -public: - VeneerAtom(const File &f, StringRef secName, const std::string &name = "") - : SimpleELFDefinedAtom(f), _section(secName), _name(name) {} - - Scope scope() const override { return DefinedAtom::scopeTranslationUnit; } - - SectionChoice sectionChoice() const override { - return DefinedAtom::sectionBasedOnContent; - } - - StringRef customSectionName() const override { return _section; } - - ContentType contentType() const override { return DefinedAtom::typeCode; } - - uint64_t size() const override { return rawContent().size(); } - - ContentPermissions permissions() const override { return permR_X; } - - Alignment alignment() const override { return 4; } - - StringRef name() const override { return _name; } - -private: - std::string _name; -}; - -/// \brief Atoms that hold veneer for relocated ARM B/BL instructions -/// in absolute code. -class Veneer_ARM_B_BL_Abs_a_Atom : public VeneerAtom { -public: - Veneer_ARM_B_BL_Abs_a_Atom(const File &f, StringRef secName, - const std::string &name) - : VeneerAtom(f, secName, name) {} - - ArrayRef<uint8_t> rawContent() const override { - return llvm::makeArrayRef(Veneer_ARM_B_BL_Abs_a_AtomContent); - } -}; - -class Veneer_ARM_B_BL_Abs_d_Atom : public VeneerAtom { -public: - Veneer_ARM_B_BL_Abs_d_Atom(const File &f, StringRef secName) - : VeneerAtom(f, secName) {} - - ArrayRef<uint8_t> rawContent() const override { - return llvm::makeArrayRef(Veneer_ARM_B_BL_Abs_d_AtomContent); - } -}; - -/// \brief Atoms that hold veneer for relocated Thumb B/BL instructions -/// in absolute code. -class Veneer_THM_B_BL_Abs_t_Atom : public VeneerAtom { -public: - Veneer_THM_B_BL_Abs_t_Atom(const File &f, StringRef secName, - const std::string &name) - : VeneerAtom(f, secName, name) {} - - DefinedAtom::CodeModel codeModel() const override { - return DefinedAtom::codeARMThumb; - } - - ArrayRef<uint8_t> rawContent() const override { - return llvm::makeArrayRef(Veneer_THM_B_BL_Abs_t_AtomContent); - } -}; - -class Veneer_THM_B_BL_Abs_a_Atom : public VeneerAtom { -public: - Veneer_THM_B_BL_Abs_a_Atom(const File &f, StringRef secName) - : VeneerAtom(f, secName) {} - - ArrayRef<uint8_t> rawContent() const override { - return llvm::makeArrayRef(Veneer_THM_B_BL_Abs_a_AtomContent); - } -}; - -template <DefinedAtom::CodeModel Model> -class ARMVeneerMappingAtom : public VeneerAtom { -public: - ARMVeneerMappingAtom(const File &f, StringRef secName, StringRef name) - : VeneerAtom(f, secName, getMappingAtomName(Model, name)) { - static_assert((Model == DefinedAtom::codeARM_a || - Model == DefinedAtom::codeARM_d || - Model == DefinedAtom::codeARM_t), - "Only mapping atom types are allowed"); - } - - uint64_t size() const override { return 0; } - - ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); } - - DefinedAtom::CodeModel codeModel() const override { return Model; } -}; - -template <class BaseAtom, DefinedAtom::CodeModel Model> -class BaseMappingAtom : public BaseAtom { -public: - BaseMappingAtom(const File &f, StringRef secName, StringRef name) - : BaseAtom(f, secName) { - static_assert((Model == DefinedAtom::codeARM_a || - Model == DefinedAtom::codeARM_d || - Model == DefinedAtom::codeARM_t), - "Only mapping atom types are allowed"); -#ifndef NDEBUG - _name = name; -#else - _name = getMappingAtomName(Model, name); -#endif - } - - DefinedAtom::CodeModel codeModel() const override { -#ifndef NDEBUG - return isThumbCode(Model) ? DefinedAtom::codeARMThumb : DefinedAtom::codeNA; -#else - return Model; -#endif - } - - StringRef name() const override { return _name; } - -private: - std::string _name; -}; - -/// \brief Atoms that are used by ARM dynamic linking -class ARMGOTAtom : public GOTAtom { -public: - ARMGOTAtom(const File &f) : GOTAtom(f, ".got") {} - - ArrayRef<uint8_t> rawContent() const override { - return llvm::makeArrayRef(ARMGotAtomContent); - } - - Alignment alignment() const override { return 4; } - -protected: - // Constructor for PLTGOT atom. - ARMGOTAtom(const File &f, StringRef secName) : GOTAtom(f, secName) {} -}; - -class ARMGOTPLTAtom : public ARMGOTAtom { -public: - ARMGOTPLTAtom(const File &f) : ARMGOTAtom(f, ".got.plt") {} -}; - -/// \brief Proxy class to keep type compatibility with PLT0Atom. -class ARMPLT0Atom : public PLT0Atom { -public: - ARMPLT0Atom(const File &f, StringRef) : PLT0Atom(f) {} -}; - -/// \brief PLT0 entry atom. -/// Serves as a mapping symbol in the release mode. -class ARMPLT0_a_Atom - : public BaseMappingAtom<ARMPLT0Atom, DefinedAtom::codeARM_a> { -public: - ARMPLT0_a_Atom(const File &f, const std::string &name) - : BaseMappingAtom(f, ".plt", name) {} - - ArrayRef<uint8_t> rawContent() const override { - return llvm::makeArrayRef(ARMPlt0_a_AtomContent); - } - - Alignment alignment() const override { return 4; } -}; - -class ARMPLT0_d_Atom - : public BaseMappingAtom<ARMPLT0Atom, DefinedAtom::codeARM_d> { -public: - ARMPLT0_d_Atom(const File &f, const std::string &name) - : BaseMappingAtom(f, ".plt", name) {} - - ArrayRef<uint8_t> rawContent() const override { - return llvm::makeArrayRef(ARMPlt0_d_AtomContent); - } - - Alignment alignment() const override { return 4; } -}; - -/// \brief PLT entry atom. -/// Serves as a mapping symbol in the release mode. -class ARMPLTAtom : public BaseMappingAtom<PLTAtom, DefinedAtom::codeARM_a> { -public: - ARMPLTAtom(const File &f, const std::string &name) - : BaseMappingAtom(f, ".plt", name) {} - - ArrayRef<uint8_t> rawContent() const override { - return llvm::makeArrayRef(ARMPltAtomContent); - } - - Alignment alignment() const override { return 4; } -}; - -/// \brief Veneer atom for PLT entry. -/// Serves as a mapping symbol in the release mode. -class ARMPLTVeneerAtom - : public BaseMappingAtom<PLTAtom, DefinedAtom::codeARM_t> { -public: - ARMPLTVeneerAtom(const File &f, const std::string &name) - : BaseMappingAtom(f, ".plt", name) {} - - ArrayRef<uint8_t> rawContent() const override { - return llvm::makeArrayRef(ARMPltVeneerAtomContent); - } - - Alignment alignment() const override { return 4; } -}; - -/// \brief Atom which represents an object for which a COPY relocation will -/// be generated. -class ARMObjectAtom : public ObjectAtom { -public: - ARMObjectAtom(const File &f) : ObjectAtom(f) {} - Alignment alignment() const override { return 4; } -}; - -class ELFPassFile : public SimpleFile { -public: - ELFPassFile(const ELFLinkingContext &eti) - : SimpleFile("ELFPassFile", kindELFObject) { - setOrdinal(eti.getNextOrdinalAndIncrement()); - } - - llvm::BumpPtrAllocator _alloc; -}; - -/// \brief CRTP base for handling relocations. -template <class Derived> class ARMRelocationPass : public Pass { - /// \brief Handle a specific reference. - void handleReference(const DefinedAtom &atom, const Reference &ref) { - DEBUG_WITH_TYPE( - "ARM", llvm::dbgs() << "\t" << LLVM_FUNCTION_NAME << "()" - << ": Name of Defined Atom: " << atom.name().str(); - llvm::dbgs() << " kindValue: " << ref.kindValue() << "\n"); - if (ref.kindNamespace() != Reference::KindNamespace::ELF) - return; - assert(ref.kindArch() == Reference::KindArch::ARM); - switch (ref.kindValue()) { - case R_ARM_ABS32: - case R_ARM_REL32: - case R_ARM_TARGET1: - case R_ARM_MOVW_ABS_NC: - case R_ARM_MOVT_ABS: - case R_ARM_THM_MOVW_ABS_NC: - case R_ARM_THM_MOVT_ABS: - static_cast<Derived *>(this)->handlePlain(isThumbCode(&atom), ref); - break; - case R_ARM_THM_CALL: - case R_ARM_CALL: - case R_ARM_JUMP24: - case R_ARM_THM_JUMP24: - case R_ARM_THM_JUMP11: { - const auto actualModel = actualSourceCodeModel(atom, ref); - const bool fromThumb = isThumbCode(actualModel); - static_cast<Derived *>(this)->handlePlain(fromThumb, ref); - static_cast<Derived *>(this)->handleVeneer(atom, fromThumb, ref); - } break; - case R_ARM_TLS_IE32: - static_cast<Derived *>(this)->handleTLSIE32(ref); - break; - case R_ARM_GOT_BREL: - static_cast<Derived *>(this)->handleGOT(ref); - break; - default: - break; - } - } - -protected: - /// \brief Determine source atom's actual code model. - /// - /// Actual code model may differ from the existing one if fixup - /// is possible on the later stages for given relocation type. - DefinedAtom::CodeModel actualSourceCodeModel(const DefinedAtom &atom, - const Reference &ref) { - const auto kindValue = ref.kindValue(); - if (kindValue != R_ARM_CALL && kindValue != R_ARM_THM_CALL) - return atom.codeModel(); - - // TODO: For unconditional jump instructions (R_ARM_CALL and R_ARM_THM_CALL) - // fixup isn't possible without veneer generation for archs below ARMv5. - - auto actualModel = atom.codeModel(); - if (const auto *da = dyn_cast<DefinedAtom>(ref.target())) { - actualModel = da->codeModel(); - } else if (const auto *sla = dyn_cast<SharedLibraryAtom>(ref.target())) { - if (sla->type() == SharedLibraryAtom::Type::Code) { - // PLT entry will be generated here - assume we don't want a veneer - // on top of it and prefer instruction fixup if needed. - actualModel = DefinedAtom::codeNA; - } - } - return actualModel; - } - - std::error_code handleVeneer(const DefinedAtom &atom, bool fromThumb, - const Reference &ref) { - // Actual instruction mode differs meaning that further fixup will be - // applied. - if (isThumbCode(&atom) != fromThumb) - return std::error_code(); - - const VeneerAtom *(Derived::*getVeneer)(const DefinedAtom *, StringRef) = - nullptr; - const auto kindValue = ref.kindValue(); - switch (kindValue) { - case R_ARM_JUMP24: - getVeneer = &Derived::getVeneer_ARM_B_BL; - break; - case R_ARM_THM_JUMP24: - getVeneer = &Derived::getVeneer_THM_B_BL; - break; - default: - return std::error_code(); - } - - // Target symbol and relocated place should have different - // instruction sets in order a veneer to be generated in between. - const auto *target = dyn_cast<DefinedAtom>(ref.target()); - if (!target || isThumbCode(target) == isThumbCode(&atom)) - return std::error_code(); - - // Veneers may only be generated for STT_FUNC target symbols - // or for symbols located in sections different to the place of relocation. - StringRef secName = atom.customSectionName(); - if (DefinedAtom::typeCode != target->contentType() && - !target->customSectionName().equals(secName)) { - StringRef kindValStr; - if (!this->_ctx.registry().referenceKindToString( - ref.kindNamespace(), ref.kindArch(), kindValue, kindValStr)) { - kindValStr = "unknown"; - } - - std::string errStr = - (Twine("Reference of type ") + Twine(kindValue) + " (" + kindValStr + - ") from " + atom.name() + "+" + Twine(ref.offsetInAtom()) + " to " + - ref.target()->name() + "+" + Twine(ref.addend()) + - " cannot be effected without a veneer").str(); - - llvm_unreachable(errStr.c_str()); - } - - assert(getVeneer && "The veneer handler is missing"); - const Atom *veneer = - (static_cast<Derived *>(this)->*getVeneer)(target, secName); - - assert(veneer && "The veneer is not set"); - const_cast<Reference &>(ref).setTarget(veneer); - return std::error_code(); - } - - /// \brief Get the veneer for ARM B/BL instructions - /// in absolute code. - const VeneerAtom *getVeneer_ARM_B_BL_Abs(const DefinedAtom *da, - StringRef secName) { - auto veneer = _veneerAtoms.lookup(da); - if (!veneer.empty()) - return veneer._veneer; - - std::string name = "__"; - name += da->name(); - name += "_from_arm"; - // Create parts of veneer with mapping symbols. - auto v_a = - new (_file._alloc) Veneer_ARM_B_BL_Abs_a_Atom(_file, secName, name); - addVeneerWithMapping<DefinedAtom::codeARM_a>(da, v_a, name); - auto v_d = new (_file._alloc) Veneer_ARM_B_BL_Abs_d_Atom(_file, secName); - addVeneerWithMapping<DefinedAtom::codeARM_d>(v_a, v_d, name); - - // Fake reference to show connection between parts of veneer. - v_a->addReferenceELF_ARM(R_ARM_NONE, 0, v_d, 0); - // Real reference to fixup. - v_d->addReferenceELF_ARM(R_ARM_ABS32, 0, da, 0); - return v_a; - } - - /// \brief Get the veneer for Thumb B/BL instructions - /// in absolute code. - const VeneerAtom *getVeneer_THM_B_BL_Abs(const DefinedAtom *da, - StringRef secName) { - auto veneer = _veneerAtoms.lookup(da); - if (!veneer.empty()) - return veneer._veneer; - - std::string name = "__"; - name += da->name(); - name += "_from_thumb"; - // Create parts of veneer with mapping symbols. - auto v_t = - new (_file._alloc) Veneer_THM_B_BL_Abs_t_Atom(_file, secName, name); - addVeneerWithMapping<DefinedAtom::codeARM_t>(da, v_t, name); - auto v_a = new (_file._alloc) Veneer_THM_B_BL_Abs_a_Atom(_file, secName); - addVeneerWithMapping<DefinedAtom::codeARM_a>(v_t, v_a, name); - - // Fake reference to show connection between parts of veneer. - v_t->addReferenceELF_ARM(R_ARM_NONE, 0, v_a, 0); - // Real reference to fixup. - v_a->addReferenceELF_ARM(R_ARM_JUMP24, 0, da, 0); - return v_t; - } - - 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) { - StringRef source; -#ifndef NDEBUG - source = "_tls_"; -#endif - return getGOT<R_ARM_TLS, A>(da, source); - } - - /// \brief Add veneer with mapping symbol. - template <DefinedAtom::CodeModel Model> - void addVeneerWithMapping(const DefinedAtom *da, VeneerAtom *va, - const std::string &name) { - assert(_veneerAtoms.lookup(da).empty() && - "Veneer or mapping already exists"); - auto *ma = new (_file._alloc) - ARMVeneerMappingAtom<Model>(_file, va->customSectionName(), name); - - // Fake reference to show connection between the mapping symbol and veneer. - va->addReferenceELF_ARM(R_ARM_NONE, 0, ma, 0); - _veneerAtoms[da] = VeneerWithMapping(va, ma); - } - - /// \brief get a veneer for a PLT entry. - const PLTAtom *getPLTVeneer(const Atom *da, PLTAtom *pa, StringRef source) { - std::string name = "__plt_from_thumb"; - name += source.empty() ? "_" : source; - name += da->name(); - // Create veneer for PLT entry. - auto va = new (_file._alloc) ARMPLTVeneerAtom(_file, name); - // Fake reference to show connection between veneer and PLT entry. - va->addReferenceELF_ARM(R_ARM_NONE, 0, pa, 0); - - _pltAtoms[da] = PLTWithVeneer(pa, va); - return va; - } - - typedef const GOTAtom *(Derived::*GOTFactory)(const Atom *); - - /// \brief get a PLT entry referencing PLTGOT entry. - /// - /// If the entry does not exist, both GOT and PLT entry are created. - const PLTAtom *getPLT(const Atom *da, bool fromThumb, GOTFactory gotFactory, - StringRef source = "") { - auto pltVeneer = _pltAtoms.lookup(da); - if (!pltVeneer.empty()) { - // Return clean PLT entry provided it is ARM code. - if (!fromThumb) - return pltVeneer._plt; - - // Check if veneer is present for Thumb to ARM transition. - if (pltVeneer._veneer) - return pltVeneer._veneer; - - // Create veneer for existing PLT entry. - return getPLTVeneer(da, pltVeneer._plt, source); - } - - // Create specific GOT entry. - const auto *ga = (static_cast<Derived *>(this)->*gotFactory)(da); - assert(_gotpltAtoms.lookup(da) == ga && - "GOT entry should be added to the PLTGOT map"); - assert(ga->customSectionName() == ".got.plt" && - "GOT entry should be in a special section"); - - std::string name = "__plt"; - name += source.empty() ? "_" : source; - name += da->name(); - // Create PLT entry for the GOT entry. - auto pa = new (_file._alloc) ARMPLTAtom(_file, name); - pa->addReferenceELF_ARM(R_ARM_ALU_PC_G0_NC, 0, ga, -8); - pa->addReferenceELF_ARM(R_ARM_ALU_PC_G1_NC, 4, ga, -4); - pa->addReferenceELF_ARM(R_ARM_LDR_PC_G2, 8, ga, 0); - - // Since all PLT entries are in ARM code, Thumb to ARM - // switching should be added if the relocated place contais Thumb code. - if (fromThumb) - return getPLTVeneer(da, pa, source); - - // Otherwise just add PLT entry and return it to the caller. - _pltAtoms[da] = PLTWithVeneer(pa); - return pa; - } - - /// \brief Create the GOT entry for a given IFUNC Atom. - const GOTAtom *createIFUNCGOT(const Atom *da) { - assert(!_gotpltAtoms.lookup(da) && "IFUNC GOT entry already exists"); - auto g = new (_file._alloc) ARMGOTPLTAtom(_file); - g->addReferenceELF_ARM(R_ARM_ABS32, 0, da, 0); - g->addReferenceELF_ARM(R_ARM_IRELATIVE, 0, da, 0); -#ifndef NDEBUG - g->_name = "__got_ifunc_"; - g->_name += da->name(); -#endif - _gotpltAtoms[da] = g; - return g; - } - - /// \brief get the PLT entry for a given IFUNC Atom. - const PLTAtom *getIFUNCPLTEntry(const DefinedAtom *da, bool fromThumb) { - return getPLT(da, fromThumb, &Derived::createIFUNCGOT, "_ifunc_"); - } - - /// \brief Redirect the call to the PLT stub for the target IFUNC. - /// - /// This create a PLT and GOT entry for the IFUNC if one does not exist. The - /// GOT entry and a IRELATIVE relocation to the original target resolver. - std::error_code handleIFUNC(bool fromThumb, const Reference &ref) { - auto target = dyn_cast<const DefinedAtom>(ref.target()); - if (target && target->contentType() == DefinedAtom::typeResolver) { - const_cast<Reference &>(ref) - .setTarget(getIFUNCPLTEntry(target, fromThumb)); - } - return std::error_code(); - } - - /// \brief Create a GOT entry containing 0. - const GOTAtom *getNullGOT() { - if (!_null) { - _null = new (_file._alloc) ARMGOTPLTAtom(_file); -#ifndef NDEBUG - _null->_name = "__got_null"; -#endif - } - return _null; - } - - /// \brief Create regular GOT entry which cannot be used in PLTGOT operation. - template <Reference::KindValue R_ARM_REL, Reference::Addend A = 0> - const GOTAtom *getGOT(const Atom *da, StringRef source = "") { - if (auto got = _gotAtoms.lookup(da)) - return got; - auto g = new (_file._alloc) ARMGOTAtom(_file); - g->addReferenceELF_ARM(R_ARM_REL, 0, da, A); -#ifndef NDEBUG - g->_name = "__got"; - g->_name += source.empty() ? "_" : source; - g->_name += da->name(); -#endif - _gotAtoms[da] = g; - return g; - } - - /// \brief get GOT entry for a regular defined atom. - const GOTAtom *getGOTEntry(const DefinedAtom *da) { - return getGOT<R_ARM_ABS32>(da); - } - - std::error_code handleGOT(const Reference &ref) { - if (isa<UndefinedAtom>(ref.target())) - const_cast<Reference &>(ref).setTarget(getNullGOT()); - else if (const auto *da = dyn_cast<DefinedAtom>(ref.target())) - const_cast<Reference &>(ref).setTarget(getGOTEntry(da)); - return std::error_code(); - } - -public: - ARMRelocationPass(const ELFLinkingContext &ctx) : _file(ctx), _ctx(ctx) {} - - /// \brief Do the pass. - /// - /// The goal here is to first process each reference individually. Each call - /// to handleReference may modify the reference itself and/or create new - /// atoms which must be stored in one of the maps below. - /// - /// After all references are handled, the atoms created during that are all - /// added to mf. - std::error_code perform(SimpleFile &mf) override { - ScopedTask task(getDefaultDomain(), "ARM GOT/PLT Pass"); - DEBUG_WITH_TYPE( - "ARM", llvm::dbgs() << "Undefined Atoms" << "\n"; - for (const auto &atom - : mf.undefined()) { - llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n"; - } - - llvm::dbgs() << "Shared Library Atoms" << "\n"; - for (const auto &atom - : mf.sharedLibrary()) { - llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n"; - } - - llvm::dbgs() << "Absolute Atoms" << "\n"; - for (const auto &atom - : mf.absolute()) { - llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n"; - } - - llvm::dbgs() << "Defined Atoms" << "\n"; - for (const auto &atom - : mf.defined()) { - llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n"; - }); - - // Process all references. - for (const auto &atom : mf.defined()) { - for (const auto &ref : *atom) { - handleReference(*atom, *ref); - } - } - - // Add all created atoms to the link. - uint64_t ordinal = 0; - if (_plt0) { - _plt0->setOrdinal(ordinal++); - mf.addAtom(*_plt0); - _plt0_d->setOrdinal(ordinal++); - mf.addAtom(*_plt0_d); - } - for (auto &pltKV : _pltAtoms) { - auto &plt = pltKV.second; - if (auto *v = plt._veneer) { - v->setOrdinal(ordinal++); - mf.addAtom(*v); - } - auto *p = plt._plt; - p->setOrdinal(ordinal++); - mf.addAtom(*p); - } - if (_null) { - _null->setOrdinal(ordinal++); - mf.addAtom(*_null); - } - if (_plt0) { - _got0->setOrdinal(ordinal++); - mf.addAtom(*_got0); - _got1->setOrdinal(ordinal++); - mf.addAtom(*_got1); - } - for (auto &gotKV : _gotAtoms) { - auto &got = gotKV.second; - got->setOrdinal(ordinal++); - mf.addAtom(*got); - } - for (auto &gotKV : _gotpltAtoms) { - auto &got = gotKV.second; - got->setOrdinal(ordinal++); - mf.addAtom(*got); - } - for (auto &objectKV : _objectAtoms) { - auto &obj = objectKV.second; - obj->setOrdinal(ordinal++); - mf.addAtom(*obj); - } - for (auto &veneerKV : _veneerAtoms) { - auto &veneer = veneerKV.second; - auto *m = veneer._mapping; - m->setOrdinal(ordinal++); - mf.addAtom(*m); - auto *v = veneer._veneer; - v->setOrdinal(ordinal++); - mf.addAtom(*v); - } - - return std::error_code(); - } - -protected: - /// \brief Owner of all the Atoms created by this pass. - ELFPassFile _file; - const ELFLinkingContext &_ctx; - - /// \brief Map Atoms to their GOT entries. - llvm::MapVector<const Atom *, GOTAtom *> _gotAtoms; - - /// \brief Map Atoms to their PLTGOT entries. - llvm::MapVector<const Atom *, GOTAtom *> _gotpltAtoms; - - /// \brief Map Atoms to their Object entries. - llvm::MapVector<const Atom *, ObjectAtom *> _objectAtoms; - - /// \brief Map Atoms to their PLT entries depending on the code model. - struct PLTWithVeneer { - PLTWithVeneer(PLTAtom *p = nullptr, PLTAtom *v = nullptr) - : _plt(p), _veneer(v) {} - - bool empty() const { - assert((_plt || !_veneer) && "Veneer appears without PLT entry"); - return !_plt && !_veneer; - } - - PLTAtom *_plt; - PLTAtom *_veneer; - }; - llvm::MapVector<const Atom *, PLTWithVeneer> _pltAtoms; - - /// \brief Map Atoms to their veneers. - struct VeneerWithMapping { - VeneerWithMapping(VeneerAtom *v = nullptr, VeneerAtom *m = nullptr) - : _veneer(v), _mapping(m) {} - - bool empty() const { - assert(((bool)_veneer == (bool)_mapping) && - "Mapping symbol should always be paired with veneer"); - return !_veneer && !_mapping; - } - - VeneerAtom *_veneer; - VeneerAtom *_mapping; - }; - llvm::MapVector<const Atom *, VeneerWithMapping> _veneerAtoms; - - /// \brief GOT entry that is always 0. Used for undefined weaks. - GOTAtom *_null = nullptr; - - /// \brief The got and plt entries for .PLT0. This is used to call into the - /// dynamic linker for symbol resolution. - /// @{ - PLT0Atom *_plt0 = nullptr; - PLT0Atom *_plt0_d = nullptr; - GOTAtom *_got0 = nullptr; - GOTAtom *_got1 = nullptr; - /// @} -}; - -/// This implements the static relocation model. Meaning GOT and PLT entries are -/// not created for references that can be directly resolved. These are -/// converted to a direct relocation. For entries that do require a GOT or PLT -/// entry, that entry is statically bound. -/// -/// TLS always assumes module 1 and attempts to remove indirection. -class ARMStaticRelocationPass final - : public ARMRelocationPass<ARMStaticRelocationPass> { -public: - ARMStaticRelocationPass(const elf::ARMLinkingContext &ctx) - : ARMRelocationPass(ctx) {} - - /// \brief Handle ordinary relocation references. - std::error_code handlePlain(bool fromThumb, const Reference &ref) { - return handleIFUNC(fromThumb, ref); - } - - /// \brief Get the veneer for ARM B/BL instructions. - const VeneerAtom *getVeneer_ARM_B_BL(const DefinedAtom *da, - StringRef secName) { - return getVeneer_ARM_B_BL_Abs(da, secName); - } - - /// \brief Get the veneer for Thumb B/BL instructions. - const VeneerAtom *getVeneer_THM_B_BL(const DefinedAtom *da, - StringRef secName) { - return getVeneer_THM_B_BL_Abs(da, secName); - } - - /// \brief Create a GOT entry for R_ARM_TLS_TPOFF32 reloc. - const GOTAtom *getTLSTPOFF32(const DefinedAtom *da) { - return getGOTTLSEntry<R_ARM_TLS_LE32>(da); - } -}; - -/// This implements the dynamic relocation model. GOT and PLT entries are -/// created for references that cannot be directly resolved. -class ARMDynamicRelocationPass final - : public ARMRelocationPass<ARMDynamicRelocationPass> { -public: - ARMDynamicRelocationPass(const elf::ARMLinkingContext &ctx) - : ARMRelocationPass(ctx) {} - - /// \brief get the PLT entry for a given atom. - const PLTAtom *getPLTEntry(const SharedLibraryAtom *sla, bool fromThumb) { - return getPLT(sla, fromThumb, &ARMDynamicRelocationPass::createPLTGOT); - } - - /// \brief Create the GOT entry for a given atom. - const GOTAtom *createPLTGOT(const Atom *da) { - assert(!_gotpltAtoms.lookup(da) && "PLTGOT entry already exists"); - auto g = new (_file._alloc) ARMGOTPLTAtom(_file); - g->addReferenceELF_ARM(R_ARM_ABS32, 0, getPLT0(), 0); - g->addReferenceELF_ARM(R_ARM_JUMP_SLOT, 0, da, 0); -#ifndef NDEBUG - g->_name = "__got_plt0_"; - g->_name += da->name(); -#endif - _gotpltAtoms[da] = g; - return g; - } - - const ObjectAtom *getObjectEntry(const SharedLibraryAtom *a) { - if (auto obj = _objectAtoms.lookup(a)) - return obj; - - auto oa = new (_file._alloc) ARMObjectAtom(_file); - oa->addReferenceELF_ARM(R_ARM_COPY, 0, oa, 0); - - oa->_name = a->name(); - oa->_size = a->size(); - - _objectAtoms[a] = oa; - return oa; - } - - /// \brief Handle ordinary relocation references. - std::error_code handlePlain(bool fromThumb, const Reference &ref) { - if (auto sla = dyn_cast<SharedLibraryAtom>(ref.target())) { - if (sla->type() == SharedLibraryAtom::Type::Data && - _ctx.getOutputELFType() == llvm::ELF::ET_EXEC) { - const_cast<Reference &>(ref).setTarget(getObjectEntry(sla)); - } else if (sla->type() == SharedLibraryAtom::Type::Code) { - const_cast<Reference &>(ref).setTarget(getPLTEntry(sla, fromThumb)); - } - return std::error_code(); - } - return handleIFUNC(fromThumb, ref); - } - - /// \brief Get the veneer for ARM B/BL instructions. - const VeneerAtom *getVeneer_ARM_B_BL(const DefinedAtom *da, - StringRef secName) { - if (_ctx.getOutputELFType() == llvm::ELF::ET_EXEC) { - return getVeneer_ARM_B_BL_Abs(da, secName); - } - llvm_unreachable("Handle ARM veneer for DSOs"); - } - - /// \brief Get the veneer for Thumb B/BL instructions. - const VeneerAtom *getVeneer_THM_B_BL(const DefinedAtom *da, - StringRef secName) { - if (_ctx.getOutputELFType() == llvm::ELF::ET_EXEC) { - return getVeneer_THM_B_BL_Abs(da, secName); - } - llvm_unreachable("Handle Thumb veneer for DSOs"); - } - - /// \brief Create a GOT entry for R_ARM_TLS_TPOFF32 reloc. - const GOTAtom *getTLSTPOFF32(const DefinedAtom *da) { - return getGOTTLSEntry<R_ARM_TLS_TPOFF32>(da); - } - - const PLT0Atom *getPLT0() { - if (_plt0) - return _plt0; - // Fill in the null entry. - getNullGOT(); - _plt0 = new (_file._alloc) ARMPLT0_a_Atom(_file, "__PLT0"); - _plt0_d = new (_file._alloc) ARMPLT0_d_Atom(_file, "__PLT0_d"); - _got0 = new (_file._alloc) ARMGOTPLTAtom(_file); - _got1 = new (_file._alloc) ARMGOTPLTAtom(_file); - _plt0_d->addReferenceELF_ARM(R_ARM_REL32, 0, _got1, 0); - // Fake reference to show connection between the GOT and PLT entries. - _plt0->addReferenceELF_ARM(R_ARM_NONE, 0, _got0, 0); - // Fake reference to show connection between parts of PLT entry. - _plt0->addReferenceELF_ARM(R_ARM_NONE, 0, _plt0_d, 0); -#ifndef NDEBUG - _got0->_name = "__got0"; - _got1->_name = "__got1"; -#endif - return _plt0; - } - - const GOTAtom *getSharedGOTEntry(const SharedLibraryAtom *sla) { - return getGOT<R_ARM_GLOB_DAT>(sla); - } - - std::error_code handleGOT(const Reference &ref) { - if (const auto sla = dyn_cast<const SharedLibraryAtom>(ref.target())) { - const_cast<Reference &>(ref).setTarget(getSharedGOTEntry(sla)); - return std::error_code(); - } - return ARMRelocationPass::handleGOT(ref); - } -}; - -} // end of anon namespace - -std::unique_ptr<Pass> -lld::elf::createARMRelocationPass(const ARMLinkingContext &ctx) { - switch (ctx.getOutputELFType()) { - case llvm::ELF::ET_EXEC: - if (ctx.isDynamic()) - return llvm::make_unique<ARMDynamicRelocationPass>(ctx); - return llvm::make_unique<ARMStaticRelocationPass>(ctx); - case llvm::ELF::ET_DYN: - return llvm::make_unique<ARMDynamicRelocationPass>(ctx); - default: - llvm_unreachable("Unhandled output file type"); - } -} diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h b/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h deleted file mode 100644 index 651e798f33b..00000000000 --- a/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h +++ /dev/null @@ -1,31 +0,0 @@ -//===--------- lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h ---------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// \brief Declares the relocation processing pass for ARM. This includes -/// GOT and PLT entries, TLS, COPY, and ifunc. -/// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_ARM_ARM_RELOCATION_PASS_H -#define LLD_READER_WRITER_ELF_ARM_ARM_RELOCATION_PASS_H - -#include <memory> - -namespace lld { -class Pass; -namespace elf { -class ARMLinkingContext; - -/// \brief Create ARM relocation pass for the given linking context. -std::unique_ptr<Pass> createARMRelocationPass(const ARMLinkingContext &); -} -} - -#endif diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h b/lld/lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h deleted file mode 100644 index 85b9c916258..00000000000 --- a/lld/lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h +++ /dev/null @@ -1,59 +0,0 @@ -//===--------- lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h ------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_ARM_ARM_SYMBOL_TABLE_H -#define LLD_READER_WRITER_ELF_ARM_ARM_SYMBOL_TABLE_H - -#include "SectionChunks.h" -#include "TargetLayout.h" -#include "ARMELFFile.h" - -namespace lld { -namespace elf { - -/// \brief The SymbolTable class represents the symbol table in a ELF file -class ARMSymbolTable : public SymbolTable<ELF32LE> { -public: - typedef llvm::object::Elf_Sym_Impl<ELF32LE> Elf_Sym; - - ARMSymbolTable(const ELFLinkingContext &ctx); - - void addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da, - int64_t addr) override; -}; - -ARMSymbolTable::ARMSymbolTable(const ELFLinkingContext &ctx) - : SymbolTable(ctx, ".symtab", TargetLayout<ELF32LE>::ORDER_SYMBOL_TABLE) {} - -void ARMSymbolTable::addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da, - int64_t addr) { - SymbolTable::addDefinedAtom(sym, da, addr); - - if ((ARMELFDefinedAtom::ARMContentType)da->contentType() == - ARMELFDefinedAtom::typeARMExidx) - sym.st_value = addr; - - // Set zero bit to distinguish real symbols addressing Thumb instructions. - // Don't care about mapping symbols like $t and others. - if (DefinedAtom::codeARMThumb == da->codeModel()) - sym.st_value = static_cast<int64_t>(sym.st_value) | 0x1; - - // Mapping symbols should have special values of binding, type and size set. - if ((DefinedAtom::codeARM_a == da->codeModel()) || - (DefinedAtom::codeARM_d == da->codeModel()) || - (DefinedAtom::codeARM_t == da->codeModel())) { - sym.setBindingAndType(llvm::ELF::STB_LOCAL, llvm::ELF::STT_NOTYPE); - sym.st_size = 0; - } -} - -} // elf -} // lld - -#endif // LLD_READER_WRITER_ELF_ARM_ARM_SYMBOL_TABLE_H diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp b/lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp deleted file mode 100644 index e1f5eadbe78..00000000000 --- a/lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp +++ /dev/null @@ -1,32 +0,0 @@ -//===--------- lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp --------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Atoms.h" -#include "ARMExecutableWriter.h" -#include "ARMDynamicLibraryWriter.h" -#include "ARMTargetHandler.h" -#include "ARMLinkingContext.h" - -using namespace lld; -using namespace elf; - -ARMTargetHandler::ARMTargetHandler(ARMLinkingContext &ctx) - : _ctx(ctx), _targetLayout(new ARMTargetLayout(ctx)), - _relocationHandler(new ARMTargetRelocationHandler(*_targetLayout)) {} - -std::unique_ptr<Writer> ARMTargetHandler::getWriter() { - switch (this->_ctx.getOutputELFType()) { - case llvm::ELF::ET_EXEC: - return llvm::make_unique<ARMExecutableWriter>(_ctx, *_targetLayout); - case llvm::ELF::ET_DYN: - return llvm::make_unique<ARMDynamicLibraryWriter>(_ctx, *_targetLayout); - default: - llvm_unreachable("unsupported output type"); - } -} diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h b/lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h deleted file mode 100644 index 32caaf9b961..00000000000 --- a/lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h +++ /dev/null @@ -1,174 +0,0 @@ -//===--------- lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h ----------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_READER_WRITER_ELF_ARM_ARM_TARGET_HANDLER_H -#define LLD_READER_WRITER_ELF_ARM_ARM_TARGET_HANDLER_H - -#include "ARMELFFile.h" -#include "ARMRelocationHandler.h" -#include "ELFReader.h" -#include "TargetLayout.h" - -namespace lld { -class ELFLinkingContext; - -namespace elf { - -/// \brief ARM specific section (.ARM.exidx) with indexes to exception handlers -class ARMExidxSection : public AtomSection<ELF32LE> { - typedef AtomSection<ELF32LE> Base; - -public: - ARMExidxSection(const ELFLinkingContext &ctx, StringRef sectionName, - int32_t permissions, int32_t order) - : Base(ctx, sectionName, ARMELFDefinedAtom::typeARMExidx, permissions, - order) { - this->_type = SHT_ARM_EXIDX; - this->_isLoadedInMemory = true; - } - - bool hasOutputSegment() const override { return true; } - - const AtomLayout *appendAtom(const Atom *atom) override { - const DefinedAtom *definedAtom = cast<DefinedAtom>(atom); - assert((ARMELFDefinedAtom::ARMContentType)definedAtom->contentType() == - ARMELFDefinedAtom::typeARMExidx && - "atom content type for .ARM.exidx section has to be typeARMExidx"); - - DefinedAtom::Alignment atomAlign = definedAtom->alignment(); - uint64_t fOffset = alignOffset(this->fileSize(), atomAlign); - uint64_t mOffset = alignOffset(this->memSize(), atomAlign); - - _atoms.push_back(new (_alloc) AtomLayout(atom, fOffset, 0)); - this->_fsize = fOffset + definedAtom->size(); - this->_msize = mOffset + definedAtom->size(); - DEBUG_WITH_TYPE("Section", llvm::dbgs() - << "[" << this->name() << " " << this << "] " - << "Adding atom: " << atom->name() << "@" - << fOffset << "\n"); - - uint64_t alignment = atomAlign.value; - if (this->_alignment < alignment) - this->_alignment = alignment; - - return _atoms.back(); - } -}; - -class ARMTargetLayout : public TargetLayout<ELF32LE> { -public: - enum ARMSectionOrder { - ORDER_ARM_EXIDX = TargetLayout::ORDER_EH_FRAME + 1, - }; - - ARMTargetLayout(ELFLinkingContext &ctx) : TargetLayout(ctx) {} - - SectionOrder getSectionOrder(StringRef name, int32_t contentType, - int32_t contentPermissions) override { - switch (contentType) { - case ARMELFDefinedAtom::typeARMExidx: - return ORDER_ARM_EXIDX; - default: - return TargetLayout::getSectionOrder(name, contentType, - contentPermissions); - } - } - - StringRef getOutputSectionName(StringRef archivePath, StringRef memberPath, - StringRef inputSectionName) const override { - return llvm::StringSwitch<StringRef>(inputSectionName) - .StartsWith(".ARM.exidx", ".ARM.exidx") - .StartsWith(".ARM.extab", ".ARM.extab") - .Default(TargetLayout::getOutputSectionName(archivePath, memberPath, - inputSectionName)); - } - - SegmentType getSegmentType(const Section<ELF32LE> *section) const override { - switch (section->order()) { - case ORDER_ARM_EXIDX: - return llvm::ELF::PT_ARM_EXIDX; - default: - return TargetLayout::getSegmentType(section); - } - } - - AtomSection<ELF32LE> * - createSection(StringRef name, int32_t contentType, - DefinedAtom::ContentPermissions contentPermissions, - SectionOrder sectionOrder) override { - if ((ARMELFDefinedAtom::ARMContentType)contentType == - ARMELFDefinedAtom::typeARMExidx) - return new ARMExidxSection(_ctx, name, contentPermissions, sectionOrder); - - return TargetLayout::createSection(name, contentType, contentPermissions, - sectionOrder); - } - - uint64_t getGOTSymAddr() { - std::call_once(_gotSymOnce, [this]() { - if (AtomLayout *gotAtom = findAbsoluteAtom("_GLOBAL_OFFSET_TABLE_")) - _gotSymAddr = gotAtom->_virtualAddr; - }); - return _gotSymAddr; - } - - uint64_t getTPOffset() { - std::call_once(_tpOffOnce, [this]() { - for (const auto &phdr : *_programHeader) { - if (phdr->p_type == llvm::ELF::PT_TLS) { - _tpOff = llvm::alignTo(TCB_SIZE, phdr->p_align); - break; - } - } - assert(_tpOff != 0 && "TLS segment not found"); - }); - return _tpOff; - } - - bool target1Rel() const { return _ctx.armTarget1Rel(); } - -private: - // TCB block size of the TLS. - enum { TCB_SIZE = 0x8 }; - -private: - uint64_t _gotSymAddr = 0; - uint64_t _tpOff = 0; - std::once_flag _gotSymOnce; - std::once_flag _tpOffOnce; -}; - -class ARMTargetHandler final : public TargetHandler { -public: - ARMTargetHandler(ARMLinkingContext &ctx); - - const TargetRelocationHandler &getRelocationHandler() const override { - return *_relocationHandler; - } - - std::unique_ptr<Reader> getObjReader() override { - return llvm::make_unique<ELFReader<ARMELFFile>>(_ctx); - } - - std::unique_ptr<Reader> getDSOReader() override { - return llvm::make_unique<ELFReader<DynamicFile<ELF32LE>>>(_ctx); - } - - std::unique_ptr<Writer> getWriter() override; - -private: - ARMLinkingContext &_ctx; - std::unique_ptr<ARMTargetLayout> _targetLayout; - std::unique_ptr<ARMTargetRelocationHandler> _relocationHandler; -}; - -} // end namespace elf -} // end namespace lld - -#endif // LLD_READER_WRITER_ELF_ARM_ARM_TARGET_HANDLER_H diff --git a/lld/lib/ReaderWriter/ELF/ARM/CMakeLists.txt b/lld/lib/ReaderWriter/ELF/ARM/CMakeLists.txt deleted file mode 100644 index c8cd6533d90..00000000000 --- a/lld/lib/ReaderWriter/ELF/ARM/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -add_lld_library(lldARMELFTarget - ARMLinkingContext.cpp - ARMTargetHandler.cpp - ARMRelocationHandler.cpp - ARMRelocationPass.cpp - LINK_LIBS - lldELF - lldReaderWriter - lldCore - LLVMObject - LLVMSupport - ) diff --git a/lld/lib/ReaderWriter/ELF/ARM/TODO.rst b/lld/lib/ReaderWriter/ELF/ARM/TODO.rst deleted file mode 100644 index 61b585ae698..00000000000 --- a/lld/lib/ReaderWriter/ELF/ARM/TODO.rst +++ /dev/null @@ -1,21 +0,0 @@ -ELF ARM -~~~~~~~~~~~ - -Unimplemented Features -###################### - -* DSO linking -* C++ code linking -* PLT entries' generation for images larger than 2^28 bytes (see Sec. A.3 of the ARM ELF reference) -* ARM/Thumb interwork veneers in position-independent code -* .ARM.exidx section (exception handling) -* -init/-fini options -* Proper debug information (DWARF data) -* TLS relocations for dynamic models -* Lots of other relocations - -Unimplemented Relocations -######################### - -All of these relocations are defined in: -http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044e/IHI0044E_aaelf.pdf |

