C++程序  |  164行  |  3.94 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 <llvm/Support/Casting.h>

#include <mcld/LD/LDSection.h>
#include <mcld/LD/LDFileFormat.h>
#include <mcld/Support/MemoryRegion.h>
#include <mcld/Support/MsgHandling.h>

namespace {
  const unsigned int ARMGOT0Num = 3;
} // end of anonymous namespace

using namespace mcld;

//===----------------------------------------------------------------------===//
// ARMGOT
ARMGOT::ARMGOT(LDSection& pSection)
  : GOT(pSection), m_pLast(NULL)
{
  // Create GOT0 entries.
  reserve(ARMGOT0Num);

  // Skip GOT0 entries.
  for (unsigned int i = 0; i < ARMGOT0Num; ++i) {
    consume();
  }
}

ARMGOT::~ARMGOT()
{
}

bool ARMGOT::hasGOT1() const
{
  return (m_SectionData->size() > ARMGOT0Num);
}

void ARMGOT::reserve(size_t pNum)
{
  for (size_t i = 0; i < pNum; i++) {
    new ARMGOTEntry(0, m_SectionData);
  }
}

ARMGOTEntry* ARMGOT::consume()
{
  if (NULL == m_pLast) {
    assert(!empty() && "Consume empty GOT entry!");
    m_pLast = llvm::cast<ARMGOTEntry>(&m_SectionData->front());
    return m_pLast;
  }

  m_pLast = llvm::cast<ARMGOTEntry>(m_pLast->getNextNode());
  return m_pLast;
}

void ARMGOT::reserveGOTPLT()
{
  ARMGOTEntry* entry = new ARMGOTEntry(0, m_SectionData);
  if (NULL == m_GOTPLT.front) {
    // GOTPLT is empty
    if (NULL == m_GOT.front) {
      // GOT part is also empty. Since entry is the last entry, we can assign
      // it to GOTPLT directly.
      m_GOTPLT.front = entry;
    }
    else {
      // GOTn is not empty. Shift GOTn backward by one entry.
      m_GOTPLT.front = m_GOT.front;
      m_GOT.front = llvm::cast<ARMGOTEntry>(m_GOT.front->getNextNode());
    }
  }
  else {
    // GOTPLT is not empty
    if (NULL != m_GOT.front)
      m_GOT.front = llvm::cast<ARMGOTEntry>(m_GOT.front->getNextNode());
  }
}

void ARMGOT::reserveGOT()
{
  ARMGOTEntry* entry = new ARMGOTEntry(0, m_SectionData);
  if (NULL == m_GOT.front) {
    // Entry must be the last entry. We can directly assign it to GOT part.
    m_GOT.front = entry;
  }
}

ARMGOTEntry* ARMGOT::consumeGOTPLT()
{
  assert(NULL != m_GOTPLT.front && "Consuming empty GOTPLT section!");

  if (NULL == m_GOTPLT.last_used) {
    m_GOTPLT.last_used = m_GOTPLT.front;
  }
  else {
    m_GOTPLT.last_used = llvm::cast<ARMGOTEntry>(m_GOTPLT.last_used->getNextNode());
    assert(m_GOTPLT.last_used != m_GOT.front && "No GOT/PLT entry to consume!");
  }
  return m_GOTPLT.last_used;
}

ARMGOTEntry* ARMGOT::consumeGOT()
{
  assert(NULL != m_GOT.front && "Consuming empty GOT section!");

  if (NULL == m_GOT.last_used) {
    m_GOT.last_used = m_GOT.front;
  }
  else {
    m_GOT.last_used = llvm::cast<ARMGOTEntry>(m_GOT.last_used->getNextNode());
    assert(m_GOT.last_used != NULL && "No GOTn entry to consume!");
  }
  return m_GOT.last_used;
}

void ARMGOT::applyGOT0(uint64_t pAddress)
{
  llvm::cast<ARMGOTEntry>
    (*(m_SectionData->getFragmentList().begin())).setValue(pAddress);
}

void ARMGOT::applyGOTPLT(uint64_t pPLTBase)
{
  if (NULL == m_GOTPLT.front)
    return;

  SectionData::iterator entry(m_GOTPLT.front);
  SectionData::iterator e_end;
  if (NULL == m_GOT.front)
    e_end = m_SectionData->end();
  else
    e_end = SectionData::iterator(m_GOT.front);

  while (entry != e_end) {
    llvm::cast<ARMGOTEntry>(entry)->setValue(pPLTBase);
    ++entry;
  }
}

uint64_t ARMGOT::emit(MemoryRegion& pRegion)
{
  uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());

  ARMGOTEntry* got = NULL;
  uint64_t result = 0x0;
  for (iterator it = begin(), ie = end(); it != ie; ++it, ++buffer) {
      got = &(llvm::cast<ARMGOTEntry>((*it)));
      *buffer = static_cast<uint32_t>(got->getValue());
      result += ARMGOTEntry::EntrySize;
  }
  return result;
}