| //===- 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 |