forked from OSchip/llvm-project
[Mips] Move member function definitions to cpp files
No functional changes. llvm-svn: 238310
This commit is contained in:
parent
729dcfb7ee
commit
06eccbea9d
|
@ -1,11 +1,14 @@
|
|||
add_llvm_library(lldMipsELFTarget
|
||||
MipsCtorsOrderPass.cpp
|
||||
MipsELFFile.cpp
|
||||
MipsELFFlagsMerger.cpp
|
||||
MipsELFWriters.cpp
|
||||
MipsLinkingContext.cpp
|
||||
MipsRelocationHandler.cpp
|
||||
MipsRelocationPass.cpp
|
||||
MipsTargetHandler32EL.cpp
|
||||
MipsTargetHandler64EL.cpp
|
||||
MipsSectionChunks.cpp
|
||||
MipsTargetHandler.cpp
|
||||
MipsTargetLayout.cpp
|
||||
LINK_LIBS
|
||||
lldELF
|
||||
lldReaderWriter
|
||||
|
|
|
@ -1,117 +0,0 @@
|
|||
//===- lib/ReaderWriter/ELF/Mips/MipsDynamicLibraryWriter.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_MIPS_MIPS_DYNAMIC_LIBRARY_WRITER_H
|
||||
#define LLD_READER_WRITER_ELF_MIPS_MIPS_DYNAMIC_LIBRARY_WRITER_H
|
||||
|
||||
#include "DynamicLibraryWriter.h"
|
||||
#include "MipsDynamicTable.h"
|
||||
#include "MipsELFWriters.h"
|
||||
#include "MipsLinkingContext.h"
|
||||
#include "MipsSectionChunks.h"
|
||||
|
||||
namespace lld {
|
||||
namespace elf {
|
||||
|
||||
template <typename ELFT> class MipsSymbolTable;
|
||||
template <typename ELFT> class MipsDynamicSymbolTable;
|
||||
template <typename ELFT> class MipsTargetLayout;
|
||||
|
||||
template <class ELFT>
|
||||
class MipsDynamicLibraryWriter : public DynamicLibraryWriter<ELFT> {
|
||||
public:
|
||||
MipsDynamicLibraryWriter(MipsLinkingContext &ctx,
|
||||
MipsTargetLayout<ELFT> &layout);
|
||||
|
||||
protected:
|
||||
// Add any runtime files and their atoms to the output
|
||||
void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
|
||||
|
||||
void finalizeDefaultAtomValues() override;
|
||||
void createDefaultSections() override;
|
||||
|
||||
std::error_code setELFHeader() override {
|
||||
DynamicLibraryWriter<ELFT>::setELFHeader();
|
||||
_writeHelper.setELFHeader(*this->_elfHeader);
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
unique_bump_ptr<SymbolTable<ELFT>> createSymbolTable() override;
|
||||
unique_bump_ptr<DynamicTable<ELFT>> createDynamicTable() override;
|
||||
unique_bump_ptr<DynamicSymbolTable<ELFT>> createDynamicSymbolTable() override;
|
||||
|
||||
private:
|
||||
MipsELFWriter<ELFT> _writeHelper;
|
||||
MipsTargetLayout<ELFT> &_targetLayout;
|
||||
unique_bump_ptr<Section<ELFT>> _reginfo;
|
||||
};
|
||||
|
||||
template <class ELFT>
|
||||
MipsDynamicLibraryWriter<ELFT>::MipsDynamicLibraryWriter(
|
||||
MipsLinkingContext &ctx, MipsTargetLayout<ELFT> &layout)
|
||||
: DynamicLibraryWriter<ELFT>(ctx, layout), _writeHelper(ctx, layout),
|
||||
_targetLayout(layout) {}
|
||||
|
||||
template <class ELFT>
|
||||
void MipsDynamicLibraryWriter<ELFT>::createImplicitFiles(
|
||||
std::vector<std::unique_ptr<File>> &result) {
|
||||
DynamicLibraryWriter<ELFT>::createImplicitFiles(result);
|
||||
result.push_back(_writeHelper.createRuntimeFile());
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void MipsDynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues() {
|
||||
// Finalize the atom values that are part of the parent.
|
||||
DynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues();
|
||||
_writeHelper.finalizeMipsRuntimeAtomValues();
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void MipsDynamicLibraryWriter<ELFT>::createDefaultSections() {
|
||||
DynamicLibraryWriter<ELFT>::createDefaultSections();
|
||||
const auto &ctx = static_cast<const MipsLinkingContext &>(this->_ctx);
|
||||
const auto &mask = ctx.getMergedReginfoMask();
|
||||
if (!mask.hasValue())
|
||||
return;
|
||||
if (ELFT::Is64Bits)
|
||||
_reginfo = unique_bump_ptr<Section<ELFT>>(
|
||||
new (this->_alloc) MipsOptionsSection<ELFT>(ctx, _targetLayout, *mask));
|
||||
else
|
||||
_reginfo = unique_bump_ptr<Section<ELFT>>(
|
||||
new (this->_alloc) MipsReginfoSection<ELFT>(ctx, _targetLayout, *mask));
|
||||
this->_layout.addSection(_reginfo.get());
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
unique_bump_ptr<SymbolTable<ELFT>>
|
||||
MipsDynamicLibraryWriter<ELFT>::createSymbolTable() {
|
||||
return unique_bump_ptr<SymbolTable<ELFT>>(
|
||||
new (this->_alloc) MipsSymbolTable<ELFT>(this->_ctx));
|
||||
}
|
||||
|
||||
/// \brief create dynamic table
|
||||
template <class ELFT>
|
||||
unique_bump_ptr<DynamicTable<ELFT>>
|
||||
MipsDynamicLibraryWriter<ELFT>::createDynamicTable() {
|
||||
return unique_bump_ptr<DynamicTable<ELFT>>(
|
||||
new (this->_alloc) MipsDynamicTable<ELFT>(this->_ctx, _targetLayout));
|
||||
}
|
||||
|
||||
/// \brief create dynamic symbol table
|
||||
template <class ELFT>
|
||||
unique_bump_ptr<DynamicSymbolTable<ELFT>>
|
||||
MipsDynamicLibraryWriter<ELFT>::createDynamicSymbolTable() {
|
||||
return unique_bump_ptr<DynamicSymbolTable<ELFT>>(
|
||||
new (this->_alloc)
|
||||
MipsDynamicSymbolTable<ELFT>(this->_ctx, _targetLayout));
|
||||
}
|
||||
|
||||
} // namespace elf
|
||||
} // namespace lld
|
||||
|
||||
#endif
|
|
@ -0,0 +1,284 @@
|
|||
//===- lib/ReaderWriter/ELF/MipsELFFile.cpp -------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "MipsELFFile.h"
|
||||
|
||||
namespace lld {
|
||||
namespace elf {
|
||||
|
||||
template <class ELFT>
|
||||
MipsELFDefinedAtom<ELFT>::MipsELFDefinedAtom(
|
||||
const MipsELFFile<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) {}
|
||||
|
||||
template <class ELFT>
|
||||
const MipsELFFile<ELFT> &MipsELFDefinedAtom<ELFT>::file() const {
|
||||
return static_cast<const MipsELFFile<ELFT> &>(this->_owningFile);
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
DefinedAtom::CodeModel MipsELFDefinedAtom<ELFT>::codeModel() const {
|
||||
switch (this->_symbol->st_other & llvm::ELF::STO_MIPS_MIPS16) {
|
||||
case llvm::ELF::STO_MIPS_MIPS16:
|
||||
return DefinedAtom::codeMips16;
|
||||
case llvm::ELF::STO_MIPS_PIC:
|
||||
return DefinedAtom::codeMipsPIC;
|
||||
case llvm::ELF::STO_MIPS_MICROMIPS:
|
||||
return DefinedAtom::codeMipsMicro;
|
||||
case llvm::ELF::STO_MIPS_MICROMIPS | llvm::ELF::STO_MIPS_PIC:
|
||||
return DefinedAtom::codeMipsMicroPIC;
|
||||
default:
|
||||
return DefinedAtom::codeNA;
|
||||
}
|
||||
}
|
||||
|
||||
template class MipsELFDefinedAtom<ELF32LE>;
|
||||
template class MipsELFDefinedAtom<ELF64LE>;
|
||||
|
||||
template <class ELFT> static bool isMips64EL() {
|
||||
return ELFT::Is64Bits && ELFT::TargetEndianness == llvm::support::little;
|
||||
}
|
||||
|
||||
template <class ELFT, bool isRela>
|
||||
static uint32_t
|
||||
extractTag(const llvm::object::Elf_Rel_Impl<ELFT, isRela> &rel) {
|
||||
return (rel.getType(isMips64EL<ELFT>()) & 0xffffff00) >> 8;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
MipsELFReference<ELFT>::MipsELFReference(uint64_t symValue, const Elf_Rela &rel)
|
||||
: ELFReference<ELFT>(&rel, rel.r_offset - symValue,
|
||||
Reference::KindArch::Mips,
|
||||
rel.getType(isMips64EL<ELFT>()) & 0xff,
|
||||
rel.getSymbol(isMips64EL<ELFT>())),
|
||||
_tag(extractTag(rel)) {}
|
||||
|
||||
template <class ELFT>
|
||||
MipsELFReference<ELFT>::MipsELFReference(uint64_t symValue, const Elf_Rel &rel)
|
||||
: ELFReference<ELFT>(rel.r_offset - symValue, Reference::KindArch::Mips,
|
||||
rel.getType(isMips64EL<ELFT>()) & 0xff,
|
||||
rel.getSymbol(isMips64EL<ELFT>())),
|
||||
_tag(extractTag(rel)) {}
|
||||
|
||||
template class MipsELFReference<ELF32LE>;
|
||||
template class MipsELFReference<ELF64LE>;
|
||||
|
||||
template <class ELFT>
|
||||
MipsELFFile<ELFT>::MipsELFFile(std::unique_ptr<MemoryBuffer> mb,
|
||||
ELFLinkingContext &ctx)
|
||||
: ELFFile<ELFT>(std::move(mb), ctx) {}
|
||||
|
||||
template <class ELFT> bool MipsELFFile<ELFT>::isPIC() const {
|
||||
return this->_objFile->getHeader()->e_flags & llvm::ELF::EF_MIPS_PIC;
|
||||
}
|
||||
|
||||
template <class ELFT> std::error_code MipsELFFile<ELFT>::doParse() {
|
||||
if (std::error_code ec = ELFFile<ELFT>::doParse())
|
||||
return ec;
|
||||
// Retrieve some auxiliary data like GP value, TLS section address etc
|
||||
// from the object file.
|
||||
return readAuxData();
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
ELFDefinedAtom<ELFT> *MipsELFFile<ELFT>::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<ELFT> *> &referenceList) {
|
||||
return new (this->_readerStorage) MipsELFDefinedAtom<ELFT>(
|
||||
*this, symName, sectionName, sym, sectionHdr, contentData, referenceStart,
|
||||
referenceEnd, referenceList);
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
const typename MipsELFFile<ELFT>::Elf_Shdr *
|
||||
MipsELFFile<ELFT>::findSectionByType(uint64_t type) const {
|
||||
for (const Elf_Shdr §ion : this->_objFile->sections())
|
||||
if (section.sh_type == type)
|
||||
return §ion;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
const typename MipsELFFile<ELFT>::Elf_Shdr *
|
||||
MipsELFFile<ELFT>::findSectionByFlags(uint64_t flags) const {
|
||||
for (const Elf_Shdr §ion : this->_objFile->sections())
|
||||
if (section.sh_flags & flags)
|
||||
return §ion;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
ErrorOr<const typename MipsELFFile<ELFT>::Elf_Mips_RegInfo *>
|
||||
MipsELFFile<ELFT>::findRegInfoSec() const {
|
||||
using namespace llvm::ELF;
|
||||
if (const Elf_Shdr *sec = findSectionByType(SHT_MIPS_OPTIONS)) {
|
||||
auto contents = this->getSectionContents(sec);
|
||||
if (std::error_code ec = contents.getError())
|
||||
return ec;
|
||||
|
||||
ArrayRef<uint8_t> raw = contents.get();
|
||||
while (!raw.empty()) {
|
||||
if (raw.size() < sizeof(Elf_Mips_Options))
|
||||
return make_dynamic_error_code(
|
||||
StringRef("Invalid size of MIPS_OPTIONS section"));
|
||||
|
||||
const auto *opt = reinterpret_cast<const Elf_Mips_Options *>(raw.data());
|
||||
if (opt->kind == ODK_REGINFO)
|
||||
return &opt->getRegInfo();
|
||||
raw = raw.slice(opt->size);
|
||||
}
|
||||
} else if (const Elf_Shdr *sec = findSectionByType(SHT_MIPS_REGINFO)) {
|
||||
auto contents = this->getSectionContents(sec);
|
||||
if (std::error_code ec = contents.getError())
|
||||
return ec;
|
||||
|
||||
ArrayRef<uint8_t> raw = contents.get();
|
||||
if (raw.size() != sizeof(Elf_Mips_RegInfo))
|
||||
return make_dynamic_error_code(
|
||||
StringRef("Invalid size of MIPS_REGINFO section"));
|
||||
|
||||
return reinterpret_cast<const Elf_Mips_RegInfo *>(raw.data());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <class ELFT> std::error_code MipsELFFile<ELFT>::readAuxData() {
|
||||
using namespace llvm::ELF;
|
||||
if (const Elf_Shdr *sec = findSectionByFlags(SHF_TLS)) {
|
||||
_tpOff = sec->sh_addr + TP_OFFSET;
|
||||
_dtpOff = sec->sh_addr + DTP_OFFSET;
|
||||
}
|
||||
|
||||
auto &ctx = static_cast<MipsLinkingContext &>(this->_ctx);
|
||||
|
||||
ErrorOr<const Elf_Mips_RegInfo *> regInfoSec = findRegInfoSec();
|
||||
if (auto ec = regInfoSec.getError())
|
||||
return ec;
|
||||
if (const Elf_Mips_RegInfo *regInfo = regInfoSec.get()) {
|
||||
ctx.mergeReginfoMask(*regInfo);
|
||||
_gp0 = regInfo->ri_gp_value;
|
||||
}
|
||||
|
||||
const Elf_Ehdr *hdr = this->_objFile->getHeader();
|
||||
if (std::error_code ec = ctx.mergeElfFlags(hdr->e_flags))
|
||||
return ec;
|
||||
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void MipsELFFile<ELFT>::createRelocationReferences(const Elf_Sym *symbol,
|
||||
ArrayRef<uint8_t> content,
|
||||
range<Elf_Rela_Iter> rels) {
|
||||
const auto value = this->getSymbolValue(symbol);
|
||||
for (const auto &rel : rels) {
|
||||
if (rel.r_offset < value || value + content.size() <= rel.r_offset)
|
||||
continue;
|
||||
auto r = new (this->_readerStorage) MipsELFReference<ELFT>(value, rel);
|
||||
this->addReferenceToSymbol(r, symbol);
|
||||
this->_references.push_back(r);
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void MipsELFFile<ELFT>::createRelocationReferences(const Elf_Sym *symbol,
|
||||
ArrayRef<uint8_t> symContent,
|
||||
ArrayRef<uint8_t> secContent,
|
||||
range<Elf_Rel_Iter> rels) {
|
||||
const auto value = this->getSymbolValue(symbol);
|
||||
for (Elf_Rel_Iter rit = rels.begin(), eit = rels.end(); rit != eit; ++rit) {
|
||||
if (rit->r_offset < value || value + symContent.size() <= rit->r_offset)
|
||||
continue;
|
||||
|
||||
auto r = new (this->_readerStorage) MipsELFReference<ELFT>(value, *rit);
|
||||
this->addReferenceToSymbol(r, symbol);
|
||||
this->_references.push_back(r);
|
||||
|
||||
auto addend = readAddend(*rit, secContent);
|
||||
auto pairRelType = getPairRelocation(*rit);
|
||||
if (pairRelType != llvm::ELF::R_MIPS_NONE) {
|
||||
addend <<= 16;
|
||||
auto mit = findMatchingRelocation(pairRelType, rit, eit);
|
||||
if (mit != eit)
|
||||
addend += int16_t(readAddend(*mit, secContent));
|
||||
else
|
||||
// FIXME (simon): Show detailed warning.
|
||||
llvm::errs() << "lld warning: cannot matching LO16 relocation\n";
|
||||
}
|
||||
this->_references.back()->setAddend(addend);
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
static uint8_t
|
||||
getPrimaryType(const llvm::object::Elf_Rel_Impl<ELFT, false> &rel) {
|
||||
return rel.getType(isMips64EL<ELFT>()) & 0xff;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
Reference::Addend
|
||||
MipsELFFile<ELFT>::readAddend(const Elf_Rel &ri,
|
||||
const ArrayRef<uint8_t> content) const {
|
||||
return readMipsRelocAddend(getPrimaryType(ri), content.data() + ri.r_offset);
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
uint32_t MipsELFFile<ELFT>::getPairRelocation(const Elf_Rel &rel) const {
|
||||
switch (getPrimaryType(rel)) {
|
||||
case llvm::ELF::R_MIPS_HI16:
|
||||
return llvm::ELF::R_MIPS_LO16;
|
||||
case llvm::ELF::R_MIPS_PCHI16:
|
||||
return llvm::ELF::R_MIPS_PCLO16;
|
||||
case llvm::ELF::R_MIPS_GOT16:
|
||||
if (isLocalBinding(rel))
|
||||
return llvm::ELF::R_MIPS_LO16;
|
||||
break;
|
||||
case llvm::ELF::R_MICROMIPS_HI16:
|
||||
return llvm::ELF::R_MICROMIPS_LO16;
|
||||
case llvm::ELF::R_MICROMIPS_GOT16:
|
||||
if (isLocalBinding(rel))
|
||||
return llvm::ELF::R_MICROMIPS_LO16;
|
||||
break;
|
||||
default:
|
||||
// Nothing to do.
|
||||
break;
|
||||
}
|
||||
return llvm::ELF::R_MIPS_NONE;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
typename MipsELFFile<ELFT>::Elf_Rel_Iter
|
||||
MipsELFFile<ELFT>::findMatchingRelocation(uint32_t pairRelType,
|
||||
Elf_Rel_Iter rit,
|
||||
Elf_Rel_Iter eit) const {
|
||||
return std::find_if(rit, eit, [&](const Elf_Rel &rel) {
|
||||
return getPrimaryType(rel) == pairRelType &&
|
||||
rel.getSymbol(isMips64EL<ELFT>()) ==
|
||||
rit->getSymbol(isMips64EL<ELFT>());
|
||||
});
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
bool MipsELFFile<ELFT>::isLocalBinding(const Elf_Rel &rel) const {
|
||||
return this->_objFile->getSymbol(rel.getSymbol(isMips64EL<ELFT>()))
|
||||
->getBinding() == llvm::ELF::STB_LOCAL;
|
||||
}
|
||||
|
||||
template class MipsELFFile<ELF32LE>;
|
||||
template class MipsELFFile<ELF64LE>;
|
||||
|
||||
} // elf
|
||||
} // lld
|
|
@ -30,70 +30,32 @@ public:
|
|||
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) {}
|
||||
std::vector<ELFReference<ELFT> *> &referenceList);
|
||||
|
||||
const MipsELFFile<ELFT>& file() const override {
|
||||
return static_cast<const MipsELFFile<ELFT> &>(this->_owningFile);
|
||||
}
|
||||
|
||||
DefinedAtom::CodeModel codeModel() const override {
|
||||
switch (this->_symbol->st_other & llvm::ELF::STO_MIPS_MIPS16) {
|
||||
case llvm::ELF::STO_MIPS_MIPS16:
|
||||
return DefinedAtom::codeMips16;
|
||||
case llvm::ELF::STO_MIPS_PIC:
|
||||
return DefinedAtom::codeMipsPIC;
|
||||
case llvm::ELF::STO_MIPS_MICROMIPS:
|
||||
return DefinedAtom::codeMipsMicro;
|
||||
case llvm::ELF::STO_MIPS_MICROMIPS | llvm::ELF::STO_MIPS_PIC:
|
||||
return DefinedAtom::codeMipsMicroPIC;
|
||||
default:
|
||||
return DefinedAtom::codeNA;
|
||||
}
|
||||
}
|
||||
const MipsELFFile<ELFT>& file() const override;
|
||||
DefinedAtom::CodeModel codeModel() const override;
|
||||
};
|
||||
|
||||
template <class ELFT> class MipsELFReference : public ELFReference<ELFT> {
|
||||
typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel;
|
||||
typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela;
|
||||
|
||||
static const bool _isMips64EL =
|
||||
ELFT::Is64Bits && ELFT::TargetEndianness == llvm::support::little;
|
||||
|
||||
public:
|
||||
MipsELFReference(uint64_t symValue, const Elf_Rela &rel)
|
||||
: ELFReference<ELFT>(
|
||||
&rel, rel.r_offset - symValue, Reference::KindArch::Mips,
|
||||
rel.getType(_isMips64EL) & 0xff, rel.getSymbol(_isMips64EL)),
|
||||
_tag(extractTag(rel)) {}
|
||||
|
||||
MipsELFReference(uint64_t symValue, const Elf_Rel &rel)
|
||||
: ELFReference<ELFT>(rel.r_offset - symValue, Reference::KindArch::Mips,
|
||||
rel.getType(_isMips64EL) & 0xff,
|
||||
rel.getSymbol(_isMips64EL)),
|
||||
_tag(extractTag(rel)) {}
|
||||
MipsELFReference(uint64_t symValue, const Elf_Rela &rel);
|
||||
MipsELFReference(uint64_t symValue, const Elf_Rel &rel);
|
||||
|
||||
uint32_t tag() const override { return _tag; }
|
||||
void setTag(uint32_t tag) { _tag = tag; }
|
||||
|
||||
private:
|
||||
uint32_t _tag;
|
||||
|
||||
template <class R> static uint32_t extractTag(const R &rel) {
|
||||
return (rel.getType(_isMips64EL) & 0xffffff00) >> 8;
|
||||
}
|
||||
};
|
||||
|
||||
template <class ELFT> class MipsELFFile : public ELFFile<ELFT> {
|
||||
public:
|
||||
MipsELFFile(std::unique_ptr<MemoryBuffer> mb, ELFLinkingContext &ctx)
|
||||
: ELFFile<ELFT>(std::move(mb), ctx) {}
|
||||
MipsELFFile(std::unique_ptr<MemoryBuffer> mb, ELFLinkingContext &ctx);
|
||||
|
||||
bool isPIC() const {
|
||||
return this->_objFile->getHeader()->e_flags & llvm::ELF::EF_MIPS_PIC;
|
||||
}
|
||||
bool isPIC() const;
|
||||
|
||||
/// \brief gp register value stored in the .reginfo section.
|
||||
int64_t getGP0() const { return _gp0; }
|
||||
|
@ -103,13 +65,7 @@ public:
|
|||
uint64_t getDTPOffset() const { return _dtpOff; }
|
||||
|
||||
protected:
|
||||
std::error_code doParse() override {
|
||||
if (std::error_code ec = ELFFile<ELFT>::doParse())
|
||||
return ec;
|
||||
// Retrieve some auxiliary data like GP value, TLS section address etc
|
||||
// from the object file.
|
||||
return readAuxData();
|
||||
}
|
||||
std::error_code doParse() override;
|
||||
|
||||
private:
|
||||
typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
|
||||
|
@ -120,9 +76,6 @@ private:
|
|||
|
||||
enum { TP_OFFSET = 0x7000, DTP_OFFSET = 0x8000 };
|
||||
|
||||
static const bool _isMips64EL =
|
||||
ELFT::Is64Bits && ELFT::TargetEndianness == llvm::support::little;
|
||||
|
||||
int64_t _gp0 = 0;
|
||||
uint64_t _tpOff = 0;
|
||||
uint64_t _dtpOff = 0;
|
||||
|
@ -132,173 +85,36 @@ private:
|
|||
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) MipsELFDefinedAtom<ELFT>(
|
||||
*this, symName, sectionName, sym, sectionHdr, contentData,
|
||||
referenceStart, referenceEnd, referenceList);
|
||||
}
|
||||
std::vector<ELFReference<ELFT> *> &referenceList) override;
|
||||
|
||||
const Elf_Shdr *findSectionByType(uint64_t type) const {
|
||||
for (const Elf_Shdr §ion : this->_objFile->sections())
|
||||
if (section.sh_type == type)
|
||||
return §ion;
|
||||
return nullptr;
|
||||
}
|
||||
void createRelocationReferences(const Elf_Sym *symbol,
|
||||
ArrayRef<uint8_t> content,
|
||||
range<Elf_Rela_Iter> rels) override;
|
||||
void createRelocationReferences(const Elf_Sym *symbol,
|
||||
ArrayRef<uint8_t> symContent,
|
||||
ArrayRef<uint8_t> secContent,
|
||||
range<Elf_Rel_Iter> rels) override;
|
||||
|
||||
const Elf_Shdr *findSectionByFlags(uint64_t flags) const {
|
||||
for (const Elf_Shdr §ion : this->_objFile->sections())
|
||||
if (section.sh_flags & flags)
|
||||
return §ion;
|
||||
return nullptr;
|
||||
}
|
||||
const Elf_Shdr *findSectionByType(uint64_t type) const;
|
||||
const Elf_Shdr *findSectionByFlags(uint64_t flags) const;
|
||||
|
||||
typedef typename llvm::object::ELFFile<ELFT>::Elf_Ehdr Elf_Ehdr;
|
||||
typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo;
|
||||
typedef llvm::object::Elf_Mips_Options<ELFT> Elf_Mips_Options;
|
||||
|
||||
ErrorOr<const Elf_Mips_RegInfo *> findRegInfoSec() const {
|
||||
using namespace llvm::ELF;
|
||||
if (const Elf_Shdr *sec = findSectionByType(SHT_MIPS_OPTIONS)) {
|
||||
auto contents = this->getSectionContents(sec);
|
||||
if (std::error_code ec = contents.getError())
|
||||
return ec;
|
||||
ErrorOr<const Elf_Mips_RegInfo *> findRegInfoSec() const;
|
||||
|
||||
ArrayRef<uint8_t> raw = contents.get();
|
||||
while (!raw.empty()) {
|
||||
if (raw.size() < sizeof(Elf_Mips_Options))
|
||||
return make_dynamic_error_code(
|
||||
StringRef("Invalid size of MIPS_OPTIONS section"));
|
||||
|
||||
const auto *opt =
|
||||
reinterpret_cast<const Elf_Mips_Options *>(raw.data());
|
||||
if (opt->kind == ODK_REGINFO)
|
||||
return &opt->getRegInfo();
|
||||
raw = raw.slice(opt->size);
|
||||
}
|
||||
} else if (const Elf_Shdr *sec = findSectionByType(SHT_MIPS_REGINFO)) {
|
||||
auto contents = this->getSectionContents(sec);
|
||||
if (std::error_code ec = contents.getError())
|
||||
return ec;
|
||||
|
||||
ArrayRef<uint8_t> raw = contents.get();
|
||||
if (raw.size() != sizeof(Elf_Mips_RegInfo))
|
||||
return make_dynamic_error_code(
|
||||
StringRef("Invalid size of MIPS_REGINFO section"));
|
||||
|
||||
return reinterpret_cast<const Elf_Mips_RegInfo *>(raw.data());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::error_code readAuxData() {
|
||||
using namespace llvm::ELF;
|
||||
if (const Elf_Shdr *sec = findSectionByFlags(SHF_TLS)) {
|
||||
_tpOff = sec->sh_addr + TP_OFFSET;
|
||||
_dtpOff = sec->sh_addr + DTP_OFFSET;
|
||||
}
|
||||
|
||||
auto &ctx = static_cast<MipsLinkingContext &>(this->_ctx);
|
||||
|
||||
ErrorOr<const Elf_Mips_RegInfo *> regInfoSec = findRegInfoSec();
|
||||
if (auto ec = regInfoSec.getError())
|
||||
return ec;
|
||||
if (const Elf_Mips_RegInfo *regInfo = regInfoSec.get()) {
|
||||
ctx.mergeReginfoMask(*regInfo);
|
||||
_gp0 = regInfo->ri_gp_value;
|
||||
}
|
||||
|
||||
const Elf_Ehdr *hdr = this->_objFile->getHeader();
|
||||
if (std::error_code ec = ctx.mergeElfFlags(hdr->e_flags))
|
||||
return ec;
|
||||
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
void createRelocationReferences(const Elf_Sym *symbol,
|
||||
ArrayRef<uint8_t> content,
|
||||
range<Elf_Rela_Iter> rels) override {
|
||||
const auto value = this->getSymbolValue(symbol);
|
||||
for (const auto &rel : rels) {
|
||||
if (rel.r_offset < value || value + content.size() <= rel.r_offset)
|
||||
continue;
|
||||
auto r = new (this->_readerStorage) MipsELFReference<ELFT>(value, rel);
|
||||
this->addReferenceToSymbol(r, symbol);
|
||||
this->_references.push_back(r);
|
||||
}
|
||||
}
|
||||
|
||||
void createRelocationReferences(const Elf_Sym *symbol,
|
||||
ArrayRef<uint8_t> symContent,
|
||||
ArrayRef<uint8_t> secContent,
|
||||
range<Elf_Rel_Iter> rels) override {
|
||||
const auto value = this->getSymbolValue(symbol);
|
||||
for (Elf_Rel_Iter rit = rels.begin(), eit = rels.end(); rit != eit; ++rit) {
|
||||
if (rit->r_offset < value || value + symContent.size() <= rit->r_offset)
|
||||
continue;
|
||||
|
||||
auto r = new (this->_readerStorage) MipsELFReference<ELFT>(value, *rit);
|
||||
this->addReferenceToSymbol(r, symbol);
|
||||
this->_references.push_back(r);
|
||||
|
||||
auto addend = readAddend(*rit, secContent);
|
||||
auto pairRelType = getPairRelocation(*rit);
|
||||
if (pairRelType != llvm::ELF::R_MIPS_NONE) {
|
||||
addend <<= 16;
|
||||
auto mit = findMatchingRelocation(pairRelType, rit, eit);
|
||||
if (mit != eit)
|
||||
addend += int16_t(readAddend(*mit, secContent));
|
||||
else
|
||||
// FIXME (simon): Show detailed warning.
|
||||
llvm::errs() << "lld warning: cannot matching LO16 relocation\n";
|
||||
}
|
||||
this->_references.back()->setAddend(addend);
|
||||
}
|
||||
}
|
||||
std::error_code readAuxData();
|
||||
|
||||
Reference::Addend readAddend(const Elf_Rel &ri,
|
||||
const ArrayRef<uint8_t> content) const {
|
||||
return readMipsRelocAddend(getPrimaryType(ri),
|
||||
content.data() + ri.r_offset);
|
||||
}
|
||||
const ArrayRef<uint8_t> content) const;
|
||||
|
||||
uint32_t getPairRelocation(const Elf_Rel &rel) const {
|
||||
switch (getPrimaryType(rel)) {
|
||||
case llvm::ELF::R_MIPS_HI16:
|
||||
return llvm::ELF::R_MIPS_LO16;
|
||||
case llvm::ELF::R_MIPS_PCHI16:
|
||||
return llvm::ELF::R_MIPS_PCLO16;
|
||||
case llvm::ELF::R_MIPS_GOT16:
|
||||
if (isLocalBinding(rel))
|
||||
return llvm::ELF::R_MIPS_LO16;
|
||||
break;
|
||||
case llvm::ELF::R_MICROMIPS_HI16:
|
||||
return llvm::ELF::R_MICROMIPS_LO16;
|
||||
case llvm::ELF::R_MICROMIPS_GOT16:
|
||||
if (isLocalBinding(rel))
|
||||
return llvm::ELF::R_MICROMIPS_LO16;
|
||||
break;
|
||||
default:
|
||||
// Nothing to do.
|
||||
break;
|
||||
}
|
||||
return llvm::ELF::R_MIPS_NONE;
|
||||
}
|
||||
uint32_t getPairRelocation(const Elf_Rel &rel) const;
|
||||
|
||||
Elf_Rel_Iter findMatchingRelocation(uint32_t pairRelType, Elf_Rel_Iter rit,
|
||||
Elf_Rel_Iter eit) const {
|
||||
return std::find_if(rit, eit, [&](const Elf_Rel &rel) {
|
||||
return getPrimaryType(rel) == pairRelType &&
|
||||
rel.getSymbol(_isMips64EL) == rit->getSymbol(_isMips64EL);
|
||||
});
|
||||
}
|
||||
Elf_Rel_Iter eit) const;
|
||||
|
||||
static uint8_t getPrimaryType(const Elf_Rel &rel) {
|
||||
return rel.getType(_isMips64EL) & 0xff;
|
||||
}
|
||||
bool isLocalBinding(const Elf_Rel &rel) const {
|
||||
return this->_objFile->getSymbol(rel.getSymbol(_isMips64EL))
|
||||
->getBinding() == llvm::ELF::STB_LOCAL;
|
||||
}
|
||||
bool isLocalBinding(const Elf_Rel &rel) const;
|
||||
};
|
||||
|
||||
} // elf
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//===- lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h -------------------===//
|
||||
//===- lib/ReaderWriter/ELF/Mips/MipsELFWriters.cpp -----------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
|
@ -6,43 +6,141 @@
|
|||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_EXECUTABLE_WRITER_H
|
||||
#define LLD_READER_WRITER_ELF_MIPS_MIPS_EXECUTABLE_WRITER_H
|
||||
|
||||
#include "ExecutableWriter.h"
|
||||
#include "MipsDynamicTable.h"
|
||||
#include "MipsELFWriters.h"
|
||||
#include "MipsLinkingContext.h"
|
||||
#include "MipsTargetHandler.h"
|
||||
#include "MipsTargetLayout.h"
|
||||
|
||||
namespace {
|
||||
class MipsDynamicAtom : public lld::elf::DynamicAtom {
|
||||
public:
|
||||
MipsDynamicAtom(const lld::File &f) : DynamicAtom(f) {}
|
||||
|
||||
ContentPermissions permissions() const override { return permR__; }
|
||||
};
|
||||
}
|
||||
|
||||
namespace lld {
|
||||
namespace elf {
|
||||
|
||||
template <typename ELFT> class MipsTargetLayout;
|
||||
template <class ELFT>
|
||||
MipsELFWriter<ELFT>::MipsELFWriter(MipsLinkingContext &ctx,
|
||||
MipsTargetLayout<ELFT> &targetLayout)
|
||||
: _ctx(ctx), _targetLayout(targetLayout) {}
|
||||
|
||||
template <class ELFT>
|
||||
class MipsExecutableWriter : public ExecutableWriter<ELFT> {
|
||||
public:
|
||||
MipsExecutableWriter(MipsLinkingContext &ctx, MipsTargetLayout<ELFT> &layout);
|
||||
void MipsELFWriter<ELFT>::setELFHeader(ELFHeader<ELFT> &elfHeader) {
|
||||
elfHeader.e_version(1);
|
||||
elfHeader.e_ident(llvm::ELF::EI_VERSION, llvm::ELF::EV_CURRENT);
|
||||
elfHeader.e_ident(llvm::ELF::EI_OSABI, llvm::ELF::ELFOSABI_NONE);
|
||||
if (_targetLayout.findOutputSection(".got.plt"))
|
||||
elfHeader.e_ident(llvm::ELF::EI_ABIVERSION, 1);
|
||||
else
|
||||
elfHeader.e_ident(llvm::ELF::EI_ABIVERSION, 0);
|
||||
|
||||
protected:
|
||||
void buildDynamicSymbolTable(const File &file) override;
|
||||
elfHeader.e_flags(_ctx.getMergedELFFlags());
|
||||
}
|
||||
|
||||
// Add any runtime files and their atoms to the output
|
||||
void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
|
||||
template <class ELFT>
|
||||
void MipsELFWriter<ELFT>::finalizeMipsRuntimeAtomValues() {
|
||||
if (!_ctx.isDynamic())
|
||||
return;
|
||||
|
||||
void finalizeDefaultAtomValues() override;
|
||||
void createDefaultSections() override;
|
||||
std::error_code setELFHeader() override;
|
||||
auto gotSection = _targetLayout.findOutputSection(".got");
|
||||
auto got = gotSection ? gotSection->virtualAddr() : 0;
|
||||
auto gp = gotSection ? got + _targetLayout.getGPOffset() : 0;
|
||||
|
||||
unique_bump_ptr<SymbolTable<ELFT>> createSymbolTable() override;
|
||||
unique_bump_ptr<DynamicTable<ELFT>> createDynamicTable() override;
|
||||
unique_bump_ptr<DynamicSymbolTable<ELFT>> createDynamicSymbolTable() override;
|
||||
setAtomValue("_gp", gp);
|
||||
setAtomValue("_gp_disp", gp);
|
||||
setAtomValue("__gnu_local_gp", gp);
|
||||
}
|
||||
|
||||
private:
|
||||
MipsELFWriter<ELFT> _writeHelper;
|
||||
MipsTargetLayout<ELFT> &_targetLayout;
|
||||
unique_bump_ptr<Section<ELFT>> _reginfo;
|
||||
};
|
||||
template <class ELFT>
|
||||
std::unique_ptr<RuntimeFile<ELFT>> MipsELFWriter<ELFT>::createRuntimeFile() {
|
||||
auto file = llvm::make_unique<RuntimeFile<ELFT>>(_ctx, "Mips runtime file");
|
||||
if (_ctx.isDynamic()) {
|
||||
file->addAbsoluteAtom("_gp");
|
||||
file->addAbsoluteAtom("_gp_disp");
|
||||
file->addAbsoluteAtom("__gnu_local_gp");
|
||||
file->addAtom(*new (file->allocator()) MipsDynamicAtom(*file));
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void MipsELFWriter<ELFT>::setAtomValue(StringRef name, uint64_t value) {
|
||||
AtomLayout *atom = _targetLayout.findAbsoluteAtom(name);
|
||||
assert(atom);
|
||||
atom->_virtualAddr = value;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
MipsDynamicLibraryWriter<ELFT>::MipsDynamicLibraryWriter(
|
||||
MipsLinkingContext &ctx, MipsTargetLayout<ELFT> &layout)
|
||||
: DynamicLibraryWriter<ELFT>(ctx, layout), _writeHelper(ctx, layout),
|
||||
_targetLayout(layout) {}
|
||||
|
||||
template <class ELFT>
|
||||
void MipsDynamicLibraryWriter<ELFT>::createImplicitFiles(
|
||||
std::vector<std::unique_ptr<File>> &result) {
|
||||
DynamicLibraryWriter<ELFT>::createImplicitFiles(result);
|
||||
result.push_back(_writeHelper.createRuntimeFile());
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void MipsDynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues() {
|
||||
DynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues();
|
||||
_writeHelper.finalizeMipsRuntimeAtomValues();
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void MipsDynamicLibraryWriter<ELFT>::createDefaultSections() {
|
||||
DynamicLibraryWriter<ELFT>::createDefaultSections();
|
||||
const auto &ctx = static_cast<const MipsLinkingContext &>(this->_ctx);
|
||||
const auto &mask = ctx.getMergedReginfoMask();
|
||||
if (!mask.hasValue())
|
||||
return;
|
||||
if (ELFT::Is64Bits)
|
||||
_reginfo = unique_bump_ptr<Section<ELFT>>(
|
||||
new (this->_alloc) MipsOptionsSection<ELFT>(ctx, _targetLayout, *mask));
|
||||
else
|
||||
_reginfo = unique_bump_ptr<Section<ELFT>>(
|
||||
new (this->_alloc) MipsReginfoSection<ELFT>(ctx, _targetLayout, *mask));
|
||||
this->_layout.addSection(_reginfo.get());
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
std::error_code MipsDynamicLibraryWriter<ELFT>::setELFHeader() {
|
||||
DynamicLibraryWriter<ELFT>::setELFHeader();
|
||||
_writeHelper.setELFHeader(*this->_elfHeader);
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
unique_bump_ptr<SymbolTable<ELFT>>
|
||||
MipsDynamicLibraryWriter<ELFT>::createSymbolTable() {
|
||||
return unique_bump_ptr<SymbolTable<ELFT>>(
|
||||
new (this->_alloc) MipsSymbolTable<ELFT>(this->_ctx));
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
unique_bump_ptr<DynamicTable<ELFT>>
|
||||
MipsDynamicLibraryWriter<ELFT>::createDynamicTable() {
|
||||
return unique_bump_ptr<DynamicTable<ELFT>>(
|
||||
new (this->_alloc) MipsDynamicTable<ELFT>(this->_ctx, _targetLayout));
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
unique_bump_ptr<DynamicSymbolTable<ELFT>>
|
||||
MipsDynamicLibraryWriter<ELFT>::createDynamicSymbolTable() {
|
||||
return unique_bump_ptr<DynamicSymbolTable<ELFT>>(new (
|
||||
this->_alloc) MipsDynamicSymbolTable<ELFT>(this->_ctx, _targetLayout));
|
||||
}
|
||||
|
||||
template class MipsDynamicLibraryWriter<ELF32LE>;
|
||||
template class MipsDynamicLibraryWriter<ELF64LE>;
|
||||
|
||||
template <class ELFT>
|
||||
MipsExecutableWriter<ELFT>::MipsExecutableWriter(MipsLinkingContext &ctx,
|
||||
|
@ -140,7 +238,7 @@ template <class ELFT> void MipsExecutableWriter<ELFT>::createDefaultSections() {
|
|||
|
||||
template <class ELFT>
|
||||
unique_bump_ptr<SymbolTable<ELFT>>
|
||||
MipsExecutableWriter<ELFT>::createSymbolTable() {
|
||||
MipsExecutableWriter<ELFT>::createSymbolTable() {
|
||||
return unique_bump_ptr<SymbolTable<ELFT>>(
|
||||
new (this->_alloc) MipsSymbolTable<ELFT>(this->_ctx));
|
||||
}
|
||||
|
@ -148,7 +246,7 @@ unique_bump_ptr<SymbolTable<ELFT>>
|
|||
/// \brief create dynamic table
|
||||
template <class ELFT>
|
||||
unique_bump_ptr<DynamicTable<ELFT>>
|
||||
MipsExecutableWriter<ELFT>::createDynamicTable() {
|
||||
MipsExecutableWriter<ELFT>::createDynamicTable() {
|
||||
return unique_bump_ptr<DynamicTable<ELFT>>(
|
||||
new (this->_alloc) MipsDynamicTable<ELFT>(this->_ctx, _targetLayout));
|
||||
}
|
||||
|
@ -156,13 +254,13 @@ unique_bump_ptr<DynamicTable<ELFT>>
|
|||
/// \brief create dynamic symbol table
|
||||
template <class ELFT>
|
||||
unique_bump_ptr<DynamicSymbolTable<ELFT>>
|
||||
MipsExecutableWriter<ELFT>::createDynamicSymbolTable() {
|
||||
return unique_bump_ptr<DynamicSymbolTable<ELFT>>(
|
||||
new (this->_alloc)
|
||||
MipsDynamicSymbolTable<ELFT>(this->_ctx, _targetLayout));
|
||||
MipsExecutableWriter<ELFT>::createDynamicSymbolTable() {
|
||||
return unique_bump_ptr<DynamicSymbolTable<ELFT>>(new (
|
||||
this->_alloc) MipsDynamicSymbolTable<ELFT>(this->_ctx, _targetLayout));
|
||||
}
|
||||
|
||||
} // namespace elf
|
||||
} // namespace lld
|
||||
template class MipsExecutableWriter<ELF32LE>;
|
||||
template class MipsExecutableWriter<ELF64LE>;
|
||||
|
||||
#endif
|
||||
} // elf
|
||||
} // lld
|
|
@ -9,6 +9,8 @@
|
|||
#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_ELF_WRITERS_H
|
||||
#define LLD_READER_WRITER_ELF_MIPS_MIPS_ELF_WRITERS_H
|
||||
|
||||
#include "DynamicLibraryWriter.h"
|
||||
#include "ExecutableWriter.h"
|
||||
#include "MipsLinkingContext.h"
|
||||
|
||||
namespace lld {
|
||||
|
@ -16,63 +18,71 @@ namespace elf {
|
|||
|
||||
template <class ELFT> class MipsTargetLayout;
|
||||
|
||||
class MipsDynamicAtom : public DynamicAtom {
|
||||
public:
|
||||
MipsDynamicAtom(const File &f) : DynamicAtom(f) {}
|
||||
|
||||
ContentPermissions permissions() const override { return permR__; }
|
||||
};
|
||||
|
||||
template <typename ELFT> class MipsELFWriter {
|
||||
public:
|
||||
MipsELFWriter(MipsLinkingContext &ctx, MipsTargetLayout<ELFT> &targetLayout)
|
||||
: _ctx(ctx), _targetLayout(targetLayout) {}
|
||||
MipsELFWriter(MipsLinkingContext &ctx, MipsTargetLayout<ELFT> &targetLayout);
|
||||
|
||||
void setELFHeader(ELFHeader<ELFT> &elfHeader) {
|
||||
elfHeader.e_version(1);
|
||||
elfHeader.e_ident(llvm::ELF::EI_VERSION, llvm::ELF::EV_CURRENT);
|
||||
elfHeader.e_ident(llvm::ELF::EI_OSABI, llvm::ELF::ELFOSABI_NONE);
|
||||
if (_targetLayout.findOutputSection(".got.plt"))
|
||||
elfHeader.e_ident(llvm::ELF::EI_ABIVERSION, 1);
|
||||
else
|
||||
elfHeader.e_ident(llvm::ELF::EI_ABIVERSION, 0);
|
||||
void setELFHeader(ELFHeader<ELFT> &elfHeader);
|
||||
|
||||
elfHeader.e_flags(_ctx.getMergedELFFlags());
|
||||
}
|
||||
void finalizeMipsRuntimeAtomValues();
|
||||
|
||||
void finalizeMipsRuntimeAtomValues() {
|
||||
if (!_ctx.isDynamic())
|
||||
return;
|
||||
|
||||
auto gotSection = _targetLayout.findOutputSection(".got");
|
||||
auto got = gotSection ? gotSection->virtualAddr() : 0;
|
||||
auto gp = gotSection ? got + _targetLayout.getGPOffset() : 0;
|
||||
|
||||
setAtomValue("_gp", gp);
|
||||
setAtomValue("_gp_disp", gp);
|
||||
setAtomValue("__gnu_local_gp", gp);
|
||||
}
|
||||
|
||||
std::unique_ptr<RuntimeFile<ELFT>> createRuntimeFile() {
|
||||
auto file = llvm::make_unique<RuntimeFile<ELFT>>(_ctx, "Mips runtime file");
|
||||
if (_ctx.isDynamic()) {
|
||||
file->addAbsoluteAtom("_gp");
|
||||
file->addAbsoluteAtom("_gp_disp");
|
||||
file->addAbsoluteAtom("__gnu_local_gp");
|
||||
file->addAtom(*new (file->allocator()) MipsDynamicAtom(*file));
|
||||
}
|
||||
return file;
|
||||
}
|
||||
std::unique_ptr<RuntimeFile<ELFT>> createRuntimeFile();
|
||||
|
||||
private:
|
||||
MipsLinkingContext &_ctx;
|
||||
MipsTargetLayout<ELFT> &_targetLayout;
|
||||
|
||||
void setAtomValue(StringRef name, uint64_t value) {
|
||||
AtomLayout *atom = _targetLayout.findAbsoluteAtom(name);
|
||||
assert(atom);
|
||||
atom->_virtualAddr = value;
|
||||
}
|
||||
void setAtomValue(StringRef name, uint64_t value);
|
||||
};
|
||||
|
||||
template <class ELFT>
|
||||
class MipsDynamicLibraryWriter : public DynamicLibraryWriter<ELFT> {
|
||||
public:
|
||||
MipsDynamicLibraryWriter(MipsLinkingContext &ctx,
|
||||
MipsTargetLayout<ELFT> &layout);
|
||||
|
||||
protected:
|
||||
// Add any runtime files and their atoms to the output
|
||||
void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
|
||||
|
||||
void finalizeDefaultAtomValues() override;
|
||||
void createDefaultSections() override;
|
||||
|
||||
std::error_code setELFHeader() override;
|
||||
|
||||
unique_bump_ptr<SymbolTable<ELFT>> createSymbolTable() override;
|
||||
unique_bump_ptr<DynamicTable<ELFT>> createDynamicTable() override;
|
||||
unique_bump_ptr<DynamicSymbolTable<ELFT>> createDynamicSymbolTable() override;
|
||||
|
||||
private:
|
||||
MipsELFWriter<ELFT> _writeHelper;
|
||||
MipsTargetLayout<ELFT> &_targetLayout;
|
||||
unique_bump_ptr<Section<ELFT>> _reginfo;
|
||||
};
|
||||
|
||||
template <class ELFT>
|
||||
class MipsExecutableWriter : public ExecutableWriter<ELFT> {
|
||||
public:
|
||||
MipsExecutableWriter(MipsLinkingContext &ctx, MipsTargetLayout<ELFT> &layout);
|
||||
|
||||
protected:
|
||||
void buildDynamicSymbolTable(const File &file) override;
|
||||
|
||||
// Add any runtime files and their atoms to the output
|
||||
void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
|
||||
|
||||
void finalizeDefaultAtomValues() override;
|
||||
void createDefaultSections() override;
|
||||
std::error_code setELFHeader() override;
|
||||
|
||||
unique_bump_ptr<SymbolTable<ELFT>> createSymbolTable() override;
|
||||
unique_bump_ptr<DynamicTable<ELFT>> createDynamicTable() override;
|
||||
unique_bump_ptr<DynamicSymbolTable<ELFT>> createDynamicSymbolTable() override;
|
||||
|
||||
private:
|
||||
MipsELFWriter<ELFT> _writeHelper;
|
||||
MipsTargetLayout<ELFT> &_targetLayout;
|
||||
unique_bump_ptr<Section<ELFT>> _reginfo;
|
||||
};
|
||||
|
||||
} // elf
|
||||
|
|
|
@ -28,9 +28,9 @@ static std::unique_ptr<TargetHandler> createTarget(llvm::Triple triple,
|
|||
MipsLinkingContext &ctx) {
|
||||
switch (triple.getArch()) {
|
||||
case llvm::Triple::mipsel:
|
||||
return createMips32ELTargetHandler(ctx);
|
||||
return llvm::make_unique<MipsTargetHandler<ELF32LE>>(ctx);
|
||||
case llvm::Triple::mips64el:
|
||||
return createMips64ELTargetHandler(ctx);
|
||||
return llvm::make_unique<MipsTargetHandler<ELF64LE>>(ctx);
|
||||
default:
|
||||
llvm_unreachable("Unhandled arch");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,235 @@
|
|||
//===- lib/ReaderWriter/ELF/Mips/MipsSectionChunks.cpp --------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "MipsLinkingContext.h"
|
||||
#include "MipsSectionChunks.h"
|
||||
#include "MipsTargetLayout.h"
|
||||
|
||||
namespace lld {
|
||||
namespace elf {
|
||||
|
||||
template <class ELFT>
|
||||
MipsReginfoSection<ELFT>::MipsReginfoSection(
|
||||
const ELFLinkingContext &ctx, MipsTargetLayout<ELFT> &targetLayout,
|
||||
const MipsReginfo ®info)
|
||||
: Section<ELFT>(ctx, ".reginfo", "MipsReginfo"),
|
||||
_targetLayout(targetLayout) {
|
||||
this->setOrder(MipsTargetLayout<ELFT>::ORDER_MIPS_REGINFO);
|
||||
this->_entSize = sizeof(Elf_Mips_RegInfo);
|
||||
this->_fsize = sizeof(Elf_Mips_RegInfo);
|
||||
this->_msize = sizeof(Elf_Mips_RegInfo);
|
||||
this->_alignment = 4;
|
||||
this->_type = SHT_MIPS_REGINFO;
|
||||
this->_flags = SHF_ALLOC;
|
||||
|
||||
std::memset(&_reginfo, 0, sizeof(_reginfo));
|
||||
_reginfo.ri_gprmask = reginfo._gpRegMask;
|
||||
_reginfo.ri_cprmask[0] = reginfo._cpRegMask[0];
|
||||
_reginfo.ri_cprmask[1] = reginfo._cpRegMask[1];
|
||||
_reginfo.ri_cprmask[2] = reginfo._cpRegMask[2];
|
||||
_reginfo.ri_cprmask[3] = reginfo._cpRegMask[3];
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void MipsReginfoSection<ELFT>::write(ELFWriter *writer,
|
||||
TargetLayout<ELFT> &layout,
|
||||
llvm::FileOutputBuffer &buffer) {
|
||||
uint8_t *dest = buffer.getBufferStart() + this->fileOffset();
|
||||
std::memcpy(dest, &_reginfo, this->_fsize);
|
||||
}
|
||||
|
||||
template <class ELFT> void MipsReginfoSection<ELFT>::finalize() {
|
||||
_reginfo.ri_gp_value = _targetLayout.getGPAddr();
|
||||
|
||||
if (this->_outputSection)
|
||||
this->_outputSection->setType(this->_type);
|
||||
}
|
||||
|
||||
template class MipsReginfoSection<ELF32LE>;
|
||||
template class MipsReginfoSection<ELF64LE>;
|
||||
|
||||
template <class ELFT>
|
||||
MipsOptionsSection<ELFT>::MipsOptionsSection(
|
||||
const ELFLinkingContext &ctx, MipsTargetLayout<ELFT> &targetLayout,
|
||||
const MipsReginfo ®info)
|
||||
: Section<ELFT>(ctx, ".MIPS.options", "MipsOptions"),
|
||||
_targetLayout(targetLayout) {
|
||||
this->setOrder(MipsTargetLayout<ELFT>::ORDER_MIPS_OPTIONS);
|
||||
this->_entSize = 1;
|
||||
this->_alignment = 8;
|
||||
this->_fsize = llvm::RoundUpToAlignment(
|
||||
sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_RegInfo), this->_alignment);
|
||||
this->_msize = this->_fsize;
|
||||
this->_type = SHT_MIPS_OPTIONS;
|
||||
this->_flags = SHF_ALLOC | SHF_MIPS_NOSTRIP;
|
||||
|
||||
_header.kind = ODK_REGINFO;
|
||||
_header.size = this->_fsize;
|
||||
_header.section = 0;
|
||||
_header.info = 0;
|
||||
|
||||
std::memset(&_reginfo, 0, sizeof(_reginfo));
|
||||
_reginfo.ri_gprmask = reginfo._gpRegMask;
|
||||
_reginfo.ri_cprmask[0] = reginfo._cpRegMask[0];
|
||||
_reginfo.ri_cprmask[1] = reginfo._cpRegMask[1];
|
||||
_reginfo.ri_cprmask[2] = reginfo._cpRegMask[2];
|
||||
_reginfo.ri_cprmask[3] = reginfo._cpRegMask[3];
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void MipsOptionsSection<ELFT>::write(ELFWriter *writer,
|
||||
TargetLayout<ELFT> &layout,
|
||||
llvm::FileOutputBuffer &buffer) {
|
||||
uint8_t *dest = buffer.getBufferStart() + this->fileOffset();
|
||||
std::memset(dest, 0, this->_fsize);
|
||||
std::memcpy(dest, &_header, sizeof(_header));
|
||||
std::memcpy(dest + sizeof(_header), &_reginfo, sizeof(_reginfo));
|
||||
}
|
||||
|
||||
template <class ELFT> void MipsOptionsSection<ELFT>::finalize() {
|
||||
_reginfo.ri_gp_value = _targetLayout.getGPAddr();
|
||||
|
||||
if (this->_outputSection)
|
||||
this->_outputSection->setType(this->_type);
|
||||
}
|
||||
|
||||
template class MipsOptionsSection<ELF32LE>;
|
||||
template class MipsOptionsSection<ELF64LE>;
|
||||
|
||||
template <class ELFT>
|
||||
MipsGOTSection<ELFT>::MipsGOTSection(const MipsLinkingContext &ctx)
|
||||
: AtomSection<ELFT>(ctx, ".got", DefinedAtom::typeGOT, DefinedAtom::permRW_,
|
||||
MipsTargetLayout<ELFT>::ORDER_GOT),
|
||||
_hasNonLocal(false), _localCount(0) {
|
||||
this->_flags |= SHF_MIPS_GPREL;
|
||||
this->_alignment = 4;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
bool MipsGOTSection<ELFT>::compare(const Atom *a, const Atom *b) const {
|
||||
auto ia = _posMap.find(a);
|
||||
auto ib = _posMap.find(b);
|
||||
|
||||
if (ia != _posMap.end() && ib != _posMap.end())
|
||||
return ia->second < ib->second;
|
||||
|
||||
return ia == _posMap.end() && ib != _posMap.end();
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
const AtomLayout *MipsGOTSection<ELFT>::appendAtom(const Atom *atom) {
|
||||
const DefinedAtom *da = dyn_cast<DefinedAtom>(atom);
|
||||
|
||||
if (atom->name() == "_GLOBAL_OFFSET_TABLE_")
|
||||
return AtomSection<ELFT>::appendAtom(atom);
|
||||
|
||||
for (const auto &r : *da) {
|
||||
if (r->kindNamespace() != Reference::KindNamespace::ELF)
|
||||
continue;
|
||||
assert(r->kindArch() == Reference::KindArch::Mips);
|
||||
switch (r->kindValue()) {
|
||||
case LLD_R_MIPS_GLOBAL_GOT:
|
||||
_hasNonLocal = true;
|
||||
_posMap[r->target()] = _posMap.size();
|
||||
return AtomSection<ELFT>::appendAtom(atom);
|
||||
case R_MIPS_TLS_TPREL32:
|
||||
case R_MIPS_TLS_DTPREL32:
|
||||
case R_MIPS_TLS_TPREL64:
|
||||
case R_MIPS_TLS_DTPREL64:
|
||||
_hasNonLocal = true;
|
||||
_tlsMap[r->target()] = _tlsMap.size();
|
||||
return AtomSection<ELFT>::appendAtom(atom);
|
||||
case R_MIPS_TLS_DTPMOD32:
|
||||
case R_MIPS_TLS_DTPMOD64:
|
||||
_hasNonLocal = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_hasNonLocal)
|
||||
++_localCount;
|
||||
|
||||
return AtomSection<ELFT>::appendAtom(atom);
|
||||
}
|
||||
|
||||
template class MipsGOTSection<ELF32LE>;
|
||||
template class MipsGOTSection<ELF64LE>;
|
||||
|
||||
template <class ELFT>
|
||||
MipsPLTSection<ELFT>::MipsPLTSection(const MipsLinkingContext &ctx)
|
||||
: AtomSection<ELFT>(ctx, ".plt", DefinedAtom::typeGOT, DefinedAtom::permR_X,
|
||||
MipsTargetLayout<ELFT>::ORDER_PLT) {}
|
||||
|
||||
template <class ELFT>
|
||||
const AtomLayout *MipsPLTSection<ELFT>::findPLTLayout(const Atom *plt) const {
|
||||
auto it = _pltLayoutMap.find(plt);
|
||||
return it != _pltLayoutMap.end() ? it->second : nullptr;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
const AtomLayout *MipsPLTSection<ELFT>::appendAtom(const Atom *atom) {
|
||||
const auto *layout = AtomSection<ELFT>::appendAtom(atom);
|
||||
|
||||
const DefinedAtom *da = cast<DefinedAtom>(atom);
|
||||
|
||||
for (const auto &r : *da) {
|
||||
if (r->kindNamespace() != Reference::KindNamespace::ELF)
|
||||
continue;
|
||||
assert(r->kindArch() == Reference::KindArch::Mips);
|
||||
if (r->kindValue() == LLD_R_MIPS_STO_PLT) {
|
||||
_pltLayoutMap[r->target()] = layout;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
template class MipsPLTSection<ELF32LE>;
|
||||
template class MipsPLTSection<ELF64LE>;
|
||||
|
||||
template <class ELFT> static bool isMips64EL() {
|
||||
return ELFT::Is64Bits && ELFT::TargetEndianness == llvm::support::little;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
MipsRelocationTable<ELFT>::MipsRelocationTable(const ELFLinkingContext &ctx,
|
||||
StringRef str, int32_t order)
|
||||
: RelocationTable<ELFT>(ctx, str, order) {}
|
||||
|
||||
template <class ELFT>
|
||||
void MipsRelocationTable<ELFT>::writeRela(ELFWriter *writer, Elf_Rela &r,
|
||||
const DefinedAtom &atom,
|
||||
const Reference &ref) {
|
||||
uint32_t rType = ref.kindValue() | (ref.tag() << 8);
|
||||
r.setSymbolAndType(this->getSymbolIndex(ref.target()), rType,
|
||||
isMips64EL<ELFT>());
|
||||
r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom();
|
||||
// The addend is used only by relative relocations
|
||||
if (this->_ctx.isRelativeReloc(ref))
|
||||
r.r_addend = writer->addressOfAtom(ref.target()) + ref.addend();
|
||||
else
|
||||
r.r_addend = 0;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void MipsRelocationTable<ELFT>::writeRel(ELFWriter *writer, Elf_Rel &r,
|
||||
const DefinedAtom &atom,
|
||||
const Reference &ref) {
|
||||
uint32_t rType = ref.kindValue() | (ref.tag() << 8);
|
||||
r.setSymbolAndType(this->getSymbolIndex(ref.target()), rType,
|
||||
isMips64EL<ELFT>());
|
||||
r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom();
|
||||
}
|
||||
|
||||
template class MipsRelocationTable<ELF32LE>;
|
||||
template class MipsRelocationTable<ELF64LE>;
|
||||
|
||||
} // elf
|
||||
} // lld
|
|
@ -23,41 +23,14 @@ template <class ELFT> class MipsReginfoSection : public Section<ELFT> {
|
|||
public:
|
||||
MipsReginfoSection(const ELFLinkingContext &ctx,
|
||||
MipsTargetLayout<ELFT> &targetLayout,
|
||||
const MipsReginfo ®info)
|
||||
: Section<ELFT>(ctx, ".reginfo", "MipsReginfo"),
|
||||
_targetLayout(targetLayout) {
|
||||
this->setOrder(MipsTargetLayout<ELFT>::ORDER_MIPS_REGINFO);
|
||||
this->_entSize = sizeof(Elf_Mips_RegInfo);
|
||||
this->_fsize = sizeof(Elf_Mips_RegInfo);
|
||||
this->_msize = sizeof(Elf_Mips_RegInfo);
|
||||
this->_alignment = 4;
|
||||
this->_type = SHT_MIPS_REGINFO;
|
||||
this->_flags = SHF_ALLOC;
|
||||
|
||||
std::memset(&_reginfo, 0, sizeof(_reginfo));
|
||||
_reginfo.ri_gprmask = reginfo._gpRegMask;
|
||||
_reginfo.ri_cprmask[0] = reginfo._cpRegMask[0];
|
||||
_reginfo.ri_cprmask[1] = reginfo._cpRegMask[1];
|
||||
_reginfo.ri_cprmask[2] = reginfo._cpRegMask[2];
|
||||
_reginfo.ri_cprmask[3] = reginfo._cpRegMask[3];
|
||||
}
|
||||
const MipsReginfo ®info);
|
||||
|
||||
StringRef segmentKindToStr() const override { return "REGINFO"; }
|
||||
|
||||
bool hasOutputSegment() const override { return true; }
|
||||
|
||||
void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
|
||||
llvm::FileOutputBuffer &buffer) override {
|
||||
uint8_t *dest = buffer.getBufferStart() + this->fileOffset();
|
||||
std::memcpy(dest, &_reginfo, this->_fsize);
|
||||
}
|
||||
|
||||
void finalize() override {
|
||||
_reginfo.ri_gp_value = _targetLayout.getGPAddr();
|
||||
|
||||
if (this->_outputSection)
|
||||
this->_outputSection->setType(this->_type);
|
||||
}
|
||||
llvm::FileOutputBuffer &buffer) override;
|
||||
void finalize() override;
|
||||
|
||||
private:
|
||||
typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo;
|
||||
|
@ -69,51 +42,15 @@ private:
|
|||
/// \brief Handle .MIPS.options section
|
||||
template <class ELFT> class MipsOptionsSection : public Section<ELFT> {
|
||||
public:
|
||||
typedef typename std::vector<MipsReginfo>::const_iterator mask_const_iterator;
|
||||
|
||||
MipsOptionsSection(const ELFLinkingContext &ctx,
|
||||
MipsTargetLayout<ELFT> &targetLayout,
|
||||
const MipsReginfo ®info)
|
||||
: Section<ELFT>(ctx, ".MIPS.options", "MipsOptions"),
|
||||
_targetLayout(targetLayout) {
|
||||
this->setOrder(MipsTargetLayout<ELFT>::ORDER_MIPS_OPTIONS);
|
||||
this->_entSize = 1;
|
||||
this->_alignment = 8;
|
||||
this->_fsize = llvm::RoundUpToAlignment(
|
||||
sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_RegInfo), this->_alignment);
|
||||
this->_msize = this->_fsize;
|
||||
this->_type = SHT_MIPS_OPTIONS;
|
||||
this->_flags = SHF_ALLOC | SHF_MIPS_NOSTRIP;
|
||||
|
||||
_header.kind = ODK_REGINFO;
|
||||
_header.size = this->_fsize;
|
||||
_header.section = 0;
|
||||
_header.info = 0;
|
||||
|
||||
std::memset(&_reginfo, 0, sizeof(_reginfo));
|
||||
_reginfo.ri_gprmask = reginfo._gpRegMask;
|
||||
_reginfo.ri_cprmask[0] = reginfo._cpRegMask[0];
|
||||
_reginfo.ri_cprmask[1] = reginfo._cpRegMask[1];
|
||||
_reginfo.ri_cprmask[2] = reginfo._cpRegMask[2];
|
||||
_reginfo.ri_cprmask[3] = reginfo._cpRegMask[3];
|
||||
}
|
||||
const MipsReginfo ®info);
|
||||
|
||||
bool hasOutputSegment() const override { return true; }
|
||||
|
||||
void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
|
||||
llvm::FileOutputBuffer &buffer) override {
|
||||
uint8_t *dest = buffer.getBufferStart() + this->fileOffset();
|
||||
std::memset(dest, 0, this->_fsize);
|
||||
std::memcpy(dest, &_header, sizeof(_header));
|
||||
std::memcpy(dest + sizeof(_header), &_reginfo, sizeof(_reginfo));
|
||||
}
|
||||
|
||||
void finalize() override {
|
||||
_reginfo.ri_gp_value = _targetLayout.getGPAddr();
|
||||
|
||||
if (this->_outputSection)
|
||||
this->_outputSection->setType(this->_type);
|
||||
}
|
||||
llvm::FileOutputBuffer &buffer) override;
|
||||
void finalize() override;
|
||||
|
||||
private:
|
||||
typedef llvm::object::Elf_Mips_Options<ELFT> Elf_Mips_Options;
|
||||
|
@ -127,14 +64,7 @@ private:
|
|||
/// \brief Handle Mips GOT section
|
||||
template <class ELFT> class MipsGOTSection : public AtomSection<ELFT> {
|
||||
public:
|
||||
MipsGOTSection(const MipsLinkingContext &ctx)
|
||||
: AtomSection<ELFT>(ctx, ".got", DefinedAtom::typeGOT,
|
||||
DefinedAtom::permRW_,
|
||||
MipsTargetLayout<ELFT>::ORDER_GOT),
|
||||
_hasNonLocal(false), _localCount(0) {
|
||||
this->_flags |= SHF_MIPS_GPREL;
|
||||
this->_alignment = 4;
|
||||
}
|
||||
MipsGOTSection(const MipsLinkingContext &ctx);
|
||||
|
||||
/// \brief Number of local GOT entries.
|
||||
std::size_t getLocalCount() const { return _localCount; }
|
||||
|
@ -148,50 +78,9 @@ public:
|
|||
}
|
||||
|
||||
/// \brief Compare two atoms accordingly theirs positions in the GOT.
|
||||
bool compare(const Atom *a, const Atom *b) const {
|
||||
auto ia = _posMap.find(a);
|
||||
auto ib = _posMap.find(b);
|
||||
bool compare(const Atom *a, const Atom *b) const;
|
||||
|
||||
if (ia != _posMap.end() && ib != _posMap.end())
|
||||
return ia->second < ib->second;
|
||||
|
||||
return ia == _posMap.end() && ib != _posMap.end();
|
||||
}
|
||||
|
||||
const AtomLayout *appendAtom(const Atom *atom) override {
|
||||
const DefinedAtom *da = dyn_cast<DefinedAtom>(atom);
|
||||
|
||||
if (atom->name() == "_GLOBAL_OFFSET_TABLE_")
|
||||
return AtomSection<ELFT>::appendAtom(atom);
|
||||
|
||||
for (const auto &r : *da) {
|
||||
if (r->kindNamespace() != Reference::KindNamespace::ELF)
|
||||
continue;
|
||||
assert(r->kindArch() == Reference::KindArch::Mips);
|
||||
switch (r->kindValue()) {
|
||||
case LLD_R_MIPS_GLOBAL_GOT:
|
||||
_hasNonLocal = true;
|
||||
_posMap[r->target()] = _posMap.size();
|
||||
return AtomSection<ELFT>::appendAtom(atom);
|
||||
case R_MIPS_TLS_TPREL32:
|
||||
case R_MIPS_TLS_DTPREL32:
|
||||
case R_MIPS_TLS_TPREL64:
|
||||
case R_MIPS_TLS_DTPREL64:
|
||||
_hasNonLocal = true;
|
||||
_tlsMap[r->target()] = _tlsMap.size();
|
||||
return AtomSection<ELFT>::appendAtom(atom);
|
||||
case R_MIPS_TLS_DTPMOD32:
|
||||
case R_MIPS_TLS_DTPMOD64:
|
||||
_hasNonLocal = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_hasNonLocal)
|
||||
++_localCount;
|
||||
|
||||
return AtomSection<ELFT>::appendAtom(atom);
|
||||
}
|
||||
const AtomLayout *appendAtom(const Atom *atom) override;
|
||||
|
||||
private:
|
||||
/// \brief True if the GOT contains non-local entries.
|
||||
|
@ -210,33 +99,11 @@ private:
|
|||
/// \brief Handle Mips PLT section
|
||||
template <class ELFT> class MipsPLTSection : public AtomSection<ELFT> {
|
||||
public:
|
||||
MipsPLTSection(const MipsLinkingContext &ctx)
|
||||
: AtomSection<ELFT>(ctx, ".plt", DefinedAtom::typeGOT,
|
||||
DefinedAtom::permR_X,
|
||||
MipsTargetLayout<ELFT>::ORDER_PLT) {}
|
||||
MipsPLTSection(const MipsLinkingContext &ctx);
|
||||
|
||||
const AtomLayout *findPLTLayout(const Atom *plt) const {
|
||||
auto it = _pltLayoutMap.find(plt);
|
||||
return it != _pltLayoutMap.end() ? it->second : nullptr;
|
||||
}
|
||||
const AtomLayout *findPLTLayout(const Atom *plt) const;
|
||||
|
||||
const AtomLayout *appendAtom(const Atom *atom) override {
|
||||
const auto *layout = AtomSection<ELFT>::appendAtom(atom);
|
||||
|
||||
const DefinedAtom *da = cast<DefinedAtom>(atom);
|
||||
|
||||
for (const auto &r : *da) {
|
||||
if (r->kindNamespace() != Reference::KindNamespace::ELF)
|
||||
continue;
|
||||
assert(r->kindArch() == Reference::KindArch::Mips);
|
||||
if (r->kindValue() == LLD_R_MIPS_STO_PLT) {
|
||||
_pltLayoutMap[r->target()] = layout;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return layout;
|
||||
}
|
||||
const AtomLayout *appendAtom(const Atom *atom) override;
|
||||
|
||||
private:
|
||||
/// \brief Map PLT Atoms to their layouts.
|
||||
|
@ -247,33 +114,15 @@ template <class ELFT> class MipsRelocationTable : public RelocationTable<ELFT> {
|
|||
typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel;
|
||||
typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela;
|
||||
|
||||
static const bool _isMips64EL =
|
||||
ELFT::Is64Bits && ELFT::TargetEndianness == llvm::support::little;
|
||||
|
||||
public:
|
||||
MipsRelocationTable(const ELFLinkingContext &ctx, StringRef str,
|
||||
int32_t order)
|
||||
: RelocationTable<ELFT>(ctx, str, order) {}
|
||||
int32_t order);
|
||||
|
||||
protected:
|
||||
void writeRela(ELFWriter *writer, Elf_Rela &r, const DefinedAtom &atom,
|
||||
const Reference &ref) override {
|
||||
uint32_t rType = ref.kindValue() | (ref.tag() << 8);
|
||||
r.setSymbolAndType(this->getSymbolIndex(ref.target()), rType, _isMips64EL);
|
||||
r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom();
|
||||
// The addend is used only by relative relocations
|
||||
if (this->_ctx.isRelativeReloc(ref))
|
||||
r.r_addend = writer->addressOfAtom(ref.target()) + ref.addend();
|
||||
else
|
||||
r.r_addend = 0;
|
||||
}
|
||||
|
||||
const Reference &ref) override;
|
||||
void writeRel(ELFWriter *writer, Elf_Rel &r, const DefinedAtom &atom,
|
||||
const Reference &ref) override {
|
||||
uint32_t rType = ref.kindValue() | (ref.tag() << 8);
|
||||
r.setSymbolAndType(this->getSymbolIndex(ref.target()), rType, _isMips64EL);
|
||||
r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom();
|
||||
}
|
||||
const Reference &ref) override;
|
||||
};
|
||||
|
||||
} // elf
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
//===- lib/ReaderWriter/ELF/Mips/MipsTargetHandler32EL.cpp ----------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ELFReader.h"
|
||||
#include "MipsELFFile.h"
|
||||
#include "MipsELFWriters.h"
|
||||
#include "MipsTargetHandler.h"
|
||||
|
||||
namespace lld {
|
||||
namespace elf {
|
||||
|
||||
template <class ELFT>
|
||||
MipsTargetHandler<ELFT>::MipsTargetHandler(MipsLinkingContext &ctx)
|
||||
: _ctx(ctx), _targetLayout(new MipsTargetLayout<ELFT>(ctx)),
|
||||
_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);
|
||||
case llvm::ELF::ET_DYN:
|
||||
return llvm::make_unique<MipsDynamicLibraryWriter<ELFT>>(_ctx,
|
||||
*_targetLayout);
|
||||
case llvm::ELF::ET_REL:
|
||||
llvm_unreachable("TODO: support -r mode");
|
||||
default:
|
||||
llvm_unreachable("unsupported output type");
|
||||
}
|
||||
}
|
||||
|
||||
template class MipsTargetHandler<ELF32LE>;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT> void MipsSymbolTable<ELFT>::finalize(bool sort) {
|
||||
SymbolTable<ELFT>::finalize(sort);
|
||||
|
||||
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<ELF32LE>;
|
||||
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();
|
||||
|
||||
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<ELF32LE>;
|
||||
template class MipsDynamicSymbolTable<ELF64LE>;
|
||||
|
||||
}
|
||||
}
|
|
@ -9,10 +9,6 @@
|
|||
#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_TARGET_HANDLER_H
|
||||
#define LLD_READER_WRITER_ELF_MIPS_MIPS_TARGET_HANDLER_H
|
||||
|
||||
#include "ELFReader.h"
|
||||
#include "MipsDynamicLibraryWriter.h"
|
||||
#include "MipsELFFile.h"
|
||||
#include "MipsExecutableWriter.h"
|
||||
#include "MipsLinkingContext.h"
|
||||
#include "MipsTargetLayout.h"
|
||||
#include "TargetHandler.h"
|
||||
|
@ -23,37 +19,12 @@ namespace elf {
|
|||
/// \brief TargetHandler for Mips
|
||||
template <class ELFT> class MipsTargetHandler final : public TargetHandler {
|
||||
public:
|
||||
MipsTargetHandler(MipsLinkingContext &ctx)
|
||||
: _ctx(ctx), _targetLayout(new MipsTargetLayout<ELFT>(ctx)),
|
||||
_relocationHandler(
|
||||
createMipsRelocationHandler<ELFT>(ctx, *_targetLayout)) {}
|
||||
MipsTargetHandler(MipsLinkingContext &ctx);
|
||||
|
||||
std::unique_ptr<Reader> getObjReader() override {
|
||||
return llvm::make_unique<ELFReader<MipsELFFile<ELFT>>>(_ctx);
|
||||
}
|
||||
|
||||
std::unique_ptr<Reader> getDSOReader() override {
|
||||
return llvm::make_unique<ELFReader<DynamicFile<ELFT>>>(_ctx);
|
||||
}
|
||||
|
||||
const TargetRelocationHandler &getRelocationHandler() const override {
|
||||
return *_relocationHandler;
|
||||
}
|
||||
|
||||
std::unique_ptr<Writer> getWriter() override {
|
||||
switch (_ctx.getOutputELFType()) {
|
||||
case llvm::ELF::ET_EXEC:
|
||||
return llvm::make_unique<MipsExecutableWriter<ELFT>>(
|
||||
_ctx, *_targetLayout);
|
||||
case llvm::ELF::ET_DYN:
|
||||
return llvm::make_unique<MipsDynamicLibraryWriter<ELFT>>(
|
||||
_ctx, *_targetLayout);
|
||||
case llvm::ELF::ET_REL:
|
||||
llvm_unreachable("TODO: support -r mode");
|
||||
default:
|
||||
llvm_unreachable("unsupported output type");
|
||||
}
|
||||
}
|
||||
std::unique_ptr<Reader> getObjReader() override;
|
||||
std::unique_ptr<Reader> getDSOReader() override;
|
||||
const TargetRelocationHandler &getRelocationHandler() const override;
|
||||
std::unique_ptr<Writer> getWriter() override;
|
||||
|
||||
private:
|
||||
MipsLinkingContext &_ctx;
|
||||
|
@ -65,105 +36,26 @@ template <class ELFT> class MipsSymbolTable : public SymbolTable<ELFT> {
|
|||
public:
|
||||
typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
|
||||
|
||||
MipsSymbolTable(const ELFLinkingContext &ctx)
|
||||
: SymbolTable<ELFT>(ctx, ".symtab",
|
||||
TargetLayout<ELFT>::ORDER_SYMBOL_TABLE) {}
|
||||
MipsSymbolTable(const ELFLinkingContext &ctx);
|
||||
|
||||
void addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
|
||||
int64_t addr) override {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void finalize(bool sort) override {
|
||||
SymbolTable<ELFT>::finalize(sort);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
int64_t addr) override;
|
||||
void finalize(bool sort) override;
|
||||
};
|
||||
|
||||
template <class ELFT>
|
||||
class MipsDynamicSymbolTable : public DynamicSymbolTable<ELFT> {
|
||||
public:
|
||||
MipsDynamicSymbolTable(const ELFLinkingContext &ctx,
|
||||
MipsTargetLayout<ELFT> &layout)
|
||||
: DynamicSymbolTable<ELFT>(ctx, layout, ".dynsym",
|
||||
TargetLayout<ELFT>::ORDER_DYNAMIC_SYMBOLS),
|
||||
_targetLayout(layout) {}
|
||||
MipsTargetLayout<ELFT> &layout);
|
||||
|
||||
void sortSymbols() override {
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
void finalize() override {
|
||||
DynamicSymbolTable<ELFT>::finalize();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void sortSymbols() override;
|
||||
void finalize() override;
|
||||
|
||||
private:
|
||||
MipsTargetLayout<ELFT> &_targetLayout;
|
||||
};
|
||||
|
||||
std::unique_ptr<TargetHandler>
|
||||
createMips32ELTargetHandler(MipsLinkingContext &ctx);
|
||||
std::unique_ptr<TargetHandler>
|
||||
createMips64ELTargetHandler(MipsLinkingContext &ctx);
|
||||
|
||||
} // end namespace elf
|
||||
} // end namespace lld
|
||||
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
//===- lib/ReaderWriter/ELF/Mips/MipsTargetHandler32EL.cpp ----------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "MipsTargetHandler.h"
|
||||
|
||||
using namespace lld;
|
||||
using namespace lld::elf;
|
||||
|
||||
std::unique_ptr<TargetHandler>
|
||||
lld::elf::createMips32ELTargetHandler(MipsLinkingContext &ctx) {
|
||||
return llvm::make_unique<MipsTargetHandler<ELF32LE>>(ctx);
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
//===- lib/ReaderWriter/ELF/Mips/MipsTargetHandler64EL.cpp ----------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "MipsTargetHandler.h"
|
||||
|
||||
using namespace lld;
|
||||
using namespace lld::elf;
|
||||
|
||||
std::unique_ptr<TargetHandler>
|
||||
lld::elf::createMips64ELTargetHandler(MipsLinkingContext &ctx) {
|
||||
return llvm::make_unique<MipsTargetHandler<ELF64LE>>(ctx);
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
//===- lib/ReaderWriter/ELF/Mips/MipsTargetLayout.cpp ---------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "MipsLinkingContext.h"
|
||||
#include "MipsTargetLayout.h"
|
||||
|
||||
namespace lld {
|
||||
namespace elf {
|
||||
|
||||
template <class ELFT>
|
||||
MipsTargetLayout<ELFT>::MipsTargetLayout(MipsLinkingContext &ctx)
|
||||
: TargetLayout<ELFT>(ctx),
|
||||
_gotSection(new (this->_allocator) MipsGOTSection<ELFT>(ctx)),
|
||||
_pltSection(new (this->_allocator) MipsPLTSection<ELFT>(ctx)) {}
|
||||
|
||||
template <class ELFT>
|
||||
AtomSection<ELFT> *MipsTargetLayout<ELFT>::createSection(
|
||||
StringRef name, int32_t type, DefinedAtom::ContentPermissions permissions,
|
||||
typename TargetLayout<ELFT>::SectionOrder order) {
|
||||
if (type == DefinedAtom::typeGOT && name == ".got")
|
||||
return _gotSection;
|
||||
if (type == DefinedAtom::typeStub && name == ".plt")
|
||||
return _pltSection;
|
||||
return TargetLayout<ELFT>::createSection(name, type, permissions, order);
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
typename TargetLayout<ELFT>::SegmentType
|
||||
MipsTargetLayout<ELFT>::getSegmentType(Section<ELFT> *section) const {
|
||||
switch (section->order()) {
|
||||
case ORDER_MIPS_REGINFO:
|
||||
return llvm::ELF::PT_MIPS_REGINFO;
|
||||
case ORDER_MIPS_OPTIONS:
|
||||
return llvm::ELF::PT_LOAD;
|
||||
default:
|
||||
return TargetLayout<ELFT>::getSegmentType(section);
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT> uint64_t MipsTargetLayout<ELFT>::getGPAddr() {
|
||||
std::call_once(_gpOnce, [this]() {
|
||||
if (AtomLayout *a = this->findAbsoluteAtom("_gp"))
|
||||
_gpAddr = a->_virtualAddr;
|
||||
});
|
||||
return _gpAddr;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
typename TargetLayout<ELFT>::SectionOrder
|
||||
MipsTargetLayout<ELFT>::getSectionOrder(StringRef name, int32_t contentType,
|
||||
int32_t contentPermissions) {
|
||||
if ((contentType == DefinedAtom::typeStub) && (name.startswith(".text")))
|
||||
return TargetLayout<ELFT>::ORDER_TEXT;
|
||||
|
||||
return TargetLayout<ELFT>::getSectionOrder(name, contentType,
|
||||
contentPermissions);
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
unique_bump_ptr<RelocationTable<ELFT>>
|
||||
MipsTargetLayout<ELFT>::createRelocationTable(StringRef name, int32_t order) {
|
||||
return unique_bump_ptr<RelocationTable<ELFT>>(new (
|
||||
this->_allocator) MipsRelocationTable<ELFT>(this->_ctx, name, order));
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
uint64_t MipsTargetLayout<ELFT>::getLookupSectionFlags(
|
||||
const OutputSection<ELFT> *os) const {
|
||||
uint64_t flags = TargetLayout<ELFT>::getLookupSectionFlags(os);
|
||||
return flags & ~llvm::ELF::SHF_MIPS_NOSTRIP;
|
||||
}
|
||||
|
||||
template class MipsTargetLayout<ELF32LE>;
|
||||
template class MipsTargetLayout<ELF64LE>;
|
||||
|
||||
} // end namespace elf
|
||||
} // end namespace lld
|
|
@ -25,10 +25,7 @@ public:
|
|||
ORDER_MIPS_OPTIONS
|
||||
};
|
||||
|
||||
MipsTargetLayout(MipsLinkingContext &ctx)
|
||||
: TargetLayout<ELFT>(ctx),
|
||||
_gotSection(new (this->_allocator) MipsGOTSection<ELFT>(ctx)),
|
||||
_pltSection(new (this->_allocator) MipsPLTSection<ELFT>(ctx)) {}
|
||||
MipsTargetLayout(MipsLinkingContext &ctx);
|
||||
|
||||
const MipsGOTSection<ELFT> &getGOTSection() const { return *_gotSection; }
|
||||
const MipsPLTSection<ELFT> &getPLTSection() const { return *_pltSection; }
|
||||
|
@ -36,60 +33,26 @@ public:
|
|||
AtomSection<ELFT> *
|
||||
createSection(StringRef name, int32_t type,
|
||||
DefinedAtom::ContentPermissions permissions,
|
||||
typename TargetLayout<ELFT>::SectionOrder order) override {
|
||||
if (type == DefinedAtom::typeGOT && name == ".got")
|
||||
return _gotSection;
|
||||
if (type == DefinedAtom::typeStub && name == ".plt")
|
||||
return _pltSection;
|
||||
return TargetLayout<ELFT>::createSection(name, type, permissions, order);
|
||||
}
|
||||
typename TargetLayout<ELFT>::SectionOrder order) override;
|
||||
|
||||
typename TargetLayout<ELFT>::SegmentType
|
||||
getSegmentType(Section<ELFT> *section) const override {
|
||||
switch (section->order()) {
|
||||
case ORDER_MIPS_REGINFO:
|
||||
return llvm::ELF::PT_MIPS_REGINFO;
|
||||
case ORDER_MIPS_OPTIONS:
|
||||
return llvm::ELF::PT_LOAD;
|
||||
default:
|
||||
return TargetLayout<ELFT>::getSegmentType(section);
|
||||
}
|
||||
}
|
||||
getSegmentType(Section<ELFT> *section) const override;
|
||||
|
||||
/// \brief GP offset relative to .got section.
|
||||
uint64_t getGPOffset() const { return 0x7FF0; }
|
||||
|
||||
/// \brief Get '_gp' symbol address.
|
||||
uint64_t getGPAddr() {
|
||||
std::call_once(_gpOnce, [this]() {
|
||||
if (AtomLayout *a = this->findAbsoluteAtom("_gp"))
|
||||
_gpAddr = a->_virtualAddr;
|
||||
});
|
||||
return _gpAddr;
|
||||
}
|
||||
uint64_t getGPAddr();
|
||||
|
||||
/// \brief Return the section order for a input section
|
||||
typename TargetLayout<ELFT>::SectionOrder
|
||||
getSectionOrder(StringRef name, int32_t contentType,
|
||||
int32_t contentPermissions) override {
|
||||
if ((contentType == DefinedAtom::typeStub) && (name.startswith(".text")))
|
||||
return TargetLayout<ELFT>::ORDER_TEXT;
|
||||
|
||||
return TargetLayout<ELFT>::getSectionOrder(name, contentType,
|
||||
contentPermissions);
|
||||
}
|
||||
int32_t contentPermissions) override;
|
||||
|
||||
protected:
|
||||
unique_bump_ptr<RelocationTable<ELFT>>
|
||||
createRelocationTable(StringRef name, int32_t order) override {
|
||||
return unique_bump_ptr<RelocationTable<ELFT>>(new (
|
||||
this->_allocator) MipsRelocationTable<ELFT>(this->_ctx, name, order));
|
||||
}
|
||||
|
||||
uint64_t getLookupSectionFlags(const OutputSection<ELFT> *os) const override {
|
||||
uint64_t flags = TargetLayout<ELFT>::getLookupSectionFlags(os);
|
||||
return flags & ~llvm::ELF::SHF_MIPS_NOSTRIP;
|
||||
}
|
||||
createRelocationTable(StringRef name, int32_t order) override;
|
||||
uint64_t getLookupSectionFlags(const OutputSection<ELFT> *os) const override;
|
||||
|
||||
private:
|
||||
MipsGOTSection<ELFT> *_gotSection;
|
||||
|
|
Loading…
Reference in New Issue