//===- 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 "mcld/IRBuilder.h"
#include "mcld/LD/LDSection.h"
#include "mcld/LD/RelocationFactory.h"
#include "mcld/Support/MsgHandling.h"
#include "mcld/Module.h"

#include <llvm/Support/Casting.h>

namespace mcld {

//===----------------------------------------------------------------------===//
// OutputRelocSection
//===----------------------------------------------------------------------===//
OutputRelocSection::OutputRelocSection(Module& pModule, LDSection& pSection)
    : m_Module(pModule),
      m_pRelocData(NULL),
      m_isVisit(false),
      m_ValidEntryIterator() {
  assert(!pSection.hasRelocData() &&
         "Given section is not a relocation section");
  m_pRelocData = IRBuilder::CreateRelocData(pSection);
}

OutputRelocSection::~OutputRelocSection() {
}

Relocation* OutputRelocSection::create() {
  Relocation* reloc = Relocation::Create();
  m_pRelocData->append(*reloc);
  return reloc;
}

void OutputRelocSection::reserveEntry(size_t pNum) {
  for (size_t i = 0; i < pNum; ++i)
    m_pRelocData->append(*Relocation::Create());
}

Relocation* OutputRelocSection::consumeEntry() {
  // first time visit this function, set m_ValidEntryIterator to
  // Fragments.begin()
  if (!m_isVisit) {
    assert(!m_pRelocData->getRelocationList().empty() &&
           "DynRelSection contains no entries.");
    m_ValidEntryIterator = m_pRelocData->begin();
    m_isVisit = true;
  } else {
    // Add m_ValidEntryIterator here instead of at the end of this function.
    // We may reserve an entry and then consume it immediately, e.g. for COPY
    // relocation, so we need to avoid setting this iterator to
    // RelocData->end() in any case, or when reserve and consume again,
    // ++m_ValidEntryIterator will still be RelocData->end().
    ++m_ValidEntryIterator;
  }
  assert(m_ValidEntryIterator != m_pRelocData->end() &&
         "No empty relocation entry for the incoming symbol.");

  return &(*m_ValidEntryIterator);
}

size_t OutputRelocSection::numOfRelocs() {
  return m_pRelocData->size();
}

bool OutputRelocSection::addSymbolToDynSym(LDSymbol& pSymbol) {
  m_Module.getSymbolTable().changeToDynamic(pSymbol);
  return true;
}

}  // namespace mcld