summaryrefslogtreecommitdiffstats
path: root/lld/lib/ReaderWriter/ELF/ARM
diff options
context:
space:
mode:
Diffstat (limited to 'lld/lib/ReaderWriter/ELF/ARM')
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/ARMDynamicLibraryWriter.h49
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/ARMELFFile.h154
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/ARMELFWriters.h120
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h68
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp64
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h80
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp680
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h35
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp986
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h31
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h59
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp32
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h174
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/CMakeLists.txt12
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/TODO.rst21
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 &registry) {
- 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
OpenPOWER on IntegriCloud