236 lines
7.8 KiB
C++
236 lines
7.8 KiB
C++
//===- 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
|