C++程序  |  185行  |  4.33 KB

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