summaryrefslogtreecommitdiff
path: root/lib/ReaderWriter/ELF/ARM
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ReaderWriter/ELF/ARM')
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMDynamicLibraryWriter.h49
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMELFFile.h143
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMELFReader.h62
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMELFWriters.h120
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h99
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp48
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h46
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp578
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h15
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp816
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h39
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp28
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h162
-rw-r--r--lib/ReaderWriter/ELF/ARM/Makefile15
-rw-r--r--lib/ReaderWriter/ELF/ARM/TODO.rst13
15 files changed, 1640 insertions, 593 deletions
diff --git a/lib/ReaderWriter/ELF/ARM/ARMDynamicLibraryWriter.h b/lib/ReaderWriter/ELF/ARM/ARMDynamicLibraryWriter.h
new file mode 100644
index 000000000000..da843b97abc0
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ARM/ARMDynamicLibraryWriter.h
@@ -0,0 +1,49 @@
+//===- 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/lib/ReaderWriter/ELF/ARM/ARMELFFile.h b/lib/ReaderWriter/ELF/ARM/ARMELFFile.h
index bc5ee35b8213..8f5477017e55 100644
--- a/lib/ReaderWriter/ELF/ARM/ARMELFFile.h
+++ b/lib/ReaderWriter/ELF/ARM/ARMELFFile.h
@@ -17,53 +17,95 @@ namespace elf {
class ARMLinkingContext;
-template <class ELFT> class ARMELFDefinedAtom : public ELFDefinedAtom<ELFT> {
- typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
- typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
+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:
- ARMELFDefinedAtom(const ELFFile<ELFT> &file, StringRef symbolName,
- StringRef sectionName, const Elf_Sym *symbol,
- const Elf_Shdr *section, ArrayRef<uint8_t> contentData,
- unsigned int referenceStart, unsigned int referenceEnd,
- std::vector<ELFReference<ELFT> *> &referenceList)
- : ELFDefinedAtom<ELFT>(file, symbolName, sectionName, symbol, section,
- contentData, referenceStart, referenceEnd,
- referenceList) {}
-
- bool isThumbFunc(const Elf_Sym *symbol) const {
+ 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);
+ (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 Elf_Sym *symbol) const override {
- const auto value = static_cast<uint64_t>(symbol->st_value);
- return isThumbFunc(symbol) ? value & ~0x1 : value;
+ 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 {
- if (isThumbFunc(this->_symbol))
- return DefinedAtom::codeARMThumb;
- return DefinedAtom::codeNA;
+ return isThumbFunc() ? DefinedAtom::codeARMThumb : DefinedAtom::codeNA;
}
};
-template <class ELFT> class ARMELFFile : public ELFFile<ELFT> {
-public:
- ARMELFFile(std::unique_ptr<MemoryBuffer> mb, ARMLinkingContext &ctx)
- : ELFFile<ELFT>(std::move(mb), ctx) {}
+class ARMELFFile : public ELFFile<ELF32LE> {
+ typedef llvm::object::Elf_Rel_Impl<ELF32LE, false> Elf_Rel;
- static ErrorOr<std::unique_ptr<ARMELFFile>>
- create(std::unique_ptr<MemoryBuffer> mb, ARMLinkingContext &ctx) {
- return std::unique_ptr<ARMELFFile<ELFT>>(
- new ARMELFFile<ELFT>(std::move(mb), ctx));
+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<ELFT> Elf_Sym;
- typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
+ 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.
@@ -73,24 +115,39 @@ private:
}
/// Process the Defined symbol and create an atom for it.
- ErrorOr<ELFDefinedAtom<ELFT> *> handleDefinedSymbol(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<ELFT> *> &referenceList) override {
- return new (this->_readerStorage) ARMELFDefinedAtom<ELFT>(
+ 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);
}
};
-template <class ELFT> class ARMDynamicFile : public DynamicFile<ELFT> {
-public:
- ARMDynamicFile(const ARMLinkingContext &context, StringRef name)
- : DynamicFile<ELFT>(context, name) {}
-};
-
} // elf
} // lld
diff --git a/lib/ReaderWriter/ELF/ARM/ARMELFReader.h b/lib/ReaderWriter/ELF/ARM/ARMELFReader.h
deleted file mode 100644
index 31af531563ea..000000000000
--- a/lib/ReaderWriter/ELF/ARM/ARMELFReader.h
+++ /dev/null
@@ -1,62 +0,0 @@
-//===--------- lib/ReaderWriter/ELF/ARM/ARMELFReader.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_ARM_ARM_ELF_READER_H
-#define LLD_READER_WRITER_ARM_ARM_ELF_READER_H
-
-#include "ARMELFFile.h"
-#include "ELFReader.h"
-
-namespace lld {
-namespace elf {
-
-typedef llvm::object::ELFType<llvm::support::little, 2, false> ARMELFType;
-
-struct ARMDynamicFileCreateELFTraits {
- typedef llvm::ErrorOr<std::unique_ptr<lld::SharedLibraryFile>> result_type;
-
- template <class ELFT>
- static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
- ARMLinkingContext &ctx) {
- return lld::elf::ARMDynamicFile<ELFT>::create(std::move(mb), ctx);
- }
-};
-
-struct ARMELFFileCreateELFTraits {
- typedef llvm::ErrorOr<std::unique_ptr<lld::File>> result_type;
-
- template <class ELFT>
- static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
- ARMLinkingContext &ctx) {
- return lld::elf::ARMELFFile<ELFT>::create(std::move(mb), ctx);
- }
-};
-
-class ARMELFObjectReader
- : public ELFObjectReader<ARMELFType, ARMELFFileCreateELFTraits,
- ARMLinkingContext> {
-public:
- ARMELFObjectReader(ARMLinkingContext &ctx)
- : ELFObjectReader<ARMELFType, ARMELFFileCreateELFTraits,
- ARMLinkingContext>(ctx, llvm::ELF::EM_ARM) {}
-};
-
-class ARMELFDSOReader
- : public ELFDSOReader<ARMELFType, ARMDynamicFileCreateELFTraits,
- ARMLinkingContext> {
-public:
- ARMELFDSOReader(ARMLinkingContext &ctx)
- : ELFDSOReader<ARMELFType, ARMDynamicFileCreateELFTraits,
- ARMLinkingContext>(ctx, llvm::ELF::EM_ARM) {}
-};
-
-} // namespace elf
-} // namespace lld
-
-#endif // LLD_READER_WRITER_ARM_ARM_ELF_READER_H
diff --git a/lib/ReaderWriter/ELF/ARM/ARMELFWriters.h b/lib/ReaderWriter/ELF/ARM/ARMELFWriters.h
new file mode 100644
index 000000000000..a842ebe53038
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ARM/ARMELFWriters.h
@@ -0,0 +1,120 @@
+//===- 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/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h b/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h
index 19311d516e4d..974dab63a126 100644
--- a/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h
+++ b/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h
@@ -10,111 +10,58 @@
#define LLD_READER_WRITER_ELF_ARM_ARM_EXECUTABLE_WRITER_H
#include "ExecutableWriter.h"
+#include "ARMELFWriters.h"
#include "ARMLinkingContext.h"
#include "ARMTargetHandler.h"
-#include "ARMSymbolTable.h"
-
-namespace {
-const char *gotSymbol = "_GLOBAL_OFFSET_TABLE_";
-}
namespace lld {
namespace elf {
-template <class ELFT>
-class ARMExecutableWriter : public ExecutableWriter<ELFT> {
+class ARMExecutableWriter : public ARMELFWriter<ExecutableWriter<ELF32LE>> {
public:
- ARMExecutableWriter(ARMLinkingContext &context,
- ARMTargetLayout<ELFT> &layout);
+ ARMExecutableWriter(ARMLinkingContext &ctx, ARMTargetLayout &layout);
protected:
// Add any runtime files and their atoms to the output
- bool createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
-
- void finalizeDefaultAtomValues() override;
-
- void addDefaultAtoms() override {
- ExecutableWriter<ELFT>::addDefaultAtoms();
- }
-
- /// \brief Create symbol table.
- unique_bump_ptr<SymbolTable<ELFT>> createSymbolTable() override;
+ void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
void processUndefinedSymbol(StringRef symName,
- RuntimeFile<ELFT> &file) const override;
-
- // Setup the ELF header.
- std::error_code setELFHeader() override;
+ RuntimeFile<ELF32LE> &file) const override;
private:
- ARMLinkingContext &_context;
- ARMTargetLayout<ELFT> &_armLayout;
+ ARMLinkingContext &_ctx;
};
-template <class ELFT>
-ARMExecutableWriter<ELFT>::ARMExecutableWriter(ARMLinkingContext &context,
- ARMTargetLayout<ELFT> &layout)
- : ExecutableWriter<ELFT>(context, layout), _context(context),
- _armLayout(layout) {}
+ARMExecutableWriter::ARMExecutableWriter(ARMLinkingContext &ctx,
+ ARMTargetLayout &layout)
+ : ARMELFWriter(ctx, layout), _ctx(ctx) {}
-template <class ELFT>
-bool ARMExecutableWriter<ELFT>::createImplicitFiles(
+void ARMExecutableWriter::createImplicitFiles(
std::vector<std::unique_ptr<File>> &result) {
- ExecutableWriter<ELFT>::createImplicitFiles(result);
- return true;
-}
-
-template <class ELFT>
-void ARMExecutableWriter<ELFT>::finalizeDefaultAtomValues() {
- // Finalize the atom values that are part of the parent.
- ExecutableWriter<ELFT>::finalizeDefaultAtomValues();
- auto gotAtomIter = _armLayout.findAbsoluteAtom(gotSymbol);
- if (gotAtomIter != _armLayout.absoluteAtoms().end()) {
- auto *gotAtom = *gotAtomIter;
- 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;
+ 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));
}
- // TODO: resolve addresses of __exidx_start/_end atoms
-}
-
-template <class ELFT>
-unique_bump_ptr<SymbolTable<ELFT>>
- ARMExecutableWriter<ELFT>::createSymbolTable() {
- return unique_bump_ptr<SymbolTable<ELFT>>(
- new (this->_alloc) ARMSymbolTable<ELFT>(this->_context));
}
-template <class ELFT>
-void ARMExecutableWriter<ELFT>::processUndefinedSymbol(
- StringRef symName, RuntimeFile<ELFT> &file) const {
+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");
}
}
-template <class ELFT>
-std::error_code ARMExecutableWriter<ELFT>::setELFHeader() {
- if (std::error_code ec = ExecutableWriter<ELFT>::setELFHeader())
- return ec;
-
- // Fixup entry point for Thumb code.
- StringRef entryName = _context.entrySymbolName();
- if (const AtomLayout *al = _armLayout.findAtomLayoutByName(entryName)) {
- const auto *ea = dyn_cast<DefinedAtom>(al->_atom);
- if (ea && ea->codeModel() == DefinedAtom::codeARMThumb)
- this->_elfHeader->e_entry(al->_virtualAddr | 0x1);
- }
-
- return std::error_code();
-}
-
} // namespace elf
} // namespace lld
diff --git a/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp b/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp
index 5f2436674268..74905b47820f 100644
--- a/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp
+++ b/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp
@@ -11,24 +11,54 @@
#include "ARMRelocationPass.h"
#include "ARMTargetHandler.h"
-using namespace lld;
-using namespace lld::elf;
+namespace lld {
+namespace elf {
std::unique_ptr<ELFLinkingContext>
-elf::ARMLinkingContext::create(llvm::Triple triple) {
+createARMLinkingContext(llvm::Triple triple) {
if (triple.getArch() == llvm::Triple::arm)
- return std::unique_ptr<ELFLinkingContext>(
- new elf::ARMLinkingContext(triple));
+ return llvm::make_unique<ARMLinkingContext>(triple);
return nullptr;
}
-elf::ARMLinkingContext::ARMLinkingContext(llvm::Triple triple)
- : ELFLinkingContext(triple, std::unique_ptr<TargetHandlerBase>(
- new ARMTargetHandler(*this))) {}
+ARMLinkingContext::ARMLinkingContext(llvm::Triple triple)
+ : ELFLinkingContext(triple, llvm::make_unique<ARMTargetHandler>(*this)) {}
-void elf::ARMLinkingContext::addPasses(PassManager &pm) {
+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/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h b/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h
index 249b79c4f07d..f687713b25b8 100644
--- a/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h
+++ b/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h
@@ -19,17 +19,61 @@ namespace elf {
class ARMLinkingContext final : public ELFLinkingContext {
public:
- static std::unique_ptr<ELFLinkingContext> create(llvm::Triple);
+ 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
diff --git a/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp b/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp
index d24fdf0fa410..97b149133ff2 100644
--- a/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp
+++ b/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp
@@ -14,6 +14,8 @@
#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;
@@ -74,7 +76,7 @@ static Reference::Addend readAddend_THM_JUMP11(const uint8_t *location) {
const auto value = read16le(location);
const uint16_t imm11 = value & 0x7FF;
- return llvm::SignExtend32<12>(imm11 << 1);
+ return llvm::SignExtend64<12>(imm11 << 1);
}
static Reference::Addend readAddend(const uint8_t *location,
@@ -82,11 +84,15 @@ static Reference::Addend readAddend(const uint8_t *location,
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 (int32_t)(read32le(location) & 0x7FFFFFFF);
+ return llvm::SignExtend64<31>(read32le(location) & 0x7FFFFFFF);
case R_ARM_THM_CALL:
case R_ARM_THM_JUMP24:
return readAddend_THM_CALL(location);
@@ -106,81 +112,98 @@ static Reference::Addend readAddend(const uint8_t *location,
}
}
-static inline void applyArmReloc(uint8_t *location, uint32_t result,
- uint32_t mask = 0xFFFFFFFF) {
+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 void applyThmReloc(uint8_t *location, uint16_t resHi,
- uint16_t resLo, uint16_t maskHi,
- uint16_t maskLo = 0xFFFF) {
+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 void applyThumb16Reloc(uint8_t *location, uint16_t result,
- uint16_t mask = 0xFFFF) {
+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 void relocR_ARM_ABS32(uint8_t *location, uint64_t P, uint64_t S,
- int64_t A, bool addressesThumb) {
+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_WITH_TYPE(
- "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
- llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
- llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
- llvm::dbgs() << " T: 0x" << Twine::utohexstr(T);
- llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
- applyArmReloc(location, result);
+ 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 void relocR_ARM_REL32(uint8_t *location, uint64_t P, uint64_t S,
- int64_t A, bool addressesThumb) {
+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_WITH_TYPE(
- "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
- llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
- llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
- llvm::dbgs() << " T: 0x" << Twine::utohexstr(T);
- llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
- applyArmReloc(location, result);
+ 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 void relocR_ARM_PREL31(uint8_t *location, uint64_t P, uint64_t S,
- int64_t A, bool addressesThumb) {
+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_WITH_TYPE(
- "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
- llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
- llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
- llvm::dbgs() << " T: 0x" << Twine::utohexstr(T);
- llvm::dbgs() << " result: 0x" << Twine::utohexstr(result);
- llvm::dbgs() << " rel31: 0x" << Twine::utohexstr(rel31) << "\n");
+ 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");
- applyArmReloc(location, rel31, mask);
+ return applyArmReloc(location, rel31, mask);
}
/// \brief Relocate B/BL instructions. useJs defines whether J1 & J2 are used
-static void relocR_ARM_THM_B_L(uint8_t *location, uint32_t result, bool useJs) {
+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;
@@ -194,12 +217,13 @@ static void relocR_ARM_THM_B_L(uint8_t *location, uint32_t result, bool useJs) {
const uint16_t bitI1 = (~(bitJ1 ^ bitS)) & 0x1;
const uint16_t resLo = (bitI1 << 13) | (bitI2 << 11) | imm11;
- applyThmReloc(location, resHi, resLo, 0x7FF, 0x2FFF);
+ return applyThumb32Reloc(location, resHi, resLo, 0x7FF, 0x2FFF);
}
/// \brief R_ARM_THM_CALL - ((S + A) | T) - P
-static void relocR_ARM_THM_CALL(uint8_t *location, uint64_t P, uint64_t S,
- int64_t A, bool useJs, bool addressesThumb) {
+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;
@@ -209,137 +233,171 @@ static void relocR_ARM_THM_CALL(uint8_t *location, uint64_t P, uint64_t S,
uint32_t result = (uint32_t)(((S + A) | T) - P);
- DEBUG_WITH_TYPE(
- "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
- llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
- llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
- llvm::dbgs() << " T: 0x" << Twine::utohexstr(T);
- llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
- relocR_ARM_THM_B_L(location, result, useJs);
+ 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) {
- applyThmReloc(location, 0, 0, 0, 0x1001);
+ return applyThumb32Reloc(location, 0, 0, 0, 0x1001);
}
+ return std::error_code();
}
/// \brief R_ARM_THM_JUMP24 - ((S + A) | T) - P
-static void relocR_ARM_THM_JUMP24(uint8_t *location, uint64_t P, uint64_t S,
- int64_t A, bool addressesThumb) {
+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_WITH_TYPE(
- "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
- llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
- llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
- llvm::dbgs() << " T: 0x" << Twine::utohexstr(T);
- llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
- relocR_ARM_THM_B_L(location, result, true);
+ 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 void relocR_ARM_THM_JUMP11(uint8_t *location, uint64_t P, uint64_t S,
- int64_t A) {
+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_WITH_TYPE(
- "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
- llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
- llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
- llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ 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");
- //we cut off first bit because it is always 1 according to p. 4.5.3
+ 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);
+}
- applyThumb16Reloc(location, result, 0x7FF);
+/// \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 void relocR_ARM_CALL(uint8_t *location, uint64_t P, uint64_t S,
- int64_t A, bool addressesThumb) {
+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_WITH_TYPE(
- "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
- llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
- llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
- llvm::dbgs() << " T: 0x" << Twine::utohexstr(T);
- llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
- applyArmReloc(location, imm24, 0xFFFFFF);
+ 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;
- applyArmReloc(location, (0xFA | bitH) << 24, 0xFF000000);
+ return applyArmReloc(location, (0xFA | bitH) << 24, 0xFF000000);
}
+ return std::error_code();
}
/// \brief R_ARM_JUMP24 - ((S + A) | T) - P
-static void relocR_ARM_JUMP24(uint8_t *location, uint64_t P, uint64_t S,
- int64_t A, bool addressesThumb) {
+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_WITH_TYPE(
- "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
- llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
- llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
- llvm::dbgs() << " T: 0x" << Twine::utohexstr(T);
- llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
- applyArmReloc(location, imm24, 0xFFFFFF);
+ 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 void relocR_ARM_MOV(uint8_t *location, uint32_t result) {
+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;
- applyArmReloc(location, (imm4 << 16) | imm12, 0xF0FFF);
+ return applyArmReloc(location, (imm4 << 16) | imm12, 0xF0FFF);
}
/// \brief R_ARM_MOVW_ABS_NC - (S + A) | T
-static void relocR_ARM_MOVW_ABS_NC(uint8_t *location, uint64_t P, uint64_t S,
- int64_t A, bool addressesThumb) {
+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_WITH_TYPE(
- "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
- llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
- llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
- llvm::dbgs() << " T: 0x" << Twine::utohexstr(T);
- llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ 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 void relocR_ARM_MOVT_ABS(uint8_t *location, uint64_t P, uint64_t S,
- int64_t 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_WITH_TYPE(
- "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
- llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
- llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
- llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ 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 void relocR_ARM_THM_MOV(uint8_t *location, uint32_t result) {
+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;
@@ -348,153 +406,275 @@ static void relocR_ARM_THM_MOV(uint8_t *location, uint32_t result) {
const uint16_t bitI = (result >> 11) & 0x1;
const uint16_t resHi = (bitI << 10) | imm4;
- applyThmReloc(location, resHi, resLo, 0x40F, 0x70FF);
+ return applyThumb32Reloc(location, resHi, resLo, 0x40F, 0x70FF);
}
/// \brief R_ARM_THM_MOVW_ABS_NC - (S + A) | T
-static void relocR_ARM_THM_MOVW_ABS_NC(uint8_t *location, uint64_t P,
- uint64_t S, int64_t A,
- bool addressesThumb) {
+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_WITH_TYPE(
- "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
- llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
- llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
- llvm::dbgs() << " T: 0x" << Twine::utohexstr(T);
- llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ 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 void relocR_ARM_THM_MOVT_ABS(uint8_t *location, uint64_t P, uint64_t S,
- int64_t 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_WITH_TYPE(
- "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
- llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
- llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
- llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ 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 void relocR_ARM_TLS_IE32(uint8_t *location, uint64_t P, uint64_t S,
- int64_t A) {
+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_WITH_TYPE(
- "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
- llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
- llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
- llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
- applyArmReloc(location, result);
+ 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 void relocR_ARM_TLS_LE32(uint8_t *location, uint64_t P, uint64_t S,
- int64_t A, uint64_t 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_WITH_TYPE(
- "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
- llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
- llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
- llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
- applyArmReloc(location, result);
+ 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 lld::AtomLayout &atom,
+ ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom,
const Reference &ref) const {
uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset;
- uint8_t *location = atomContent + ref.offsetInAtom();
- uint64_t targetVAddress = writer.addressOfAtom(ref.target());
- uint64_t relocVAddress = atom._virtualAddr + ref.offsetInAtom();
+ 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(location, ref.kindValue());
+ readAddend(loc, ref.kindValue()) + ref.addend();
// Flags that the relocation addresses Thumb instruction
- bool addressesThumb = false;
-
+ bool thumb = false;
if (const auto *definedAtom = dyn_cast<DefinedAtom>(ref.target())) {
- addressesThumb = (DefinedAtom::codeARMThumb == definedAtom->codeModel());
+ thumb = isThumbCode(definedAtom);
}
switch (ref.kindValue()) {
case R_ARM_NONE:
- break;
+ return std::error_code();
case R_ARM_ABS32:
- relocR_ARM_ABS32(location, relocVAddress, targetVAddress, addend,
- addressesThumb);
- break;
+ return relocR_ARM_ABS32(loc, reloc, target, addend, thumb);
case R_ARM_REL32:
- relocR_ARM_REL32(location, relocVAddress, targetVAddress, addend,
- addressesThumb);
- break;
+ 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
- relocR_ARM_THM_CALL(location, relocVAddress, targetVAddress, addend, true,
- addressesThumb);
- break;
+ return relocR_ARM_THM_CALL(loc, reloc, target, addend, true, thumb);
case R_ARM_CALL:
- relocR_ARM_CALL(location, relocVAddress, targetVAddress, addend,
- addressesThumb);
- break;
+ return relocR_ARM_CALL(loc, reloc, target, addend, thumb);
case R_ARM_JUMP24:
- relocR_ARM_JUMP24(location, relocVAddress, targetVAddress, addend,
- addressesThumb);
- break;
+ return relocR_ARM_JUMP24(loc, reloc, target, addend, thumb);
case R_ARM_THM_JUMP24:
- relocR_ARM_THM_JUMP24(location, relocVAddress, targetVAddress, addend,
- addressesThumb);
- break;
+ return relocR_ARM_THM_JUMP24(loc, reloc, target, addend, thumb);
case R_ARM_THM_JUMP11:
- relocR_ARM_THM_JUMP11(location, relocVAddress, targetVAddress, addend);
- break;
+ return relocR_ARM_THM_JUMP11(loc, reloc, target, addend);
case R_ARM_MOVW_ABS_NC:
- relocR_ARM_MOVW_ABS_NC(location, relocVAddress, targetVAddress, addend,
- addressesThumb);
- break;
+ return relocR_ARM_MOVW_ABS_NC(loc, reloc, target, addend, thumb);
case R_ARM_MOVT_ABS:
- relocR_ARM_MOVT_ABS(location, relocVAddress, targetVAddress, addend);
- break;
+ return relocR_ARM_MOVT_ABS(loc, reloc, target, addend);
case R_ARM_THM_MOVW_ABS_NC:
- relocR_ARM_THM_MOVW_ABS_NC(location, relocVAddress, targetVAddress, addend,
- addressesThumb);
- break;
+ return relocR_ARM_THM_MOVW_ABS_NC(loc, reloc, target, addend, thumb);
case R_ARM_THM_MOVT_ABS:
- relocR_ARM_THM_MOVT_ABS(location, relocVAddress, targetVAddress, addend);
- break;
+ return relocR_ARM_THM_MOVT_ABS(loc, reloc, target, addend);
case R_ARM_PREL31:
- relocR_ARM_PREL31(location, relocVAddress, targetVAddress, addend,
- addressesThumb);
- break;
+ return relocR_ARM_PREL31(loc, reloc, target, addend, thumb);
case R_ARM_TLS_IE32:
- relocR_ARM_TLS_IE32(location, relocVAddress, targetVAddress, addend);
- break;
+ return relocR_ARM_TLS_IE32(loc, reloc, target, addend);
case R_ARM_TLS_LE32:
- relocR_ARM_TLS_LE32(location, relocVAddress, targetVAddress, addend,
- _armLayout.getTPOffset());
- break;
+ 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();
}
- return std::error_code();
+ llvm_unreachable("All switch cases must return directly");
}
diff --git a/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h b/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h
index 227d68617bf9..a1f3d091f204 100644
--- a/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h
+++ b/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h
@@ -10,26 +10,23 @@
#ifndef LLD_READER_WRITER_ELF_ARM_ARM_RELOCATION_HANDLER_H
#define LLD_READER_WRITER_ELF_ARM_ARM_RELOCATION_HANDLER_H
-#include "ARMTargetHandler.h"
+#include "lld/ReaderWriter/ELFLinkingContext.h"
namespace lld {
namespace elf {
-typedef llvm::object::ELFType<llvm::support::little, 2, false> ARMELFType;
-template <class ELFT> class ARMTargetLayout;
+class ARMTargetLayout;
-class ARMTargetRelocationHandler final
- : public TargetRelocationHandler {
+class ARMTargetRelocationHandler final : public TargetRelocationHandler {
public:
- ARMTargetRelocationHandler(ARMTargetLayout<ARMELFType> &layout)
- : _armLayout(layout) {}
+ ARMTargetRelocationHandler(ARMTargetLayout &layout) : _armLayout(layout) {}
std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
- const lld::AtomLayout &,
+ const AtomLayout &,
const Reference &) const override;
private:
- ARMTargetLayout<ARMELFType> &_armLayout;
+ ARMTargetLayout &_armLayout;
};
} // end namespace elf
diff --git a/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp b/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp
index 27ec66ac5557..fc2ae75cd7a7 100644
--- a/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp
+++ b/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp
@@ -20,7 +20,7 @@
#include "ARMLinkingContext.h"
#include "Atoms.h"
#include "lld/Core/Simple.h"
-#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Debug.h"
@@ -28,34 +28,77 @@ using namespace lld;
using namespace lld::elf;
using namespace llvm::ELF;
-// ARM B/BL instructions of static relocation veneer.
+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_StaticAtomContent[8] = {
- 0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc, #-4]
+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 static relocation veneer.
+// 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_StaticAtomContent[8] = {
+static const uint8_t Veneer_THM_B_BL_Abs_t_AtomContent[4] = {
0x78, 0x47, // bx pc
- 0x00, 0x00, // nop
+ 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};
-namespace {
+// .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)
- : SimpleELFDefinedAtom(f), _section(secName) {}
+ VeneerAtom(const File &f, StringRef secName, const std::string &name = "")
+ : SimpleELFDefinedAtom(f), _section(secName), _name(name) {}
Scope scope() const override { return DefinedAtom::scopeTranslationUnit; }
@@ -65,58 +108,208 @@ public:
StringRef customSectionName() const override { return _section; }
- ContentType contentType() const override {
- return DefinedAtom::typeCode;
- }
+ 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 Alignment(2); }
+ Alignment alignment() const override { return 4; }
StringRef name() const override { return _name; }
+
+private:
std::string _name;
};
-/// \brief Atoms that hold veneer for statically relocated
-/// ARM B/BL instructions.
-class Veneer_ARM_B_BL_StaticAtom : public VeneerAtom {
+/// \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_StaticAtom(const File &f, StringRef secName)
- : VeneerAtom(f, secName) {}
+ 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_StaticAtomContent);
+ return llvm::makeArrayRef(Veneer_ARM_B_BL_Abs_a_AtomContent);
}
};
-/// \brief Atoms that hold veneer for statically relocated
-/// Thumb B/BL instructions.
-class Veneer_THM_B_BL_StaticAtom : public VeneerAtom {
+class Veneer_ARM_B_BL_Abs_d_Atom : public VeneerAtom {
public:
- Veneer_THM_B_BL_StaticAtom(const File &f, StringRef secName)
+ 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_StaticAtomContent);
+ 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, StringRef secName) : GOTAtom(f, secName) {}
+ ARMGOTAtom(const File &f) : GOTAtom(f, ".got") {}
ArrayRef<uint8_t> rawContent() const override {
return llvm::makeArrayRef(ARMGotAtomContent);
}
- Alignment alignment() const override { return Alignment(2); }
+ 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 {
@@ -140,30 +333,92 @@ template <class Derived> class ARMRelocationPass : public Pass {
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:
- static_cast<Derived *>(this)->handleVeneer(atom, ref);
- break;
+ 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:
- std::error_code handleVeneer(const DefinedAtom &atom, const Reference &ref) {
+ /// \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 || target->codeModel() == atom.codeModel())
+ if (!target || isThumbCode(target) == isThumbCode(&atom))
return std::error_code();
- // TODO: For unconditional jump instructions (R_ARM_CALL and R_ARM_THM_CALL)
- // fixup isn't possible without veneer generation for archs below ARMv5.
-
// Veneers may only be generated for STT_FUNC target symbols
// or for symbols located in sections different to the place of relocation.
- const auto kindValue = ref.kindValue();
StringRef secName = atom.customSectionName();
if (DefinedAtom::typeCode != target->contentType() &&
!target->customSectionName().equals(secName)) {
@@ -182,29 +437,69 @@ protected:
llvm_unreachable(errStr.c_str());
}
- const Atom *veneer = nullptr;
- switch (kindValue) {
- case R_ARM_JUMP24:
- veneer = static_cast<Derived *>(this)
- ->getVeneer_ARM_B_BL(target, secName);
- break;
- case R_ARM_THM_JUMP24:
- veneer = static_cast<Derived *>(this)
- ->getVeneer_THM_B_BL(target, secName);
- break;
- default:
- llvm_unreachable("Unhandled reference type for veneer generation");
- }
+ 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));
+ 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");
@@ -213,20 +508,160 @@ protected:
/// \brief Create a GOT entry for TLS with reloc type and addend specified.
template <Reference::KindValue R_ARM_TLS, Reference::Addend A = 0>
const GOTAtom *getGOTTLSEntry(const DefinedAtom *da) {
- auto got = _gotMap.find(da);
- if (got != _gotMap.end())
- return got->second;
- auto g = new (_file._alloc) ARMGOTAtom(_file, ".got");
- g->addReferenceELF_ARM(R_ARM_TLS, 0, da, A);
+ StringRef source;
#ifndef NDEBUG
- g->_name = "__got_tls_";
+ 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
- _gotMap[da] = g;
- _gotVector.push_back(g);
+ _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) {}
@@ -238,35 +673,35 @@ public:
///
/// After all references are handled, the atoms created during that are all
/// added to mf.
- void perform(std::unique_ptr<MutableFile> &mf) override {
+ 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()) {
+ : mf.undefined()) {
llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n";
}
llvm::dbgs() << "Shared Library Atoms" << "\n";
for (const auto &atom
- : mf->sharedLibrary()) {
+ : mf.sharedLibrary()) {
llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n";
}
llvm::dbgs() << "Absolute Atoms" << "\n";
for (const auto &atom
- : mf->absolute()) {
+ : mf.absolute()) {
llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n";
}
llvm::dbgs() << "Defined Atoms" << "\n";
for (const auto &atom
- : mf->defined()) {
+ : mf.defined()) {
llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n";
});
// Process all references.
- for (const auto &atom : mf->defined()) {
+ for (const auto &atom : mf.defined()) {
for (const auto &ref : *atom) {
handleReference(*atom, *ref);
}
@@ -274,14 +709,58 @@ public:
// Add all created atoms to the link.
uint64_t ordinal = 0;
- for (auto &got : _gotVector) {
+ 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);
+ 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 &veneer : _veneerVector) {
- veneer->setOrdinal(ordinal++);
- mf->addAtom(*veneer);
+ 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:
@@ -290,16 +769,56 @@ protected:
const ELFLinkingContext &_ctx;
/// \brief Map Atoms to their GOT entries.
- llvm::DenseMap<const Atom *, GOTAtom *> _gotMap;
+ llvm::MapVector<const Atom *, GOTAtom *> _gotAtoms;
- /// \brief Map Atoms to their veneers.
- llvm::DenseMap<const Atom *, VeneerAtom *> _veneerMap;
+ /// \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 the list of GOT/PLT atoms
- std::vector<GOTAtom *> _gotVector;
+ /// \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) {}
- /// \brief the list of veneer atoms.
- std::vector<VeneerAtom *> _veneerVector;
+ 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
@@ -314,47 +833,138 @@ 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) {
- auto veneer = _veneerMap.find(da);
- if (_veneerMap.end() != veneer)
- return veneer->second;
+ 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 v = new (_file._alloc) Veneer_ARM_B_BL_StaticAtom(_file, secName);
- v->addReferenceELF_ARM(R_ARM_ABS32, 4, da, 0);
+ auto oa = new (_file._alloc) ARMObjectAtom(_file);
+ oa->addReferenceELF_ARM(R_ARM_COPY, 0, oa, 0);
- v->_name = "__";
- v->_name += da->name();
- v->_name += "_from_arm";
+ oa->_name = a->name();
+ oa->_size = a->size();
+
+ _objectAtoms[a] = oa;
+ return oa;
+ }
- _veneerMap[da] = v;
- _veneerVector.push_back(v);
- return v;
+ /// \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) {
- auto veneer = _veneerMap.find(da);
- if (_veneerMap.end() != veneer)
- return veneer->second;
+ if (_ctx.getOutputELFType() == llvm::ELF::ET_EXEC) {
+ return getVeneer_THM_B_BL_Abs(da, secName);
+ }
+ llvm_unreachable("Handle Thumb veneer for DSOs");
+ }
- auto v = new (_file._alloc) Veneer_THM_B_BL_StaticAtom(_file, secName);
- v->addReferenceELF_ARM(R_ARM_JUMP24, 4, da, 0);
+ /// \brief Create a GOT entry for R_ARM_TLS_TPOFF32 reloc.
+ const GOTAtom *getTLSTPOFF32(const DefinedAtom *da) {
+ return getGOTTLSEntry<R_ARM_TLS_TPOFF32>(da);
+ }
- v->_name = "__";
- v->_name += da->name();
- v->_name += "_from_thumb";
+ 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;
+ }
- _veneerMap[da] = v;
- _veneerVector.push_back(v);
- return v;
+ const GOTAtom *getSharedGOTEntry(const SharedLibraryAtom *sla) {
+ return getGOT<R_ARM_GLOB_DAT>(sla);
}
- /// \brief Create a GOT entry for R_ARM_TLS_TPOFF32 reloc.
- const GOTAtom *getTLSTPOFF32(const DefinedAtom *da) {
- return getGOTTLSEntry<R_ARM_TLS_LE32>(da);
+ 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);
}
};
@@ -365,8 +975,10 @@ lld::elf::createARMRelocationPass(const ARMLinkingContext &ctx) {
switch (ctx.getOutputELFType()) {
case llvm::ELF::ET_EXEC:
if (ctx.isDynamic())
- llvm_unreachable("Unhandled output file type");
+ 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/lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h b/lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h
index 540a480421a8..85b9c9162589 100644
--- a/lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h
+++ b/lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h
@@ -10,34 +10,47 @@
#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
-template<class ELFT>
-class ARMSymbolTable : public SymbolTable<ELFT> {
+class ARMSymbolTable : public SymbolTable<ELF32LE> {
public:
- typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+ typedef llvm::object::Elf_Sym_Impl<ELF32LE> Elf_Sym;
- ARMSymbolTable(const ELFLinkingContext &context);
+ ARMSymbolTable(const ELFLinkingContext &ctx);
void addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
int64_t addr) override;
};
-template <class ELFT>
-ARMSymbolTable<ELFT>::ARMSymbolTable(const ELFLinkingContext &context)
- : SymbolTable<ELFT>(context, ".symtab",
- DefaultLayout<ELFT>::ORDER_SYMBOL_TABLE) {}
+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);
-template <class ELFT>
-void ARMSymbolTable<ELFT>::addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
- int64_t addr) {
- SymbolTable<ELFT>::addDefinedAtom(sym, da, addr);
+ if ((ARMELFDefinedAtom::ARMContentType)da->contentType() ==
+ ARMELFDefinedAtom::typeARMExidx)
+ sym.st_value = addr;
- // Set zero bit to distinguish symbols addressing Thumb instructions
+ // 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
diff --git a/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp b/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp
index de90f490f621..e1f5eadbe789 100644
--- a/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp
+++ b/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp
@@ -9,36 +9,24 @@
#include "Atoms.h"
#include "ARMExecutableWriter.h"
+#include "ARMDynamicLibraryWriter.h"
#include "ARMTargetHandler.h"
#include "ARMLinkingContext.h"
using namespace lld;
using namespace elf;
-ARMTargetHandler::ARMTargetHandler(ARMLinkingContext &context)
- : _context(context), _armTargetLayout(
- new ARMTargetLayout<ARMELFType>(context)),
- _armRelocationHandler(new ARMTargetRelocationHandler(
- *_armTargetLayout.get())) {}
-
-void ARMTargetHandler::registerRelocationNames(Registry &registry) {
- registry.addKindTable(Reference::KindNamespace::ELF, Reference::KindArch::ARM,
- kindStrings);
-}
+ARMTargetHandler::ARMTargetHandler(ARMLinkingContext &ctx)
+ : _ctx(ctx), _targetLayout(new ARMTargetLayout(ctx)),
+ _relocationHandler(new ARMTargetRelocationHandler(*_targetLayout)) {}
std::unique_ptr<Writer> ARMTargetHandler::getWriter() {
- switch (this->_context.getOutputELFType()) {
+ switch (this->_ctx.getOutputELFType()) {
case llvm::ELF::ET_EXEC:
- return std::unique_ptr<Writer>(
- new ARMExecutableWriter<ARMELFType>(_context, *_armTargetLayout.get()));
+ 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");
}
}
-
-#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name),
-
-const Registry::KindStrings ARMTargetHandler::kindStrings[] = {
-#include "llvm/Support/ELFRelocs/ARM.def"
- LLD_KIND_STRING_END
-};
diff --git a/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h b/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h
index 10641954da25..0352e81a1f61 100644
--- a/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h
+++ b/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h
@@ -11,75 +11,161 @@
#define LLD_READER_WRITER_ELF_ARM_ARM_TARGET_HANDLER_H
#include "ARMELFFile.h"
-#include "ARMELFReader.h"
#include "ARMRelocationHandler.h"
-#include "DefaultTargetHandler.h"
+#include "ELFReader.h"
#include "TargetLayout.h"
-#include "lld/Core/Simple.h"
-#include "llvm/ADT/Optional.h"
-#include <map>
-
namespace lld {
+class ELFLinkingContext;
+
namespace elf {
-typedef llvm::object::ELFType<llvm::support::little, 2, false> ARMELFType;
-class ARMLinkingContext;
-template <class ELFT> class ARMTargetLayout : public TargetLayout<ELFT> {
+/// \brief ARM specific section (.ARM.exidx) with indexes to exception handlers
+class ARMExidxSection : public AtomSection<ELF32LE> {
+ typedef AtomSection<ELF32LE> Base;
+
public:
- ARMTargetLayout(ARMLinkingContext &context)
- : TargetLayout<ELFT>(context) {}
+ 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;
+ }
- uint64_t getTPOffset() {
- if (_tpOff.hasValue())
- return *_tpOff;
+ bool hasOutputSegment() const override { return true; }
- for (const auto &phdr : *this->_programHeader) {
- if (phdr->p_type == llvm::ELF::PT_TLS) {
- _tpOff = llvm::RoundUpToAlignment(TCB_SIZE, phdr->p_align);
- return *_tpOff;
- }
+ 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);
}
- llvm_unreachable("TLS segment not found");
}
+ 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::RoundUpToAlignment(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 };
- // Cached value of the TLS offset from the $tp pointer.
- llvm::Optional<uint64_t> _tpOff;
+private:
+ uint64_t _gotSymAddr = 0;
+ uint64_t _tpOff = 0;
+ std::once_flag _gotSymOnce;
+ std::once_flag _tpOffOnce;
};
-class ARMTargetHandler final : public DefaultTargetHandler<ARMELFType> {
+class ARMTargetHandler final : public TargetHandler {
public:
- ARMTargetHandler(ARMLinkingContext &context);
-
- ARMTargetLayout<ARMELFType> &getTargetLayout() override {
- return *(_armTargetLayout.get());
- }
-
- void registerRelocationNames(Registry &registry) override;
+ ARMTargetHandler(ARMLinkingContext &ctx);
- const ARMTargetRelocationHandler &getRelocationHandler() const override {
- return *(_armRelocationHandler.get());
+ const TargetRelocationHandler &getRelocationHandler() const override {
+ return *_relocationHandler;
}
std::unique_ptr<Reader> getObjReader() override {
- return std::unique_ptr<Reader>(new ARMELFObjectReader(_context));
+ return llvm::make_unique<ELFReader<ARMELFFile>>(_ctx);
}
std::unique_ptr<Reader> getDSOReader() override {
- return std::unique_ptr<Reader>(new ARMELFDSOReader(_context));
+ return llvm::make_unique<ELFReader<DynamicFile<ELF32LE>>>(_ctx);
}
std::unique_ptr<Writer> getWriter() override;
private:
- static const Registry::KindStrings kindStrings[];
- ARMLinkingContext &_context;
- std::unique_ptr<ARMTargetLayout<ARMELFType>> _armTargetLayout;
- std::unique_ptr<ARMTargetRelocationHandler> _armRelocationHandler;
+ ARMLinkingContext &_ctx;
+ std::unique_ptr<ARMTargetLayout> _targetLayout;
+ std::unique_ptr<ARMTargetRelocationHandler> _relocationHandler;
};
} // end namespace elf
diff --git a/lib/ReaderWriter/ELF/ARM/Makefile b/lib/ReaderWriter/ELF/ARM/Makefile
deleted file mode 100644
index f67d36a1b612..000000000000
--- a/lib/ReaderWriter/ELF/ARM/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-##===------ lld/lib/ReaderWriter/ELF/ARM/Makefile ----------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LLD_LEVEL := ../../../..
-LIBRARYNAME := lldARMELFTarget
-USEDLIBS = lldCore.a
-CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF/ARM -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF
-
-include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/ELF/ARM/TODO.rst b/lib/ReaderWriter/ELF/ARM/TODO.rst
index d05419decb78..61b585ae698c 100644
--- a/lib/ReaderWriter/ELF/ARM/TODO.rst
+++ b/lib/ReaderWriter/ELF/ARM/TODO.rst
@@ -4,14 +4,15 @@ ELF ARM
Unimplemented Features
######################
-* Static executable linking - in progress
-* Dynamic executable linking
* DSO linking
-* PLT entries' generation for images larger than 2^28 bytes (see Sec. A.3 of the ELF reference)
-* ARM and Thumb interworking (see http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0203j/Bcghfebi.html)
-* .ARM.exidx section handling
+* 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
-* Lots of relocations
+* Proper debug information (DWARF data)
+* TLS relocations for dynamic models
+* Lots of other relocations
Unimplemented Relocations
#########################