summaryrefslogtreecommitdiff
path: root/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp')
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp171
1 files changed, 151 insertions, 20 deletions
diff --git a/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp b/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp
index f60ab63c6af7..817e29444666 100644
--- a/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp
+++ b/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp
@@ -1,4 +1,4 @@
-//===- lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp --------------------===//
+//===- lib/ReaderWriter/ELF/Mips/MipsTargetHandler32EL.cpp ----------------===//
//
// The LLVM Linker
//
@@ -7,29 +7,160 @@
//
//===----------------------------------------------------------------------===//
+#include "ELFReader.h"
+#include "MipsELFFile.h"
+#include "MipsELFWriters.h"
#include "MipsTargetHandler.h"
-using namespace lld;
-using namespace elf;
+namespace lld {
+namespace elf {
-void MipsRelocationStringTable::registerTable(Registry &registry) {
- registry.addKindTable(Reference::KindNamespace::ELF,
- Reference::KindArch::Mips, kindStrings);
+template <class ELFT>
+MipsTargetHandler<ELFT>::MipsTargetHandler(MipsLinkingContext &ctx)
+ : _ctx(ctx), _targetLayout(new MipsTargetLayout<ELFT>(ctx, _abiInfoHandler)),
+ _relocationHandler(
+ createMipsRelocationHandler<ELFT>(ctx, *_targetLayout)) {}
+
+template <class ELFT>
+std::unique_ptr<Reader> MipsTargetHandler<ELFT>::getObjReader() {
+ return llvm::make_unique<ELFReader<MipsELFFile<ELFT>>>(_ctx);
+}
+
+template <class ELFT>
+std::unique_ptr<Reader> MipsTargetHandler<ELFT>::getDSOReader() {
+ return llvm::make_unique<ELFReader<DynamicFile<ELFT>>>(_ctx);
+}
+
+template <class ELFT>
+const TargetRelocationHandler &
+MipsTargetHandler<ELFT>::getRelocationHandler() const {
+ return *_relocationHandler;
+}
+
+template <class ELFT>
+std::unique_ptr<Writer> MipsTargetHandler<ELFT>::getWriter() {
+ switch (_ctx.getOutputELFType()) {
+ case llvm::ELF::ET_EXEC:
+ return llvm::make_unique<MipsExecutableWriter<ELFT>>(_ctx, *_targetLayout,
+ _abiInfoHandler);
+ case llvm::ELF::ET_DYN:
+ return llvm::make_unique<MipsDynamicLibraryWriter<ELFT>>(
+ _ctx, *_targetLayout, _abiInfoHandler);
+ case llvm::ELF::ET_REL:
+ llvm_unreachable("TODO: support -r mode");
+ default:
+ llvm_unreachable("unsupported output type");
+ }
+}
+
+template <class ELFT> MipsAbi MipsTargetHandler<ELFT>::getAbi() const {
+ return _abiInfoHandler.getAbi();
+}
+
+template class MipsTargetHandler<ELF32BE>;
+template class MipsTargetHandler<ELF32LE>;
+template class MipsTargetHandler<ELF64BE>;
+template class MipsTargetHandler<ELF64LE>;
+
+template <class ELFT>
+MipsSymbolTable<ELFT>::MipsSymbolTable(const ELFLinkingContext &ctx)
+ : SymbolTable<ELFT>(ctx, ".symtab",
+ TargetLayout<ELFT>::ORDER_SYMBOL_TABLE) {}
+
+template <class ELFT>
+void MipsSymbolTable<ELFT>::addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
+ int64_t addr) {
+ SymbolTable<ELFT>::addDefinedAtom(sym, da, addr);
+
+ switch (da->codeModel()) {
+ case DefinedAtom::codeMipsMicro:
+ sym.st_other |= llvm::ELF::STO_MIPS_MICROMIPS;
+ break;
+ case DefinedAtom::codeMipsMicroPIC:
+ sym.st_other |= llvm::ELF::STO_MIPS_MICROMIPS | llvm::ELF::STO_MIPS_PIC;
+ break;
+ default:
+ break;
+ }
}
-#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name),
+template <class ELFT> void MipsSymbolTable<ELFT>::finalize(bool sort) {
+ SymbolTable<ELFT>::finalize(sort);
-const Registry::KindStrings MipsRelocationStringTable::kindStrings[] = {
-#include "llvm/Support/ELFRelocs/Mips.def"
- LLD_KIND_STRING_ENTRY(LLD_R_MIPS_GLOBAL_GOT),
- LLD_KIND_STRING_ENTRY(LLD_R_MIPS_32_HI16),
- LLD_KIND_STRING_ENTRY(LLD_R_MIPS_64_HI16),
- LLD_KIND_STRING_ENTRY(LLD_R_MIPS_GLOBAL_26),
- LLD_KIND_STRING_ENTRY(LLD_R_MIPS_HI16),
- LLD_KIND_STRING_ENTRY(LLD_R_MIPS_LO16),
- LLD_KIND_STRING_ENTRY(LLD_R_MIPS_STO_PLT),
- LLD_KIND_STRING_ENTRY(LLD_R_MICROMIPS_GLOBAL_26_S1),
- LLD_KIND_STRING_END
-};
+ for (auto &ste : this->_symbolTable) {
+ if (!ste._atom)
+ continue;
+ if (const auto *da = dyn_cast<DefinedAtom>(ste._atom)) {
+ if (da->codeModel() == DefinedAtom::codeMipsMicro ||
+ da->codeModel() == DefinedAtom::codeMipsMicroPIC) {
+ // Adjust dynamic microMIPS symbol value. That allows a dynamic
+ // linker to recognize and handle this symbol correctly.
+ ste._symbol.st_value = ste._symbol.st_value | 1;
+ }
+ }
+ }
+}
+
+template class MipsSymbolTable<ELF32BE>;
+template class MipsSymbolTable<ELF32LE>;
+template class MipsSymbolTable<ELF64BE>;
+template class MipsSymbolTable<ELF64LE>;
+
+template <class ELFT>
+MipsDynamicSymbolTable<ELFT>::MipsDynamicSymbolTable(
+ const ELFLinkingContext &ctx, MipsTargetLayout<ELFT> &layout)
+ : DynamicSymbolTable<ELFT>(ctx, layout, ".dynsym",
+ TargetLayout<ELFT>::ORDER_DYNAMIC_SYMBOLS),
+ _targetLayout(layout) {}
+
+template <class ELFT> void MipsDynamicSymbolTable<ELFT>::sortSymbols() {
+ typedef typename DynamicSymbolTable<ELFT>::SymbolEntry SymbolEntry;
+ std::stable_sort(this->_symbolTable.begin(), this->_symbolTable.end(),
+ [this](const SymbolEntry &A, const SymbolEntry &B) {
+ if (A._symbol.getBinding() != STB_GLOBAL &&
+ B._symbol.getBinding() != STB_GLOBAL)
+ return A._symbol.getBinding() < B._symbol.getBinding();
+
+ return _targetLayout.getGOTSection().compare(A._atom,
+ B._atom);
+ });
+}
+
+template <class ELFT> void MipsDynamicSymbolTable<ELFT>::finalize() {
+ DynamicSymbolTable<ELFT>::finalize();
-#undef ELF_RELOC
+ const auto &pltSection = _targetLayout.getPLTSection();
+
+ for (auto &ste : this->_symbolTable) {
+ const Atom *a = ste._atom;
+ if (!a)
+ continue;
+ if (auto *layout = pltSection.findPLTLayout(a)) {
+ a = layout->_atom;
+ // Under some conditions a dynamic symbol table record should hold
+ // a symbol value of the corresponding PLT entry. For details look
+ // at the PLT entry creation code in the class MipsRelocationPass.
+ // Let's update atomLayout fields for such symbols.
+ assert(!ste._atomLayout);
+ ste._symbol.st_value = layout->_virtualAddr;
+ ste._symbol.st_other |= ELF::STO_MIPS_PLT;
+ }
+
+ if (const auto *da = dyn_cast<DefinedAtom>(a)) {
+ if (da->codeModel() == DefinedAtom::codeMipsMicro ||
+ da->codeModel() == DefinedAtom::codeMipsMicroPIC) {
+ // Adjust dynamic microMIPS symbol value. That allows a dynamic
+ // linker to recognize and handle this symbol correctly.
+ ste._symbol.st_value = ste._symbol.st_value | 1;
+ }
+ }
+ }
+}
+
+template class MipsDynamicSymbolTable<ELF32BE>;
+template class MipsDynamicSymbolTable<ELF32LE>;
+template class MipsDynamicSymbolTable<ELF64BE>;
+template class MipsDynamicSymbolTable<ELF64LE>;
+
+}
+}