//===- MipsGOT.cpp --------------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "MipsGOT.h"
#include <llvm/Support/Casting.h>
#include <mcld/LD/ResolveInfo.h>
#include <mcld/Support/MemoryRegion.h>
#include <mcld/Support/MsgHandling.h>
namespace {
const size_t MipsGOT0Num = 1;
}
using namespace mcld;
//===----------------------------------------------------------------------===//
// MipsGOT
//===----------------------------------------------------------------------===//
MipsGOT::MipsGOT(LDSection& pSection)
: GOT(pSection),
m_pLocalNum(0),
m_pLast(NULL)
{
// Create GOT0 entries.
reserve(MipsGOT0Num);
// Skip GOT0 entries.
iterator it = m_SectionData->begin();
for (size_t i = 1; i < MipsGOT0Num; ++i) {
assert((it != m_SectionData->end()) &&
"Generation of GOT0 entries is incomplete!");
++it;
}
m_LocalGOTIterator = it;
m_GlobalGOTIterator = it;
m_pLocalNum = MipsGOT0Num;
}
void MipsGOT::reserve(size_t pNum)
{
for (size_t i = 0; i < pNum; i++) {
new MipsGOTEntry(0, m_SectionData);
}
}
MipsGOTEntry* MipsGOT::consume()
{
if (NULL == m_pLast) {
assert(!empty() && "Consume empty GOT entry!");
m_pLast = llvm::cast<MipsGOTEntry>(&m_SectionData->front());
return m_pLast;
}
m_pLast = llvm::cast<MipsGOTEntry>(m_pLast->getNextNode());
return m_pLast;
}
bool MipsGOT::hasGOT1() const
{
return (m_SectionData->size() > MipsGOT0Num);
}
uint64_t MipsGOT::emit(MemoryRegion& pRegion)
{
uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());
uint64_t result = 0;
for (iterator it = begin(), ie = end();
it != ie; ++it, ++buffer) {
MipsGOTEntry* got = &(llvm::cast<MipsGOTEntry>((*it)));
*buffer = static_cast<uint32_t>(got->getValue());
result += got->size();
}
return result;
}
void MipsGOT::reserveLocalEntry()
{
reserve(1);
++m_pLocalNum;
// Move global entries iterator forward.
// We need to put global GOT entries after all local ones.
++m_GlobalGOTIterator;
}
void MipsGOT::reserveGlobalEntry()
{
reserve(1);
}
MipsGOTEntry* MipsGOT::consumeLocal()
{
iterator& it = m_LocalGOTIterator;
++it;
assert(it != m_SectionData->getFragmentList().end() &&
"The number of GOT Entries and ResolveInfo doesn't match");
return llvm::cast<MipsGOTEntry>(&(*it));
}
MipsGOTEntry* MipsGOT::consumeGlobal()
{
iterator& it = m_GlobalGOTIterator;
++it;
assert(it != m_SectionData->getFragmentList().end() &&
"The number of GOT Entries and ResolveInfo doesn't match");
return llvm::cast<MipsGOTEntry>(&(*it));
}
size_t MipsGOT::getTotalNum() const
{
return m_SectionData->getFragmentList().size();
}
size_t MipsGOT::getLocalNum() const
{
return m_pLocalNum;
}