diff options
author | Stephen Hines <srhines@google.com> | 2014-02-14 18:00:16 -0800 |
---|---|---|
committer | Stephen Hines <srhines@google.com> | 2014-02-19 16:29:27 -0800 |
commit | 87f34658dec9097d987d254a990ea7f311bfc95f (patch) | |
tree | aaf3301283eddb3884dd21317f5861e66c4b7aad /lib/Target/Mips/MipsRelocator.cpp | |
parent | b3ee01ade7820351a29904d942b73ce83340f4f8 (diff) | |
download | mclinker-87f34658dec9097d987d254a990ea7f311bfc95f.tar.gz |
Update MCLinker to work with LLVM 3.4.
This corresponds to merging upstream MCLinker with the following SHA:
6dcbf36cdb146d6f175ba2f18a9004753cafeaff
Change-Id: I1bc8c2ce4accc563450bc71ee295a6e47a0c0469
Diffstat (limited to 'lib/Target/Mips/MipsRelocator.cpp')
-rw-r--r-- | lib/Target/Mips/MipsRelocator.cpp | 951 |
1 files changed, 699 insertions, 252 deletions
diff --git a/lib/Target/Mips/MipsRelocator.cpp b/lib/Target/Mips/MipsRelocator.cpp index 8f08862..314a6ad 100644 --- a/lib/Target/Mips/MipsRelocator.cpp +++ b/lib/Target/Mips/MipsRelocator.cpp @@ -6,26 +6,155 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// +#include "MipsRelocator.h" +#include "MipsRelocationFunctions.h" -#include <llvm/ADT/Twine.h> -#include <llvm/Support/ELF.h> +#include <mcld/IRBuilder.h> +#include <mcld/LinkerConfig.h> +#include <mcld/Object/ObjectBuilder.h> #include <mcld/Support/MsgHandling.h> #include <mcld/Target/OutputRelocSection.h> -#include <mcld/LinkerConfig.h> -#include <mcld/IRBuilder.h> +#include <mcld/LD/ELFFileFormat.h> -#include "MipsRelocator.h" -#include "MipsRelocationFunctions.h" +#include <llvm/ADT/Twine.h> +#include <llvm/Support/ELF.h> + +namespace llvm { +namespace ELF { + +// FIXME: Consider upstream these relocation types to LLVM. +enum { + R_MIPS_LA25_LUI = 200, + R_MIPS_LA25_J = 201, + R_MIPS_LA25_ADD = 202, + R_MIPS_PC32 = 248, +}; + +} // end namespace ELF +} // end namespace llvm using namespace mcld; //===----------------------------------------------------------------------===// +// MipsRelocationInfo +//===----------------------------------------------------------------------===// +class mcld::MipsRelocationInfo +{ +public: + static bool HasSubType(const Relocation& pParent, Relocation::Type pType) + { + if (llvm::ELF::R_MIPS_NONE == pType) + return true; + + for (Relocation::Type type = pParent.type(); + llvm::ELF::R_MIPS_NONE != (type & 0xff); type >>= 8) { + if ((type & 0xff) == pType) + return true; + } + + return false; + } + + MipsRelocationInfo(Relocation& pParent, bool pIsRel) + : m_Parent(&pParent), + m_Type(pParent.type()), + m_Addend(0), + m_Symbol(pParent.symValue()), + m_Result(pParent.target()) + { + if (pIsRel && (type() < llvm::ELF::R_MIPS_LA25_LUI || + type() > llvm::ELF::R_MIPS_LA25_ADD)) + m_Addend = pParent.target(); + else + m_Addend = pParent.addend(); + } + + bool isNone() const + { + return llvm::ELF::R_MIPS_NONE == type(); + } + + bool isLast() const + { + return llvm::ELF::R_MIPS_NONE == (m_Type >> 8); + } + + MipsRelocationInfo next() const + { + return MipsRelocationInfo(*m_Parent, m_Type >> 8, result(), result(), 0); + } + + const Relocation& parent() const + { + return *m_Parent; + } + + Relocation& parent() + { + return *m_Parent; + } + + Relocation::Type type() const + { + return m_Type & 0xff; + } + + Relocation::DWord A() const + { + return m_Addend; + } + + Relocation::DWord S() const + { + return m_Symbol; + } + + Relocation::DWord P() const + { + return parent().place(); + } + + Relocation::DWord result() const + { + return m_Result; + } + + Relocation::DWord& result() + { + return m_Result; + } + +private: + Relocation* m_Parent; + Relocation::Type m_Type; + Relocation::DWord m_Addend; + Relocation::DWord m_Symbol; + Relocation::DWord m_Result; + + MipsRelocationInfo(Relocation& pParent, Relocation::Type pType, + Relocation::DWord pResult, + Relocation::DWord pAddend, Relocation::DWord pSymbol) + : m_Parent(&pParent), + m_Type(pType), + m_Addend(pAddend), + m_Symbol(pSymbol), + m_Result(pResult) + {} + + bool isFirst() const { + return m_Type == parent().type(); + } +}; + +//===----------------------------------------------------------------------===// // Relocation Functions and Tables //===----------------------------------------------------------------------===// DECL_MIPS_APPLY_RELOC_FUNCS /// the prototype of applying function -typedef Relocator::Result (*ApplyFunctionType)(Relocation&, MipsRelocator&); +typedef Relocator::Result (*ApplyFunctionType)(MipsRelocationInfo&, + MipsRelocator& pParent); + // the table entry of applying functions struct ApplyFunctionTriple @@ -49,78 +178,102 @@ MipsRelocator::MipsRelocator(MipsGNULDBackend& pParent, : Relocator(pConfig), m_Target(pParent), m_pApplyingInput(NULL), - m_AHL(0) + m_CurrentLo16Reloc(NULL) { } Relocator::Result -MipsRelocator::applyRelocation(Relocation& pRelocation) +MipsRelocator::applyRelocation(Relocation& pReloc) { - Relocation::Type type = pRelocation.type(); + // If m_CurrentLo16Reloc is not NULL we are processing + // postponed relocation. Otherwise check relocation type + // and postpone it for later handling. + if (NULL == m_CurrentLo16Reloc && isPostponed(pReloc)) { + postponeRelocation(pReloc); + return OK; + } + + for (MipsRelocationInfo info(pReloc, isRel()); + !info.isNone(); info = info.next()) { + if (info.type() >= sizeof(ApplyFunctions) / sizeof(ApplyFunctions[0])) + return Unknown; + + const ApplyFunctionTriple & triple = ApplyFunctions[info.type()]; - if (type >= sizeof(ApplyFunctions) / sizeof(ApplyFunctions[0])) { - return Unknown; + Result res = triple.func(info, *this); + if (OK != res) + return res; + + if (info.isLast()) { + uint64_t mask = 0xFFFFFFFFFFFFFFFFULL >> (64 - triple.size); + pReloc.target() &= ~mask; + pReloc.target() |= info.result() & mask; + } } - // apply the relocation - return ApplyFunctions[type].func(pRelocation, *this); + return OK; } const char* MipsRelocator::getName(Relocation::Type pType) const { - return ApplyFunctions[pType].name; + return ApplyFunctions[pType & 0xff].name; } Relocator::Size MipsRelocator::getSize(Relocation::Type pType) const { - return ApplyFunctions[pType].size; + return ApplyFunctions[pType & 0xff].size; } void MipsRelocator::scanRelocation(Relocation& pReloc, IRBuilder& pBuilder, Module& pModule, - LDSection& pSection) + LDSection& pSection, + Input& pInput) { // rsym - The relocation target symbol ResolveInfo* rsym = pReloc.symInfo(); assert(NULL != rsym && "ResolveInfo of relocation not set while scanRelocation"); // Skip relocation against _gp_disp - if (NULL != getTarget().getGpDispSymbol()) { - if (pReloc.symInfo() == getTarget().getGpDispSymbol()->resolveInfo()) - return; - } - - pReloc.updateAddend(); + if (NULL != getTarget().getGpDispSymbol() && + rsym == getTarget().getGpDispSymbol()->resolveInfo()) + return; assert(NULL != pSection.getLink()); if (0 == (pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC)) return; - // We test isLocal or if pInputSym is not a dynamic symbol - // We assume -Bsymbolic to bind all symbols internaly via !rsym->isDyn() - // Don't put undef symbols into local entries. - if ((rsym->isLocal() || !getTarget().isDynamicSymbol(*rsym) || - !rsym->isDyn()) && !rsym->isUndef()) - scanLocalReloc(pReloc, pBuilder, pSection); - else - scanGlobalReloc(pReloc, pBuilder, pSection); + for (MipsRelocationInfo info(pReloc, isRel()); + !info.isNone(); info = info.next()) { + // We test isLocal or if pInputSym is not a dynamic symbol + // We assume -Bsymbolic to bind all symbols internaly via !rsym->isDyn() + // Don't put undef symbols into local entries. + if (isLocalReloc(*rsym)) + scanLocalReloc(info, pBuilder, pSection); + else + scanGlobalReloc(info, pBuilder, pSection); + + if (getTarget().needsLA25Stub(info.type(), info.parent().symInfo())) + getTarget().addNonPICBranchSym(pReloc.symInfo()); + } - // check if we shoule issue undefined reference for the relocation target - // symbol + // Check if we should issue undefined reference + // for the relocation target symbol. if (rsym->isUndef() && !rsym->isDyn() && !rsym->isWeak() && !rsym->isNull()) - fatal(diag::undefined_reference) << rsym->name(); + issueUndefRef(pReloc, pSection, pInput); } bool MipsRelocator::initializeScan(Input& pInput) { - getTarget().getGOT().initializeScan(pInput); + if (LinkerConfig::Object != config().codeGenType()) + getTarget().getGOT().initializeScan(pInput); return true; } bool MipsRelocator::finalizeScan(Input& pInput) { - getTarget().getGOT().finalizeScan(pInput); + if (LinkerConfig::Object != config().codeGenType()) + getTarget().getGOT().finalizeScan(pInput); return true; } @@ -136,17 +289,18 @@ bool MipsRelocator::finalizeApply(Input& pInput) return true; } -void MipsRelocator::scanLocalReloc(Relocation& pReloc, +void MipsRelocator::scanLocalReloc(MipsRelocationInfo& pReloc, IRBuilder& pBuilder, const LDSection& pSection) { - ResolveInfo* rsym = pReloc.symInfo(); + ResolveInfo* rsym = pReloc.parent().symInfo(); switch (pReloc.type()){ case llvm::ELF::R_MIPS_NONE: case llvm::ELF::R_MIPS_16: break; case llvm::ELF::R_MIPS_32: + case llvm::ELF::R_MIPS_64: if (LinkerConfig::DynObj == config().codeGenType()) { // TODO: (simon) The gold linker does not create an entry in .rel.dyn // section if the symbol section flags contains SHF_EXECINSTR. @@ -155,10 +309,6 @@ void MipsRelocator::scanLocalReloc(Relocation& pReloc, getTarget().getRelDyn().reserveEntry(); rsym->setReserved(rsym->reserved() | ReserveRel); getTarget().checkAndSetHasTextRel(*pSection.getLink()); - - // Remeber this rsym is a local GOT entry (as if it needs an entry). - // Actually we don't allocate an GOT entry. - getTarget().getGOT().setLocal(rsym); } break; case llvm::ELF::R_MIPS_REL32: @@ -168,9 +318,6 @@ void MipsRelocator::scanLocalReloc(Relocation& pReloc, case llvm::ELF::R_MIPS_PC16: case llvm::ELF::R_MIPS_SHIFT5: case llvm::ELF::R_MIPS_SHIFT6: - case llvm::ELF::R_MIPS_64: - case llvm::ELF::R_MIPS_GOT_PAGE: - case llvm::ELF::R_MIPS_GOT_OFST: case llvm::ELF::R_MIPS_SUB: case llvm::ELF::R_MIPS_INSERT_A: case llvm::ELF::R_MIPS_INSERT_B: @@ -193,17 +340,18 @@ void MipsRelocator::scanLocalReloc(Relocation& pReloc, case llvm::ELF::R_MIPS_CALL_HI16: case llvm::ELF::R_MIPS_GOT_LO16: case llvm::ELF::R_MIPS_CALL_LO16: - if (getTarget().getGOT().reserveLocalEntry(*rsym)) { + case llvm::ELF::R_MIPS_GOT_DISP: + case llvm::ELF::R_MIPS_GOT_PAGE: + case llvm::ELF::R_MIPS_GOT_OFST: + if (getTarget().getGOT().reserveLocalEntry(*rsym, + pReloc.type(), pReloc.A())) { if (getTarget().getGOT().hasMultipleGOT()) getTarget().checkAndSetHasTextRel(*pSection.getLink()); - // Remeber this rsym is a local GOT entry - getTarget().getGOT().setLocal(rsym); } break; case llvm::ELF::R_MIPS_GPREL32: case llvm::ELF::R_MIPS_GPREL16: case llvm::ELF::R_MIPS_LITERAL: - case llvm::ELF::R_MIPS_GOT_DISP: break; case llvm::ELF::R_MIPS_TLS_DTPMOD32: case llvm::ELF::R_MIPS_TLS_DTPREL32: @@ -219,17 +367,18 @@ void MipsRelocator::scanLocalReloc(Relocation& pReloc, case llvm::ELF::R_MIPS_TLS_TPREL_HI16: case llvm::ELF::R_MIPS_TLS_TPREL_LO16: break; + case llvm::ELF::R_MIPS_PC32: + break; default: - fatal(diag::unknown_relocation) << (int)pReloc.type() - << pReloc.symInfo()->name(); + fatal(diag::unknown_relocation) << (int)pReloc.type() << rsym->name(); } } -void MipsRelocator::scanGlobalReloc(Relocation& pReloc, +void MipsRelocator::scanGlobalReloc(MipsRelocationInfo& pReloc, IRBuilder& pBuilder, const LDSection& pSection) { - ResolveInfo* rsym = pReloc.symInfo(); + ResolveInfo* rsym = pReloc.parent().symInfo(); switch (pReloc.type()){ case llvm::ELF::R_MIPS_NONE: @@ -250,12 +399,15 @@ void MipsRelocator::scanGlobalReloc(Relocation& pReloc, case llvm::ELF::R_MIPS_LO16: if (getTarget().symbolNeedsDynRel(*rsym, false, true)) { getTarget().getRelDyn().reserveEntry(); - rsym->setReserved(rsym->reserved() | ReserveRel); - getTarget().checkAndSetHasTextRel(*pSection.getLink()); - - // Remeber this rsym is a global GOT entry (as if it needs an entry). - // Actually we don't allocate an GOT entry. - getTarget().getGOT().setGlobal(rsym); + if (getTarget().symbolNeedsCopyReloc(pReloc.parent(), *rsym)) { + LDSymbol& cpySym = defineSymbolforCopyReloc(pBuilder, *rsym); + addCopyReloc(*cpySym.resolveInfo()); + } + else { + // set Rel bit + rsym->setReserved(rsym->reserved() | ReserveRel); + getTarget().checkAndSetHasTextRel(*pSection.getLink()); + } } break; case llvm::ELF::R_MIPS_GOT16: @@ -270,18 +422,25 @@ void MipsRelocator::scanGlobalReloc(Relocation& pReloc, if (getTarget().getGOT().reserveGlobalEntry(*rsym)) { if (getTarget().getGOT().hasMultipleGOT()) getTarget().checkAndSetHasTextRel(*pSection.getLink()); - // Remeber this rsym is a global GOT entry - getTarget().getGOT().setGlobal(rsym); } break; case llvm::ELF::R_MIPS_LITERAL: case llvm::ELF::R_MIPS_GPREL32: fatal(diag::invalid_global_relocation) << (int)pReloc.type() - << pReloc.symInfo()->name(); + << rsym->name(); break; case llvm::ELF::R_MIPS_GPREL16: break; case llvm::ELF::R_MIPS_26: + // Create a PLT entry if the symbol requires it and does not have it. + if (getTarget().symbolNeedsPLT(*rsym) && + !(rsym->reserved() & ReservePLT)) { + getTarget().getPLT().reserveEntry(); + getTarget().getGOTPLT().reserve(); + getTarget().getRelPLT().reserveEntry(); + rsym->setReserved(rsym->reserved() | ReservePLT); + } + break; case llvm::ELF::R_MIPS_PC16: break; case llvm::ELF::R_MIPS_16: @@ -303,8 +462,8 @@ void MipsRelocator::scanGlobalReloc(Relocation& pReloc, case llvm::ELF::R_MIPS_TLS_TPREL_LO16: break; case llvm::ELF::R_MIPS_REL32: - break; case llvm::ELF::R_MIPS_JALR: + case llvm::ELF::R_MIPS_PC32: break; case llvm::ELF::R_MIPS_COPY: case llvm::ELF::R_MIPS_GLOB_DAT: @@ -312,156 +471,320 @@ void MipsRelocator::scanGlobalReloc(Relocation& pReloc, fatal(diag::dynamic_relocation) << (int)pReloc.type(); break; default: - fatal(diag::unknown_relocation) << (int)pReloc.type() - << pReloc.symInfo()->name(); + fatal(diag::unknown_relocation) << (int)pReloc.type() << rsym->name(); } } -//===----------------------------------------------------------------------===// -// Relocation helper function -//===----------------------------------------------------------------------===// -static const char * const GP_DISP_NAME = "_gp_disp"; +bool MipsRelocator::isPostponed(const Relocation& pReloc) const +{ + if (MipsRelocationInfo::HasSubType(pReloc, llvm::ELF::R_MIPS_HI16)) + return true; -// Find next R_MIPS_LO16 relocation paired to pReloc. -static -Relocation* helper_FindLo16Reloc(Relocation& pReloc) + if (MipsRelocationInfo::HasSubType(pReloc, llvm::ELF::R_MIPS_GOT16) && + pReloc.symInfo()->isLocal()) + return true; + + return false; +} + +void MipsRelocator::addCopyReloc(ResolveInfo& pSym) { - Relocation* reloc = static_cast<Relocation*>(pReloc.getNextNode()); - while (NULL != reloc) - { - if (llvm::ELF::R_MIPS_LO16 == reloc->type() && - reloc->symInfo() == pReloc.symInfo()) - return reloc; + Relocation& relEntry = *getTarget().getRelDyn().consumeEntry(); + relEntry.setType(llvm::ELF::R_MIPS_COPY); + assert(pSym.outSymbol()->hasFragRef()); + relEntry.targetRef().assign(*pSym.outSymbol()->fragRef()); + relEntry.setSymInfo(&pSym); +} - reloc = static_cast<Relocation*>(reloc->getNextNode()); +LDSymbol& MipsRelocator::defineSymbolforCopyReloc(IRBuilder& pBuilder, + const ResolveInfo& pSym) +{ + // Get or create corresponding BSS LDSection + ELFFileFormat* fileFormat = getTarget().getOutputFormat(); + LDSection* bssSectHdr = + ResolveInfo::ThreadLocal == pSym.type() ? &fileFormat->getTBSS() + : &fileFormat->getBSS(); + + // Get or create corresponding BSS SectionData + SectionData* bssData = + bssSectHdr->hasSectionData() ? bssSectHdr->getSectionData() + : IRBuilder::CreateSectionData(*bssSectHdr); + + // Determine the alignment by the symbol value + // FIXME: here we use the largest alignment + uint32_t addrAlign = config().targets().bitclass() / 8; + + // Allocate space in BSS for the copy symbol + Fragment* frag = new FillFragment(0x0, 1, pSym.size()); + uint64_t size = ObjectBuilder::AppendFragment(*frag, *bssData, addrAlign); + bssSectHdr->setSize(bssSectHdr->size() + size); + + // Change symbol binding to Global if it's a weak symbol + ResolveInfo::Binding binding = (ResolveInfo::Binding)pSym.binding(); + if (binding == ResolveInfo::Weak) + binding = ResolveInfo::Global; + + // Define the copy symbol in the bss section and resolve it + LDSymbol* cpySym = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>( + pSym.name(), + (ResolveInfo::Type)pSym.type(), + ResolveInfo::Define, + binding, + pSym.size(), // size + 0x0, // value + FragmentRef::Create(*frag, 0x0), + (ResolveInfo::Visibility)pSym.other()); + + // Output all other alias symbols if any + Module::AliasList* alias_list = pBuilder.getModule().getAliasList(pSym); + if (NULL == alias_list) + return *cpySym; + + for (Module::alias_iterator it = alias_list->begin(), ie = alias_list->end(); + it != ie; ++it) { + const ResolveInfo* alias = *it; + if (alias == &pSym || !alias->isDyn()) + continue; + + pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>( + alias->name(), + (ResolveInfo::Type)alias->type(), + ResolveInfo::Define, + binding, + alias->size(), // size + 0x0, // value + FragmentRef::Create(*frag, 0x0), + (ResolveInfo::Visibility)alias->other()); } - return NULL; + + return *cpySym; } -// Check the symbol is _gp_disp. -static -bool helper_isGpDisp(const Relocation& pReloc) +void MipsRelocator::postponeRelocation(Relocation& pReloc) { - const ResolveInfo* rsym = pReloc.symInfo(); - return 0 == strcmp(GP_DISP_NAME, rsym->name()); + ResolveInfo* rsym = pReloc.symInfo(); + m_PostponedRelocs[rsym].insert(&pReloc); } -static -Relocator::Address helper_GetGP(MipsRelocator& pParent) +void MipsRelocator::applyPostponedRelocations(MipsRelocationInfo& pLo16Reloc) { - return pParent.getTarget().getGOT().getGPAddr(pParent.getApplyingInput()); + m_CurrentLo16Reloc = &pLo16Reloc; + + ResolveInfo* rsym = pLo16Reloc.parent().symInfo(); + + RelocationSet & relocs = m_PostponedRelocs[rsym]; + for (RelocationSet::iterator it = relocs.begin(); it != relocs.end(); ++it) + (*it)->apply(*this); + + m_PostponedRelocs.erase(rsym); + + m_CurrentLo16Reloc = NULL; } -static -void helper_SetupRelDynForGOTEntry(MipsGOTEntry& got_entry, - Relocation& pReloc, - ResolveInfo* rsym, - MipsRelocator& pParent) +bool MipsRelocator::isGpDisp(const Relocation& pReloc) const { - MipsGNULDBackend& ld_backend = pParent.getTarget(); + return 0 == strcmp("_gp_disp", pReloc.symInfo()->name()); +} - Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry(); - rel_entry.setType(llvm::ELF::R_MIPS_REL32); - rel_entry.targetRef() = *FragmentRef::Create(got_entry, 0); - rel_entry.setSymInfo(rsym); +bool MipsRelocator::isRel() const +{ + return config().targets().is32Bits(); } -static -MipsGOTEntry& helper_GetGOTEntry(Relocation& pReloc, MipsRelocator& pParent) +bool MipsRelocator::isLocalReloc(ResolveInfo& pSym) const +{ + if (pSym.isUndef()) + return false; + + return pSym.isLocal() || + !getTarget().isDynamicSymbol(pSym) || + !pSym.isDyn(); +} + +Relocator::Address MipsRelocator::getGPAddress() +{ + return getTarget().getGOT().getGPAddr(getApplyingInput()); +} + +Relocator::Address MipsRelocator::getGP0() +{ + return getTarget().getGP0(getApplyingInput()); +} + +Fragment& MipsRelocator::getLocalGOTEntry(MipsRelocationInfo& pReloc, + Relocation::DWord entryValue) { // rsym - The relocation target symbol - ResolveInfo* rsym = pReloc.symInfo(); - MipsGNULDBackend& ld_backend = pParent.getTarget(); - MipsGOT& got = ld_backend.getGOT(); - MipsGOTEntry* got_entry; - - if (got.isLocal(rsym) && ResolveInfo::Section == rsym->type()) { - // Local section symbols consume local got entries. - got_entry = got.consumeLocal(); - if (got.isPrimaryGOTConsumed()) - helper_SetupRelDynForGOTEntry(*got_entry, pReloc, NULL, pParent); - return *got_entry; - } + ResolveInfo* rsym = pReloc.parent().symInfo(); + MipsGOT& got = getTarget().getGOT(); + + assert(isLocalReloc(*rsym) && + "Attempt to get a global GOT entry for the local relocation"); - got_entry = got.lookupEntry(rsym); - if (NULL != got_entry) { - // found a mapping, then return the mapped entry immediately + Fragment* got_entry = got.lookupLocalEntry(rsym, entryValue); + + // Found a mapping, then return the mapped entry immediately. + if (NULL != got_entry) return *got_entry; - } - // not found - if (got.isLocal(rsym)) - got_entry = got.consumeLocal(); + // Not found. + got_entry = got.consumeLocal(); + + if (got.isPrimaryGOTConsumed()) + setupRelDynEntry(*FragmentRef::Create(*got_entry, 0), NULL); else - got_entry = got.consumeGlobal(); + got.setEntryValue(got_entry, entryValue); - got.recordEntry(rsym, got_entry); + got.recordLocalEntry(rsym, entryValue, got_entry); - // If we first get this GOT entry, we should initialize it. - if (!got.isLocal(rsym) || ResolveInfo::Section != rsym->type()) { - if (!got.isPrimaryGOTConsumed()) - got_entry->setValue(pReloc.symValue()); - } + return *got_entry; +} + +Fragment& MipsRelocator::getGlobalGOTEntry(MipsRelocationInfo& pReloc) +{ + // rsym - The relocation target symbol + ResolveInfo* rsym = pReloc.parent().symInfo(); + MipsGOT& got = getTarget().getGOT(); + + assert(!isLocalReloc(*rsym) && + "Attempt to get a local GOT entry for the global relocation"); + + Fragment* got_entry = got.lookupGlobalEntry(rsym); + + // Found a mapping, then return the mapped entry immediately. + if (NULL != got_entry) + return *got_entry; + + // Not found. + got_entry = got.consumeGlobal(); if (got.isPrimaryGOTConsumed()) - helper_SetupRelDynForGOTEntry(*got_entry, pReloc, - got.isLocal(rsym) ? NULL : rsym, pParent); + setupRelDynEntry(*FragmentRef::Create(*got_entry, 0), rsym); + else + got.setEntryValue(got_entry, pReloc.parent().symValue()); + + got.recordGlobalEntry(rsym, got_entry); return *got_entry; } -static -Relocator::Address helper_GetGOTOffset(Relocation& pReloc, - MipsRelocator& pParent) +Relocator::Address MipsRelocator::getGOTOffset(MipsRelocationInfo& pReloc) { - MipsGNULDBackend& ld_backend = pParent.getTarget(); - MipsGOT& got = ld_backend.getGOT(); - MipsGOTEntry& got_entry = helper_GetGOTEntry(pReloc, pParent); - return got.getGPRelOffset(pParent.getApplyingInput(), got_entry); + ResolveInfo* rsym = pReloc.parent().symInfo(); + MipsGOT& got = getTarget().getGOT(); + + if (isLocalReloc(*rsym)) { + uint64_t value = pReloc.S(); + + if (ResolveInfo::Section == rsym->type()) + value += pReloc.A(); + + return got.getGPRelOffset(getApplyingInput(), + getLocalGOTEntry(pReloc, value)); + } + else { + return got.getGPRelOffset(getApplyingInput(), getGlobalGOTEntry(pReloc)); + } } -static -int32_t helper_CalcAHL(const Relocation& pHiReloc, const Relocation& pLoReloc) +void MipsRelocator::createDynRel(MipsRelocationInfo& pReloc) +{ + Relocator::DWord A = pReloc.A(); + Relocator::DWord S = pReloc.S(); + + ResolveInfo* rsym = pReloc.parent().symInfo(); + + if (isLocalReloc(*rsym)) { + setupRelDynEntry(pReloc.parent().targetRef(), NULL); + pReloc.result() = A + S; + } + else { + setupRelDynEntry(pReloc.parent().targetRef(), rsym); + // Don't add symbol value that will be resolved by the dynamic linker. + pReloc.result() = A; + } +} + +uint64_t MipsRelocator::calcAHL(const MipsRelocationInfo& pHiReloc) { - assert((pHiReloc.type() == llvm::ELF::R_MIPS_HI16 || - pHiReloc.type() == llvm::ELF::R_MIPS_GOT16) && - pLoReloc.type() == llvm::ELF::R_MIPS_LO16 && - "Incorrect type of relocation for AHL calculation"); + assert(NULL != m_CurrentLo16Reloc && + "There is no saved R_MIPS_LO16 relocation"); - // Note the addend is section symbol offset here - assert (pHiReloc.addend() == pLoReloc.addend()); + uint64_t AHI = pHiReloc.A() & 0xFFFF; + uint64_t ALO = m_CurrentLo16Reloc->A() & 0xFFFF; + uint64_t AHL = (AHI << 16) + int16_t(ALO); - int32_t AHI = pHiReloc.target(); - int32_t ALO = pLoReloc.target(); - int32_t AHL = ((AHI & 0xFFFF) << 16) + (int16_t)(ALO & 0xFFFF) + - pLoReloc.addend(); return AHL; } -static -void helper_DynRel(Relocation& pReloc, MipsRelocator& pParent) +bool MipsRelocator::isN64ABI() const { - ResolveInfo* rsym = pReloc.symInfo(); - MipsGNULDBackend& ld_backend = pParent.getTarget(); - MipsGOT& got = ld_backend.getGOT(); + return config().targets().is64Bits(); +} - Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry(); +uint64_t MipsRelocator::getPLTAddress(ResolveInfo& rsym) +{ + assert((rsym.reserved() & MipsRelocator::ReservePLT) && + "Symbol does not require a PLT entry"); - rel_entry.setType(llvm::ELF::R_MIPS_REL32); - rel_entry.targetRef() = pReloc.targetRef(); + SymPLTMap::const_iterator it = m_SymPLTMap.find(&rsym); - Relocator::DWord A = pReloc.target() + pReloc.addend(); - Relocator::DWord S = pReloc.symValue(); + Fragment* plt; - if (got.isLocal(rsym)) { - rel_entry.setSymInfo(NULL); - pReloc.target() = A + S; + if (it != m_SymPLTMap.end()) { + plt = it->second.first; } else { - rel_entry.setSymInfo(rsym); - // Don't add symbol value that will be resolved by the dynamic linker - pReloc.target() = A; + plt = getTarget().getPLT().consume(); + + Fragment* got = getTarget().getGOTPLT().consume(); + Relocation* rel = getTarget().getRelPLT().consumeEntry(); + + rel->setType(llvm::ELF::R_MIPS_JUMP_SLOT); + rel->targetRef().assign(*got); + rel->setSymInfo(&rsym); + + m_SymPLTMap[&rsym] = PLTDescriptor(plt, got); } + + return getTarget().getPLT().addr() + plt->getOffset(); +} + +//===----------------------------------------------------------------------===// +// Mips32Relocator +//===----------------------------------------------------------------------===// +Mips32Relocator::Mips32Relocator(Mips32GNULDBackend& pParent, + const LinkerConfig& pConfig) + : MipsRelocator(pParent, pConfig) +{} + +void Mips32Relocator::setupRelDynEntry(FragmentRef& pFragRef, ResolveInfo* pSym) +{ + Relocation& relEntry = *getTarget().getRelDyn().consumeEntry(); + relEntry.setType(llvm::ELF::R_MIPS_REL32); + relEntry.targetRef() = pFragRef; + relEntry.setSymInfo(pSym); +} + +//===----------------------------------------------------------------------===// +// Mips64Relocator +//===----------------------------------------------------------------------===// +Mips64Relocator::Mips64Relocator(Mips64GNULDBackend& pParent, + const LinkerConfig& pConfig) + : MipsRelocator(pParent, pConfig) +{} + +void Mips64Relocator::setupRelDynEntry(FragmentRef& pFragRef, ResolveInfo* pSym) +{ + Relocation::Type type = llvm::ELF::R_MIPS_REL32 | + llvm::ELF::R_MIPS_64 << 8; + // FIXME (simon): Fix dynamic relocations. + type = llvm::ELF::R_MIPS_NONE; + + Relocation& relEntry = *getTarget().getRelDyn().consumeEntry(); + relEntry.setType(type); + relEntry.targetRef() = pFragRef; + relEntry.setSymInfo(pSym); } //=========================================// @@ -470,35 +793,60 @@ void helper_DynRel(Relocation& pReloc, MipsRelocator& pParent) // R_MIPS_NONE and those unsupported/deprecated relocation type static -MipsRelocator::Result none(Relocation& pReloc, MipsRelocator& pParent) +MipsRelocator::Result none(MipsRelocationInfo& pReloc, MipsRelocator& pParent) { return MipsRelocator::OK; } // R_MIPS_32: S + A static -MipsRelocator::Result abs32(Relocation& pReloc, MipsRelocator& pParent) +MipsRelocator::Result abs32(MipsRelocationInfo& pReloc, MipsRelocator& pParent) { - ResolveInfo* rsym = pReloc.symInfo(); + ResolveInfo* rsym = pReloc.parent().symInfo(); + + Relocator::DWord A = pReloc.A(); + Relocator::DWord S = pReloc.S(); - Relocator::DWord A = pReloc.target() + pReloc.addend(); - Relocator::DWord S = pReloc.symValue(); + LDSection& target_sect = + pReloc.parent().targetRef().frag()->getParent()->getSection(); - LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection(); // If the flag of target section is not ALLOC, we will not scan this relocation // but perform static relocation. (e.g., applying .debug section) if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) { - pReloc.target() = S + A; + pReloc.result() = S + A; return MipsRelocator::OK; } if (rsym->reserved() & MipsRelocator::ReserveRel) { - helper_DynRel(pReloc, pParent); - + pParent.createDynRel(pReloc); return MipsRelocator::OK; } - pReloc.target() = (S + A); + pReloc.result() = S + A; + + return MipsRelocator::OK; +} + +// R_MIPS_26: +// local : ((A | ((P + 4) & 0x3F000000)) + S) >> 2 +// external: (sign–extend(A) + S) >> 2 +static +MipsRelocator::Result rel26(MipsRelocationInfo& pReloc, MipsRelocator& pParent) +{ + ResolveInfo* rsym = pReloc.parent().symInfo(); + + int32_t A = ((pReloc.parent().target() & 0x03FFFFFF) << 2); + int32_t P = pReloc.P(); + int32_t S = rsym->reserved() & MipsRelocator::ReservePLT + ? pParent.getPLTAddress(*rsym) + : pReloc.S(); + + if (rsym->isLocal()) + pReloc.result() = A | ((P + 4) & 0x3F000000); + else + pReloc.result() = mcld::signExtend<28>(A); + + pReloc.result() = (pReloc.result() + S) >> 2; return MipsRelocator::OK; } @@ -507,29 +855,23 @@ MipsRelocator::Result abs32(Relocation& pReloc, MipsRelocator& pParent) // local/external: ((AHL + S) - (short)(AHL + S)) >> 16 // _gp_disp : ((AHL + GP - P) - (short)(AHL + GP - P)) >> 16 static -MipsRelocator::Result hi16(Relocation& pReloc, MipsRelocator& pParent) +MipsRelocator::Result hi16(MipsRelocationInfo& pReloc, MipsRelocator& pParent) { - Relocation* lo_reloc = helper_FindLo16Reloc(pReloc); - assert(NULL != lo_reloc && "There is no paired R_MIPS_LO16 for R_MIPS_HI16"); - - int32_t AHL = helper_CalcAHL(pReloc, *lo_reloc); - int32_t res = 0; - - pParent.setAHL(AHL); + uint64_t AHL = pParent.calcAHL(pReloc); - if (helper_isGpDisp(pReloc)) { - int32_t P = pReloc.place(); - int32_t GP = helper_GetGP(pParent); - res = ((AHL + GP - P) - (int16_t)(AHL + GP - P)) >> 16; + if (pParent.isGpDisp(pReloc.parent())) { + int32_t P = pReloc.P(); + int32_t GP = pParent.getGPAddress(); + pReloc.result() = ((AHL + GP - P) - (int16_t)(AHL + GP - P)) >> 16; } else { - int32_t S = pReloc.symValue(); - res = ((AHL + S) - (int16_t)(AHL + S)) >> 16; + int32_t S = pReloc.S(); + if (pParent.isN64ABI()) + pReloc.result() = (pReloc.A() + S + 0x8000ull) >> 16; + else + pReloc.result() = ((AHL + S) - (int16_t)(AHL + S)) >> 16; } - pReloc.target() &= 0xFFFF0000; - pReloc.target() |= (res & 0xFFFF); - return MipsRelocator::OK; } @@ -537,27 +879,45 @@ MipsRelocator::Result hi16(Relocation& pReloc, MipsRelocator& pParent) // local/external: AHL + S // _gp_disp : AHL + GP - P + 4 static -MipsRelocator::Result lo16(Relocation& pReloc, MipsRelocator& pParent) +MipsRelocator::Result lo16(MipsRelocationInfo& pReloc, MipsRelocator& pParent) { - int32_t res = 0; - - if (helper_isGpDisp(pReloc)) { - int32_t P = pReloc.place(); - int32_t GP = helper_GetGP(pParent); - int32_t AHL = pParent.getAHL(); - res = AHL + GP - P + 4; + // AHL is a combination of HI16 and LO16 addends. But R_MIPS_LO16 + // uses low 16 bits of the AHL. That is why we do not need R_MIPS_HI16 + // addend here. + int32_t AHL = (pReloc.A() & 0xFFFF); + + if (pParent.isGpDisp(pReloc.parent())) { + int32_t P = pReloc.P(); + int32_t GP = pParent.getGPAddress(); + pReloc.result() = AHL + GP - P + 4; } else { - int32_t S = pReloc.symValue(); - // The previous AHL may be for other hi/lo pairs. - // We need to calcuate the lo part now. It is easy. - // Remember to add the section offset to ALO. - int32_t ALO = (pReloc.target() & 0xFFFF) + pReloc.addend(); - res = ALO + S; + int32_t S = pReloc.S(); + pReloc.result() = AHL + S; } - pReloc.target() &= 0xFFFF0000; - pReloc.target() |= (res & 0xFFFF); + pParent.applyPostponedRelocations(pReloc); + + return MipsRelocator::OK; +} + +// R_MIPS_GPREL16: +// external: sign–extend(A) + S - GP +// local : sign–extend(A) + S + GP0 – GP +static +MipsRelocator::Result gprel16(MipsRelocationInfo& pReloc, MipsRelocator& pParent) +{ + // Remember to add the section offset to A. + uint64_t A = pReloc.A(); + uint64_t S = pReloc.S(); + uint64_t GP0 = pParent.getGP0(); + uint64_t GP = pParent.getGPAddress(); + + ResolveInfo* rsym = pReloc.parent().symInfo(); + if (rsym->isLocal()) + pReloc.result() = A + S + GP0 - GP; + else + pReloc.result() = A + S - GP; return MipsRelocator::OK; } @@ -566,52 +926,35 @@ MipsRelocator::Result lo16(Relocation& pReloc, MipsRelocator& pParent) // local : G (calculate AHL and put high 16 bit to GOT) // external: G static -MipsRelocator::Result got16(Relocation& pReloc, MipsRelocator& pParent) +MipsRelocator::Result got16(MipsRelocationInfo& pReloc, MipsRelocator& pParent) { - MipsGNULDBackend& ld_backend = pParent.getTarget(); - MipsGOT& got = ld_backend.getGOT(); - ResolveInfo* rsym = pReloc.symInfo(); - Relocator::Address G = 0; - - if (rsym->isLocal()) { - Relocation* lo_reloc = helper_FindLo16Reloc(pReloc); - assert(NULL != lo_reloc && "There is no paired R_MIPS_LO16 for R_MIPS_GOT16"); - - int32_t AHL = helper_CalcAHL(pReloc, *lo_reloc); - int32_t S = pReloc.symValue(); + if (pReloc.parent().symInfo()->isLocal()) { + int32_t AHL = pParent.calcAHL(pReloc); + int32_t S = pReloc.S(); + int32_t res = (AHL + S + 0x8000) & 0xFFFF0000; - pParent.setAHL(AHL); + MipsGOT& got = pParent.getTarget().getGOT(); - int32_t res = (AHL + S + 0x8000) & 0xFFFF0000; - MipsGOTEntry& got_entry = helper_GetGOTEntry(pReloc, pParent); + Fragment& got_entry = pParent.getLocalGOTEntry(pReloc, res); - got_entry.setValue(res); - G = got.getGPRelOffset(pParent.getApplyingInput(), got_entry); + pReloc.result() = got.getGPRelOffset(pParent.getApplyingInput(), got_entry); } else { - G = helper_GetGOTOffset(pReloc, pParent); + pReloc.result() = pParent.getGOTOffset(pReloc); } - pReloc.target() &= 0xFFFF0000; - pReloc.target() |= (G & 0xFFFF); - return MipsRelocator::OK; } // R_MIPS_GOTHI16: // external: (G - (short)G) >> 16 + A static -MipsRelocator::Result gothi16(Relocation& pReloc, MipsRelocator& pParent) +MipsRelocator::Result gothi16(MipsRelocationInfo& pReloc, MipsRelocator& pParent) { - int32_t res = 0; - - Relocator::Address G = helper_GetGOTOffset(pReloc, pParent); - int32_t A = pReloc.target() + pReloc.addend(); + Relocator::Address G = pParent.getGOTOffset(pReloc); + int32_t A = pReloc.A(); - res = (G - (int16_t)G) >> (16 + A); - - pReloc.target() &= 0xFFFF0000; - pReloc.target() |= (res & 0xFFFF); + pReloc.result() = (G - (int16_t)G) >> (16 + A); return MipsRelocator::OK; } @@ -619,41 +962,145 @@ MipsRelocator::Result gothi16(Relocation& pReloc, MipsRelocator& pParent) // R_MIPS_GOTLO16: // external: G & 0xffff static -MipsRelocator::Result gotlo16(Relocation& pReloc, MipsRelocator& pParent) +MipsRelocator::Result gotlo16(MipsRelocationInfo& pReloc, MipsRelocator& pParent) { - Relocator::Address G = helper_GetGOTOffset(pReloc, pParent); + pReloc.result() = pParent.getGOTOffset(pReloc) & 0xffff; - pReloc.target() &= 0xFFFF0000; - pReloc.target() |= (G & 0xFFFF); + return MipsRelocator::OK; +} + +// R_MIPS_SUB: +// external/local: S - A +static +MipsRelocator::Result sub(MipsRelocationInfo& pReloc, MipsRelocator& pParent) +{ + uint64_t S = pReloc.S(); + uint64_t A = pReloc.A(); + + pReloc.result() = S - A; return MipsRelocator::OK; } // R_MIPS_CALL16: G static -MipsRelocator::Result call16(Relocation& pReloc, MipsRelocator& pParent) +MipsRelocator::Result call16(MipsRelocationInfo& pReloc, MipsRelocator& pParent) { - Relocator::Address G = helper_GetGOTOffset(pReloc, pParent); - - pReloc.target() &= 0xFFFF0000; - pReloc.target() |= (G & 0xFFFF); + pReloc.result() = pParent.getGOTOffset(pReloc); return MipsRelocator::OK; } // R_MIPS_GPREL32: A + S + GP0 - GP static -MipsRelocator::Result gprel32(Relocation& pReloc, MipsRelocator& pParent) +MipsRelocator::Result gprel32(MipsRelocationInfo& pReloc, MipsRelocator& pParent) { // Remember to add the section offset to A. - int32_t A = pReloc.target() + pReloc.addend(); - int32_t S = pReloc.symValue(); - int32_t GP = helper_GetGP(pParent); + uint64_t A = pReloc.A(); + uint64_t S = pReloc.S(); + uint64_t GP0 = pParent.getGP0(); + uint64_t GP = pParent.getGPAddress(); + + pReloc.result() = A + S + GP0 - GP; + + return MipsRelocator::OK; +} + +// R_MIPS_64: S + A +static +MipsRelocator::Result abs64(MipsRelocationInfo& pReloc, MipsRelocator& pParent) +{ + // FIXME (simon): Consider to merge with abs32() or use the same function + // but with another mask size. + ResolveInfo* rsym = pReloc.parent().symInfo(); + + Relocator::DWord A = pReloc.A(); + Relocator::DWord S = pReloc.S(); + + LDSection& target_sect = + pReloc.parent().targetRef().frag()->getParent()->getSection(); + + // If the flag of target section is not ALLOC, we will not scan this relocation + // but perform static relocation. (e.g., applying .debug section) + if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) { + pReloc.result() = S + A; + return MipsRelocator::OK; + } + + if (rsym->reserved() & MipsRelocator::ReserveRel) { + pParent.createDynRel(pReloc); + return MipsRelocator::OK; + } - // llvm does not emits SHT_MIPS_REGINFO section. - // Assume that GP0 is zero. - pReloc.target() = (A + S - GP) & 0xFFFFFFFF; + pReloc.result() = S + A; return MipsRelocator::OK; } +// R_MIPS_GOT_DISP / R_MIPS_GOT_PAGE: G +static +MipsRelocator::Result gotdisp(MipsRelocationInfo& pReloc, MipsRelocator& pParent) +{ + pReloc.result() = pParent.getGOTOffset(pReloc); + + return MipsRelocator::OK; +} + +// R_MIPS_GOT_OFST: +static +MipsRelocator::Result gotoff(MipsRelocationInfo& pReloc, MipsRelocator& pParent) +{ + // FIXME (simon): Needs to be implemented. + return MipsRelocator::OK; +} + +// R_MIPS_JALR: +static +MipsRelocator::Result jalr(MipsRelocationInfo& pReloc, MipsRelocator& pParent) +{ + return MipsRelocator::OK; +} + +// R_MIPS_LA25_LUI +static +MipsRelocator::Result la25lui(MipsRelocationInfo& pReloc, MipsRelocator& pParent) +{ + int32_t S = pReloc.S(); + + pReloc.result() = (S + 0x8000) >> 16; + + return MipsRelocator::OK; +} + +// R_MIPS_LA25_J +static +MipsRelocator::Result la25j(MipsRelocationInfo& pReloc, MipsRelocator& pParent) +{ + int32_t S = pReloc.S(); + + pReloc.result() = S >> 2; + + return MipsRelocator::OK; +} + +// R_MIPS_LA25_ADD +static +MipsRelocator::Result la25add(MipsRelocationInfo& pReloc, MipsRelocator& pParent) +{ + pReloc.result() = pReloc.S(); + + return MipsRelocator::OK; +} + +// R_MIPS_PC32: +static +MipsRelocator::Result pc32(MipsRelocationInfo& pReloc, MipsRelocator& pParent) +{ + return MipsRelocator::OK; +} + +static +MipsRelocator::Result unsupport(MipsRelocationInfo& pReloc, MipsRelocator& pParent) +{ + return MipsRelocator::Unsupport; +} |