//===- 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 MipsGOTEntrySize = 4;
const size_t MipsGOT0Num = 1;
}
using namespace mcld;
//===----------------------------------------------------------------------===//
// MipsGOT
MipsGOT::MipsGOT(LDSection& pSection, SectionData& pSectionData)
: GOT(pSection, pSectionData, MipsGOTEntrySize),
m_pLocalNum(0)
{
// Create GOT0 entries.
for (size_t i = 0; i < MipsGOT0Num; ++i) {
GOTEntry* entry =
new (std::nothrow) GOTEntry(0, MipsGOTEntrySize, &m_SectionData);
if (NULL == entry)
fatal(diag::fail_allocate_memory_got);
m_Section.setSize(m_Section.size() + MipsGOTEntrySize);
}
// 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;
}
MipsGOT::iterator MipsGOT::begin()
{
return m_SectionData.getFragmentList().begin();
}
MipsGOT::iterator MipsGOT::end()
{
return m_SectionData.getFragmentList().end();
}
MipsGOT::const_iterator MipsGOT::begin() const
{
return m_SectionData.getFragmentList().begin();
}
MipsGOT::const_iterator MipsGOT::end() const
{
return m_SectionData.getFragmentList().end();
}
uint64_t MipsGOT::emit(MemoryRegion& pRegion)
{
uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());
size_t entry_size = getEntrySize();
uint64_t result = 0;
for (iterator it = begin(), ie = end();
it != ie; ++it, ++buffer) {
GOTEntry* got = &(llvm::cast<GOTEntry>((*it)));
*buffer = static_cast<uint32_t>(got->getContent());
result += entry_size;
}
return result;
}
void MipsGOT::reserveEntry(size_t pNum)
{
for (size_t i = 0; i < pNum; ++i) {
GOTEntry* entry =
new (std::nothrow) GOTEntry(0, MipsGOTEntrySize, &m_SectionData);
if (NULL == entry)
fatal(diag::fail_allocate_memory_got);
m_Section.setSize(m_Section.size() + MipsGOTEntrySize);
}
}
void MipsGOT::reserveLocalEntry()
{
reserveEntry(1);
++m_pLocalNum;
// Move global entries iterator forward.
// We need to put global GOT entries after all local ones.
++m_GlobalGOTIterator;
}
void MipsGOT::reserveGlobalEntry()
{
reserveEntry(1);
}
GOTEntry* MipsGOT::getEntry(const ResolveInfo& pInfo, bool& pExist)
{
if (isLocal(&pInfo) && pInfo.type() == ResolveInfo::Section) {
pExist = false;
iterator& it = m_LocalGOTIterator;
++it;
assert(it != m_SectionData.getFragmentList().end() &&
"The number of GOT Entries and ResolveInfo doesn't match");
GOTEntry* entry = llvm::cast<GOTEntry>(&(*it));
return entry;
}
GOTEntry*& entry = m_GeneralGOTMap[&pInfo];
pExist = NULL != entry;
if (!pExist) {
iterator& it = isLocal(&pInfo) ? m_LocalGOTIterator : m_GlobalGOTIterator;
++it;
assert(it != m_SectionData.getFragmentList().end() &&
"The number of GOT Entries and ResolveInfo doesn't match");
entry = llvm::cast<GOTEntry>(&(*it));
}
return entry;
}
size_t MipsGOT::getTotalNum() const
{
return m_SectionData.getFragmentList().size();
}
size_t MipsGOT::getLocalNum() const
{
return m_pLocalNum;
}