//===- impl.cpp -----------------------------------------------------------===// // // The MCLinker Project // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "ARMGOT.h" #include <mcld/LD/LDFileFormat.h> #include <mcld/Support/MemoryRegion.h> #include <llvm/Support/ErrorHandling.h> #include <new> namespace { const size_t ARMGOTEntrySize = 4; } // end of anonymous namespace using namespace mcld; //===----------------------------------------------------------------------===// // ARMGOT ARMGOT::ARMGOT(LDSection& pSection, llvm::MCSectionData& pSectionData) : GOT(pSection, pSectionData, ARMGOTEntrySize), m_NormalGOTIterator(), m_GOTPLTIterator(), m_GOTPLTBegin(), m_GOTPLTEnd() { GOTEntry* Entry = 0; // Create GOT0 entries. for (int i = 0; i < 3; i++) { Entry = new (std::nothrow) GOTEntry(0, ARMGOTEntrySize, &m_SectionData); if (!Entry) llvm::report_fatal_error("Allocating GOT0 entries failed!"); m_Section.setSize(m_Section.size() + ARMGOTEntrySize); } // Skip GOT0 entries. iterator it = m_SectionData.begin(); iterator ie = m_SectionData.end(); for (int i = 1; i < ARMGOT0Num; ++i) { if (it == ie) llvm::report_fatal_error("Generation of GOT0 entries is incomplete!"); ++it; } m_NormalGOTIterator = it; m_GOTPLTIterator = it; m_GOTPLTBegin = it; m_GOTPLTEnd = it; } ARMGOT::~ARMGOT() { } void ARMGOT::reserveEntry(size_t pNum) { GOTEntry* Entry = 0; for (size_t i = 0; i < pNum; i++) { Entry = new (std::nothrow) GOTEntry(0, ARMGOTEntrySize, &m_SectionData); if (!Entry) llvm::report_fatal_error("Allocating new memory for GOTEntry failed"); m_Section.setSize(m_Section.size() + ARMGOTEntrySize); } } void ARMGOT::reserveGOTPLTEntry() { GOTEntry* got_entry = 0; got_entry= new GOTEntry(0, getEntrySize(),&(getSectionData())); if (!got_entry) llvm::report_fatal_error("Allocating new memory for GOT failed!"); m_Section.setSize(m_Section.size() + getEntrySize()); ++m_GOTPLTEnd; ++m_NormalGOTIterator; } GOTEntry* ARMGOT::getEntry(const ResolveInfo& pInfo, bool& pExist) { GOTEntry *&Entry = m_NormalGOTMap[&pInfo]; pExist = 1; if (!Entry) { pExist = 0; ++m_NormalGOTIterator; assert(m_NormalGOTIterator != m_SectionData.getFragmentList().end() && "The number of GOT Entries and ResolveInfo doesn't match!"); Entry = llvm::cast<GOTEntry>(&(*m_NormalGOTIterator)); } return Entry; } void ARMGOT::applyGOT0(uint64_t pAddress) { llvm::cast<GOTEntry> (*(m_SectionData.getFragmentList().begin())).setContent(pAddress); } void ARMGOT::applyAllGOTPLT(uint64_t pPLTBase) { iterator begin = getGOTPLTBegin(); iterator end = getGOTPLTEnd(); for (;begin != end ;++begin) llvm::cast<GOTEntry>(*begin).setContent(pPLTBase); } GOTEntry*& ARMGOT::lookupGOTPLTMap(const ResolveInfo& pSymbol) { return m_GOTPLTMap[&pSymbol]; } ARMGOT::iterator ARMGOT::begin() { return m_SectionData.getFragmentList().begin(); } ARMGOT::const_iterator ARMGOT::begin() const { return m_SectionData.getFragmentList().begin(); } ARMGOT::iterator ARMGOT::end() { return m_SectionData.getFragmentList().end(); } ARMGOT::const_iterator ARMGOT::end() const { return m_SectionData.getFragmentList().end(); } ARMGOT::iterator ARMGOT::getNextGOTPLTEntry() { return ++m_GOTPLTIterator; } ARMGOT::iterator ARMGOT::getGOTPLTBegin() { // Move to the first GOTPLT entry from last GOT0 entry. iterator begin = m_GOTPLTBegin; return ++begin; } const ARMGOT::iterator ARMGOT::getGOTPLTEnd() { // Move to end or the first normal GOT entry from the last GOTPLT entry. iterator end = m_GOTPLTEnd; return ++end; } uint64_t ARMGOT::emit(MemoryRegion& pRegion) { uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer()); GOTEntry* got = 0; unsigned int entry_size = getEntrySize(); uint64_t result = 0x0; for (iterator it = begin(), ie = end(); it != ie; ++it, ++buffer) { got = &(llvm::cast<GOTEntry>((*it))); *buffer = static_cast<uint32_t>(got->getContent()); result += entry_size; } return result; }