//===- OutputRelocSection.cpp ---------------------------------------------===//
//
//                     The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include <mcld/Target/OutputRelocSection.h>

#include <llvm/Support/Casting.h>

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

using namespace mcld;

//===----------------------------------------------------------------------===//
// OutputRelocSection
//===----------------------------------------------------------------------===//
OutputRelocSection::OutputRelocSection(LDSection& pSection,
                                       SectionData& pSectionData,
                                       unsigned int pEntrySize)
  : m_pSection(&pSection),
    m_pSectionData(&pSectionData),
    m_EntryBytes(pEntrySize),
    m_isVisit(false),
    m_ValidEntryIterator(){
}

OutputRelocSection::~OutputRelocSection()
{
}

void OutputRelocSection::reserveEntry(RelocationFactory& pRelFactory,
                                      size_t pNum)
{
  for(size_t i=0; i<pNum; i++) {
    m_pSectionData->getFragmentList().push_back(pRelFactory.produceEmptyEntry());
    // update section size
    m_pSection->setSize(m_pSection->size() + m_EntryBytes);
  }
}

Relocation* OutputRelocSection::getEntry(const ResolveInfo& pSymbol,
                                         bool isForGOT,
                                         bool& pExist)
{
  // first time visit this function, set m_ValidEntryIterator to
  // Fragments.begin()
  if(!m_isVisit) {
    assert( !m_pSectionData->getFragmentList().empty() &&
             "DynRelSection contains no entries.");
    m_ValidEntryIterator = m_pSectionData->getFragmentList().begin();
    m_isVisit = true;
  }

  assert(m_ValidEntryIterator != m_pSectionData->end() &&
         "No empty relocation entry for the incoming symbol.");

  // if this relocation is used to relocate GOT (.got or .got.plt),
  // check if we've gotten an entry for this symbol before. If yes,
  // return the found entry in map.
  // Otherwise, this relocation is used to relocate general section
  // (data or text section), return an empty entry directly.
  Relocation* result;

  if(isForGOT) {
    // get or create entry in m_SymRelMap
    Relocation *&entry = m_SymRelMap[&pSymbol];
    pExist = true;

    if(NULL == entry) {
      pExist = false;
      entry = llvm::cast<Relocation>(&(*m_ValidEntryIterator));
      ++m_ValidEntryIterator;
    }
    result = entry;
  }
  else {
    pExist = false;
    result = llvm::cast<Relocation>(&(*m_ValidEntryIterator));
    ++m_ValidEntryIterator;
  }
  return result;
}