diff options
Diffstat (limited to 'lib/ReaderWriter/ELF/Mips/MipsSectionChunks.cpp')
-rw-r--r-- | lib/ReaderWriter/ELF/Mips/MipsSectionChunks.cpp | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.cpp b/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.cpp new file mode 100644 index 0000000000000..98cc059787efc --- /dev/null +++ b/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.cpp @@ -0,0 +1,264 @@ +//===- 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 Elf_Mips_RegInfo ®info) + : Section<ELFT>(ctx, ".reginfo", "MipsReginfo"), _reginfo(reginfo), + _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; +} + +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<ELF32BE>; +template class MipsReginfoSection<ELF32LE>; +template class MipsReginfoSection<ELF64BE>; +template class MipsReginfoSection<ELF64LE>; + +template <class ELFT> +MipsOptionsSection<ELFT>::MipsOptionsSection( + const ELFLinkingContext &ctx, MipsTargetLayout<ELFT> &targetLayout, + const Elf_Mips_RegInfo ®info) + : Section<ELFT>(ctx, ".MIPS.options", "MipsOptions"), _reginfo(reginfo), + _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; +} + +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<ELF32BE>; +template class MipsOptionsSection<ELF32LE>; +template class MipsOptionsSection<ELF64BE>; +template class MipsOptionsSection<ELF64LE>; + +template <class ELFT> +MipsAbiFlagsSection<ELFT>::MipsAbiFlagsSection( + const ELFLinkingContext &ctx, MipsTargetLayout<ELFT> &targetLayout, + const Elf_Mips_ABIFlags &abiFlags) + : Section<ELFT>(ctx, ".MIPS.abiflags", "MipsAbiFlags"), _abiFlags(abiFlags), + _targetLayout(targetLayout) { + this->setOrder(MipsTargetLayout<ELFT>::ORDER_MIPS_ABI_FLAGS); + this->_alignment = 8; + this->_fsize = llvm::RoundUpToAlignment(sizeof(_abiFlags), this->_alignment); + this->_msize = this->_fsize; + this->_entSize = this->_fsize; + this->_type = SHT_MIPS_ABIFLAGS; + this->_flags = SHF_ALLOC; +} + +template <class ELFT> +void MipsAbiFlagsSection<ELFT>::write(ELFWriter *writer, + TargetLayout<ELFT> &layout, + llvm::FileOutputBuffer &buffer) { + uint8_t *dest = buffer.getBufferStart() + this->fileOffset(); + std::memcpy(dest, &_abiFlags, this->_fsize); +} + +template <class ELFT> void MipsAbiFlagsSection<ELFT>::finalize() { + if (this->_outputSection) + this->_outputSection->setType(this->_type); +} + +template class MipsAbiFlagsSection<ELF32BE>; +template class MipsAbiFlagsSection<ELF32LE>; +template class MipsAbiFlagsSection<ELF64BE>; +template class MipsAbiFlagsSection<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<ELF32BE>; +template class MipsGOTSection<ELF32LE>; +template class MipsGOTSection<ELF64BE>; +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<ELF32BE>; +template class MipsPLTSection<ELF32LE>; +template class MipsPLTSection<ELF64BE>; +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<ELF32BE>; +template class MipsRelocationTable<ELF32LE>; +template class MipsRelocationTable<ELF64BE>; +template class MipsRelocationTable<ELF64LE>; + +} // elf +} // lld |