blob: fcf7fb3b0efb4e1562ef318c47452aab6b0870d2 [file] [log] [blame]
//===- HexagonLDBackend.cpp -----------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "Hexagon.h"
#include "HexagonELFDynamic.h"
#include "HexagonLDBackend.h"
#include "HexagonRelocator.h"
#include "HexagonGNUInfo.h"
#include "HexagonAbsoluteStub.h"
#include <llvm/ADT/Triple.h>
#include <llvm/Support/Casting.h>
#include <mcld/LinkerConfig.h>
#include <mcld/IRBuilder.h>
#include <mcld/Fragment/AlignFragment.h>
#include <mcld/Fragment/FillFragment.h>
#include <mcld/Fragment/RegionFragment.h>
#include <mcld/Support/MemoryRegion.h>
#include <mcld/Support/MemoryArea.h>
#include <mcld/Support/MsgHandling.h>
#include <mcld/Support/TargetRegistry.h>
#include <mcld/Object/ObjectBuilder.h>
#include <mcld/Fragment/Stub.h>
#include <mcld/LD/BranchIslandFactory.h>
#include <mcld/LD/StubFactory.h>
#include <mcld/LD/LDContext.h>
#include <cstring>
using namespace mcld;
//===----------------------------------------------------------------------===//
// HexagonLDBackend
//===----------------------------------------------------------------------===//
HexagonLDBackend::HexagonLDBackend(const LinkerConfig& pConfig,
HexagonGNUInfo* pInfo)
: GNULDBackend(pConfig, pInfo),
m_pRelocator(NULL),
m_pGOT(NULL),
m_pGOTPLT(NULL),
m_pPLT(NULL),
m_pRelaDyn(NULL),
m_pRelaPLT(NULL),
m_pDynamic(NULL),
m_pGOTSymbol(NULL),
m_CopyRel(llvm::ELF::R_HEX_COPY) {
}
HexagonLDBackend::~HexagonLDBackend()
{
delete m_pRelocator;
delete m_pGOT;
delete m_pPLT;
delete m_pRelaDyn;
delete m_pRelaPLT;
delete m_pDynamic;
}
bool HexagonLDBackend::initRelocator()
{
if (NULL == m_pRelocator) {
m_pRelocator = new HexagonRelocator(*this, config());
}
return true;
}
Relocator* HexagonLDBackend::getRelocator()
{
assert(NULL != m_pRelocator);
return m_pRelocator;
}
void HexagonLDBackend::doPreLayout(IRBuilder& pBuilder)
{
// initialize .dynamic data
if (!config().isCodeStatic() && NULL == m_pDynamic)
m_pDynamic = new HexagonELFDynamic(*this, config());
// set .got.plt and .got sizes
// when building shared object, the .got section is must
if ((LinkerConfig::Object != config().codeGenType()) &&
(!config().isCodeStatic())) {
setGOTSectionSize(pBuilder);
// set .plt size
if (m_pPLT->hasPLT1())
m_pPLT->finalizeSectionSize();
// set .rela.dyn size
if (!m_pRelaDyn->empty()) {
assert(!config().isCodeStatic() &&
"static linkage should not result in a dynamic relocation section");
setRelaDynSize();
}
// set .rela.plt size
if (!m_pRelaPLT->empty()) {
assert(!config().isCodeStatic() &&
"static linkage should not result in a dynamic relocation section");
setRelaPLTSize();
}
}
// Shared libraries are compiled with -G0 so there is no need to set SData.
if (LinkerConfig::Object == config().codeGenType())
SetSDataSection();
}
void HexagonLDBackend::doPostLayout(Module& pModule, IRBuilder& pBuilder)
{
}
/// dynamic - the dynamic section of the target machine.
/// Use co-variant return type to return its own dynamic section.
HexagonELFDynamic& HexagonLDBackend::dynamic()
{
assert(NULL != m_pDynamic);
return *m_pDynamic;
}
/// dynamic - the dynamic section of the target machine.
/// Use co-variant return type to return its own dynamic section.
const HexagonELFDynamic& HexagonLDBackend::dynamic() const
{
assert(NULL != m_pDynamic);
return *m_pDynamic;
}
uint64_t HexagonLDBackend::emitSectionData(const LDSection& pSection,
MemoryRegion& pRegion) const
{
if (!pRegion.size())
return 0;
const ELFFileFormat* FileFormat = getOutputFormat();
unsigned int EntrySize = 0;
uint64_t RegionSize = 0;
if ((LinkerConfig::Object != config().codeGenType()) &&
(!config().isCodeStatic())) {
if (&pSection == &(FileFormat->getPLT())) {
assert(m_pPLT && "emitSectionData failed, m_pPLT is NULL!");
unsigned char* buffer = pRegion.getBuffer();
m_pPLT->applyPLT0();
m_pPLT->applyPLT1();
HexagonPLT::iterator it = m_pPLT->begin();
unsigned int plt0_size = llvm::cast<PLTEntryBase>((*it)).size();
memcpy(buffer, llvm::cast<PLTEntryBase>((*it)).getValue(), plt0_size);
RegionSize += plt0_size;
++it;
PLTEntryBase* plt1 = 0;
HexagonPLT::iterator ie = m_pPLT->end();
while (it != ie) {
plt1 = &(llvm::cast<PLTEntryBase>(*it));
EntrySize = plt1->size();
memcpy(buffer + RegionSize, plt1->getValue(), EntrySize);
RegionSize += EntrySize;
++it;
}
return RegionSize;
}
else if (&pSection == &(FileFormat->getGOT())) {
RegionSize += emitGOTSectionData(pRegion);
return RegionSize;
}
else if (&pSection == &(FileFormat->getGOTPLT())) {
RegionSize += emitGOTPLTSectionData(pRegion, FileFormat);
return RegionSize;
}
}
const SectionData* sect_data = pSection.getSectionData();
SectionData::const_iterator frag_iter, frag_end = sect_data->end();
uint8_t* out_offset = pRegion.start();
for (frag_iter = sect_data->begin(); frag_iter != frag_end; ++frag_iter) {
size_t size = frag_iter->size();
switch(frag_iter->getKind()) {
case Fragment::Fillment: {
const FillFragment& fill_frag =
llvm::cast<FillFragment>(*frag_iter);
if (0 == fill_frag.getValueSize()) {
// virtual fillment, ignore it.
break;
}
memset(out_offset, fill_frag.getValue(), fill_frag.size());
break;
}
case Fragment::Region: {
const RegionFragment& region_frag =
llvm::cast<RegionFragment>(*frag_iter);
const uint8_t* start = region_frag.getRegion().start();
memcpy(out_offset, start, size);
break;
}
case Fragment::Alignment: {
const AlignFragment& align_frag = llvm::cast<AlignFragment>(*frag_iter);
uint64_t count = size / align_frag.getValueSize();
switch (align_frag.getValueSize()) {
case 1u:
std::memset(out_offset, align_frag.getValue(), count);
break;
default:
llvm::report_fatal_error(
"unsupported value size for align fragment emission yet.\n");
break;
} // end switch
break;
}
case Fragment::Null: {
assert(0x0 == size);
break;
}
default:
llvm::report_fatal_error("unsupported fragment type.\n");
break;
} // end switch
out_offset += size;
} // end for
return pRegion.size();
}
HexagonGOT& HexagonLDBackend::getGOT()
{
assert(NULL != m_pGOT);
return *m_pGOT;
}
const HexagonGOT& HexagonLDBackend::getGOT() const
{
assert(NULL != m_pGOT);
return *m_pGOT;
}
HexagonPLT& HexagonLDBackend::getPLT()
{
assert(NULL != m_pPLT && "PLT section not exist");
return *m_pPLT;
}
const HexagonPLT& HexagonLDBackend::getPLT() const
{
assert(NULL != m_pPLT && "PLT section not exist");
return *m_pPLT;
}
OutputRelocSection& HexagonLDBackend::getRelaDyn()
{
assert(NULL != m_pRelaDyn && ".rela.dyn section not exist");
return *m_pRelaDyn;
}
const OutputRelocSection& HexagonLDBackend::getRelaDyn() const
{
assert(NULL != m_pRelaDyn && ".rela.dyn section not exist");
return *m_pRelaDyn;
}
OutputRelocSection& HexagonLDBackend::getRelaPLT()
{
assert(NULL != m_pRelaPLT && ".rela.plt section not exist");
return *m_pRelaPLT;
}
const OutputRelocSection& HexagonLDBackend::getRelaPLT() const
{
assert(NULL != m_pRelaPLT && ".rela.plt section not exist");
return *m_pRelaPLT;
}
HexagonGOTPLT& HexagonLDBackend::getGOTPLT()
{
assert(NULL != m_pGOTPLT);
return *m_pGOTPLT;
}
const HexagonGOTPLT& HexagonLDBackend::getGOTPLT() const
{
assert(NULL != m_pGOTPLT);
return *m_pGOTPLT;
}
void HexagonLDBackend::setRelaDynSize()
{
ELFFileFormat* file_format = getOutputFormat();
file_format->getRelaDyn().setSize
(m_pRelaDyn->numOfRelocs() * getRelaEntrySize());
}
void HexagonLDBackend::setRelaPLTSize()
{
ELFFileFormat* file_format = getOutputFormat();
file_format->getRelaPlt().setSize
(m_pRelaPLT->numOfRelocs() * getRelaEntrySize());
}
void HexagonLDBackend::setGOTSectionSize(IRBuilder& pBuilder)
{
// set .got.plt size
if (LinkerConfig::DynObj == config().codeGenType() ||
m_pGOTPLT->hasGOT1() ||
NULL != m_pGOTSymbol) {
m_pGOTPLT->finalizeSectionSize();
defineGOTSymbol(pBuilder, *(m_pGOTPLT->begin()));
}
// set .got size
if (!m_pGOT->empty())
m_pGOT->finalizeSectionSize();
}
uint64_t HexagonLDBackend::emitGOTSectionData(MemoryRegion& pRegion) const
{
assert(m_pGOT && "emitGOTSectionData failed, m_pGOT is NULL!");
uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());
HexagonGOTEntry* got = 0;
unsigned int EntrySize = HexagonGOTEntry::EntrySize;
uint64_t RegionSize = 0;
for (HexagonGOT::iterator it = m_pGOT->begin(),
ie = m_pGOT->end(); it != ie; ++it, ++buffer) {
got = &(llvm::cast<HexagonGOTEntry>((*it)));
*buffer = static_cast<uint32_t>(got->getValue());
RegionSize += EntrySize;
}
return RegionSize;
}
void HexagonLDBackend::defineGOTSymbol(IRBuilder& pBuilder,
Fragment& pFrag)
{
// define symbol _GLOBAL_OFFSET_TABLE_
if (m_pGOTSymbol != NULL) {
pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>(
"_GLOBAL_OFFSET_TABLE_",
ResolveInfo::Object,
ResolveInfo::Define,
ResolveInfo::Local,
0x0, // size
0x0, // value
FragmentRef::Create(pFrag, 0x0),
ResolveInfo::Hidden);
}
else {
m_pGOTSymbol = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
"_GLOBAL_OFFSET_TABLE_",
ResolveInfo::Object,
ResolveInfo::Define,
ResolveInfo::Local,
0x0, // size
0x0, // value
FragmentRef::Create(pFrag, 0x0),
ResolveInfo::Hidden);
}
}
uint64_t HexagonLDBackend::emitGOTPLTSectionData(MemoryRegion& pRegion,
const ELFFileFormat* FileFormat) const
{
assert(m_pGOTPLT && "emitGOTPLTSectionData failed, m_pGOTPLT is NULL!");
m_pGOTPLT->applyGOT0(FileFormat->getDynamic().addr());
m_pGOTPLT->applyAllGOTPLT(*m_pPLT);
uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer());
HexagonGOTEntry* got = 0;
unsigned int EntrySize = HexagonGOTEntry::EntrySize;
uint64_t RegionSize = 0;
for (HexagonGOTPLT::iterator it = m_pGOTPLT->begin(),
ie = m_pGOTPLT->end(); it != ie; ++it, ++buffer) {
got = &(llvm::cast<HexagonGOTEntry>((*it)));
*buffer = static_cast<uint32_t>(got->getValue());
RegionSize += EntrySize;
}
return RegionSize;
}
unsigned int
HexagonLDBackend::getTargetSectionOrder(const LDSection& pSectHdr) const
{
const ELFFileFormat* file_format = getOutputFormat();
if (LinkerConfig::Object != config().codeGenType()) {
if (&pSectHdr == &file_format->getGOT()) {
if (config().options().hasNow())
return SHO_RELRO;
return SHO_RELRO_LAST;
}
if (&pSectHdr == &file_format->getGOTPLT()) {
if (config().options().hasNow())
return SHO_RELRO;
return SHO_NON_RELRO_FIRST;
}
if (&pSectHdr == &file_format->getPLT())
return SHO_PLT;
}
if (&pSectHdr == m_pstart)
return SHO_INIT;
if (&pSectHdr == m_psdata)
return SHO_SMALL_DATA;
return SHO_UNDEFINED;
}
void HexagonLDBackend::initTargetSections(Module& pModule,
ObjectBuilder& pBuilder)
{
if ((LinkerConfig::Object != config().codeGenType()) &&
(!config().isCodeStatic())) {
ELFFileFormat* file_format = getOutputFormat();
// initialize .got
LDSection& got = file_format->getGOT();
m_pGOT = new HexagonGOT(got);
// initialize .got.plt
LDSection& gotplt = file_format->getGOTPLT();
m_pGOTPLT = new HexagonGOTPLT(gotplt);
// initialize .plt
LDSection& plt = file_format->getPLT();
m_pPLT = new HexagonPLT(plt,
*m_pGOTPLT,
config());
// initialize .rela.plt
LDSection& relaplt = file_format->getRelaPlt();
relaplt.setLink(&plt);
m_pRelaPLT = new OutputRelocSection(pModule, relaplt);
// initialize .rela.dyn
LDSection& reladyn = file_format->getRelaDyn();
m_pRelaDyn = new OutputRelocSection(pModule, reladyn);
}
m_psdata = pBuilder.CreateSection(".sdata",
LDFileFormat::Target,
llvm::ELF::SHT_PROGBITS,
llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
4*1024);
m_pscommon_1 = pBuilder.CreateSection(".scommon.1",
LDFileFormat::Target,
llvm::ELF::SHT_PROGBITS,
llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
1);
IRBuilder::CreateSectionData(*m_pscommon_1);
m_pscommon_2 = pBuilder.CreateSection(".scommon.2",
LDFileFormat::Target,
llvm::ELF::SHT_PROGBITS,
llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
2);
IRBuilder::CreateSectionData(*m_pscommon_2);
m_pscommon_4 = pBuilder.CreateSection(".scommon.4",
LDFileFormat::Target,
llvm::ELF::SHT_PROGBITS,
llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
4);
IRBuilder::CreateSectionData(*m_pscommon_4);
m_pscommon_8 = pBuilder.CreateSection(".scommon.8",
LDFileFormat::Target,
llvm::ELF::SHT_PROGBITS,
llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
8);
IRBuilder::CreateSectionData(*m_pscommon_8);
m_pstart = pBuilder.CreateSection(".start",
LDFileFormat::Target,
llvm::ELF::SHT_PROGBITS,
llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
8);
IRBuilder::CreateSectionData(*m_pstart);
}
void HexagonLDBackend::initTargetSymbols(IRBuilder& pBuilder, Module& pModule)
{
if (config().codeGenType() == LinkerConfig::Object)
return;
// Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the
// same name in input
m_pGOTSymbol = pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
"_GLOBAL_OFFSET_TABLE_",
ResolveInfo::Object,
ResolveInfo::Define,
ResolveInfo::Local,
0x0, // size
0x0, // value
FragmentRef::Null(),
ResolveInfo::Hidden);
m_psdabase =
pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
"_SDA_BASE_",
ResolveInfo::Object,
ResolveInfo::Define,
ResolveInfo::Absolute,
0x0, // size
0x0, // value
FragmentRef::Null(),
ResolveInfo::Hidden);
pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
"__sbss_start",
ResolveInfo::Object,
ResolveInfo::Define,
ResolveInfo::Absolute,
0x0, // size
0x0, // value
FragmentRef::Null(),
ResolveInfo::Hidden);
pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
"__sbss_end",
ResolveInfo::Object,
ResolveInfo::Define,
ResolveInfo::Absolute,
0x0, // size
0x0, // value
FragmentRef::Null(),
ResolveInfo::Hidden);
}
bool HexagonLDBackend::initTargetStubs()
{
if (NULL != getStubFactory()) {
getStubFactory()->addPrototype
(new HexagonAbsoluteStub(config().isCodeIndep()));
return true;
}
return false;
}
bool HexagonLDBackend::initBRIslandFactory()
{
if (NULL == m_pBRIslandFactory) {
m_pBRIslandFactory = new BranchIslandFactory(maxBranchOffset(), 0);
}
return true;
}
bool HexagonLDBackend::initStubFactory()
{
if (NULL == m_pStubFactory) {
m_pStubFactory = new StubFactory();
}
return true;
}
bool HexagonLDBackend::doRelax(Module& pModule, IRBuilder& pBuilder,
bool& pFinished)
{
assert(NULL != getStubFactory() && NULL != getBRIslandFactory());
bool isRelaxed = false;
ELFFileFormat* file_format = getOutputFormat();
// check branch relocs and create the related stubs if needed
Module::obj_iterator input, inEnd = pModule.obj_end();
for (input = pModule.obj_begin(); input != inEnd; ++input) {
LDContext::sect_iterator rs, rsEnd = (*input)->context()->relocSectEnd();
for (rs = (*input)->context()->relocSectBegin(); rs != rsEnd; ++rs) {
if (LDFileFormat::Ignore == (*rs)->kind() || !(*rs)->hasRelocData())
continue;
RelocData::iterator reloc, rEnd = (*rs)->getRelocData()->end();
for (reloc = (*rs)->getRelocData()->begin(); reloc != rEnd; ++reloc) {
switch (reloc->type()) {
case llvm::ELF::R_HEX_B22_PCREL:
case llvm::ELF::R_HEX_B15_PCREL:
case llvm::ELF::R_HEX_B7_PCREL:
case llvm::ELF::R_HEX_B13_PCREL:
case llvm::ELF::R_HEX_B9_PCREL: {
Relocation* relocation = llvm::cast<Relocation>(reloc);
uint64_t sym_value = 0x0;
LDSymbol* symbol = relocation->symInfo()->outSymbol();
if (symbol->hasFragRef()) {
uint64_t value = symbol->fragRef()->getOutputOffset();
uint64_t addr =
symbol->fragRef()->frag()->getParent()->getSection().addr();
sym_value = addr + value;
}
Stub* stub = getStubFactory()->create(*relocation, // relocation
sym_value, //symbol value
pBuilder,
*getBRIslandFactory());
if (NULL != stub) {
assert(NULL != stub->symInfo());
// increase the size of .symtab and .strtab
LDSection& symtab = file_format->getSymTab();
LDSection& strtab = file_format->getStrTab();
symtab.setSize(symtab.size() + sizeof(llvm::ELF::Elf32_Sym));
strtab.setSize(strtab.size() + stub->symInfo()->nameSize() + 1);
isRelaxed = true;
}
}
break;
default:
break;
}
}
}
}
// find the first fragment w/ invalid offset due to stub insertion
Fragment* invalid = NULL;
pFinished = true;
for (BranchIslandFactory::iterator island = getBRIslandFactory()->begin(),
island_end = getBRIslandFactory()->end(); island != island_end; ++island)
{
if ((*island).end() == file_format->getText().getSectionData()->end())
break;
Fragment* exit = (*island).end();
if (((*island).offset() + (*island).size()) > exit->getOffset()) {
invalid = exit;
pFinished = false;
break;
}
}
// reset the offset of invalid fragments
while (NULL != invalid) {
invalid->setOffset(invalid->getPrevNode()->getOffset() +
invalid->getPrevNode()->size());
invalid = invalid->getNextNode();
}
// reset the size of .text
if (isRelaxed) {
file_format->getText().setSize(
file_format->getText().getSectionData()->back().getOffset() +
file_format->getText().getSectionData()->back().size());
}
return isRelaxed;
}
/// finalizeSymbol - finalize the symbol value
bool HexagonLDBackend::finalizeTargetSymbols()
{
if (config().codeGenType() == LinkerConfig::Object)
return true;
if (m_psdabase)
m_psdabase->setValue(m_psdata->addr());
ELFSegment *edata = m_ELFSegmentTable.find(llvm::ELF::PT_LOAD,
llvm::ELF::PF_W, llvm::ELF::PF_X);
if (NULL != edata) {
if (NULL != f_pEData && ResolveInfo::ThreadLocal != f_pEData->type()) {
f_pEData->setValue(edata->vaddr() + edata->filesz());
}
if (NULL != f_p_EData && ResolveInfo::ThreadLocal != f_p_EData->type()) {
f_p_EData->setValue(edata->vaddr() + edata->filesz());
}
if (NULL != f_pBSSStart &&
ResolveInfo::ThreadLocal != f_pBSSStart->type()) {
f_pBSSStart->setValue(edata->vaddr() + edata->filesz());
}
if (NULL != f_pEnd && ResolveInfo::ThreadLocal != f_pEnd->type()) {
f_pEnd->setValue(((edata->vaddr() +
edata->memsz()) + 7) & ~7);
}
if (NULL != f_p_End && ResolveInfo::ThreadLocal != f_p_End->type()) {
f_p_End->setValue(((edata->vaddr() +
edata->memsz()) + 7) & ~7);
}
}
return true;
}
/// merge Input Sections
bool HexagonLDBackend::mergeSection(Module& pModule, LDSection& pInputSection)
{
if ((pInputSection.flag() & llvm::ELF::SHF_HEX_GPREL) ||
(pInputSection.kind() == LDFileFormat::LinkOnce) ||
(pInputSection.kind() == LDFileFormat::Target)) {
SectionData *sd = NULL;
if (!m_psdata->hasSectionData()) {
sd = IRBuilder::CreateSectionData(*m_psdata);
m_psdata->setSectionData(sd);
}
sd = m_psdata->getSectionData();
MoveSectionDataAndSort(*pInputSection.getSectionData(), *sd);
}
else {
ObjectBuilder builder(config(), pModule);
return builder.MergeSection(pInputSection);
}
return true;
}
bool HexagonLDBackend::SetSDataSection() {
SectionData *pTo = (m_psdata->getSectionData());
if (pTo) {
MoveCommonData(*m_pscommon_1->getSectionData(), *pTo);
MoveCommonData(*m_pscommon_2->getSectionData(), *pTo);
MoveCommonData(*m_pscommon_4->getSectionData(), *pTo);
MoveCommonData(*m_pscommon_8->getSectionData(), *pTo);
SectionData::FragmentListType& to_list = pTo->getFragmentList();
SectionData::FragmentListType::iterator fragTo, fragToEnd = to_list.end();
uint32_t offset = 0;
for (fragTo = to_list.begin(); fragTo != fragToEnd; ++fragTo) {
fragTo->setOffset(offset);
offset += fragTo->size();
}
// set up pTo's header
pTo->getSection().setSize(offset);
SectionData::FragmentListType& newlist = pTo->getFragmentList();
for (fragTo = newlist.begin(), fragToEnd = newlist.end();
fragTo != fragToEnd; ++fragTo) {
fragTo->setParent(pTo);
}
}
return true;
}
/// allocateCommonSymbols - allocate common symbols in the corresponding
/// sections. This is called at pre-layout stage.
/// @refer Google gold linker: common.cc: 214
bool HexagonLDBackend::allocateCommonSymbols(Module& pModule)
{
SymbolCategory& symbol_list = pModule.getSymbolTable();
if (symbol_list.emptyCommons() && symbol_list.emptyLocals()) {
SetSDataSection();
return true;
}
int8_t maxGPSize = config().options().getGPSize();
SymbolCategory::iterator com_sym, com_end;
// get corresponding BSS LDSection
ELFFileFormat* file_format = getOutputFormat();
LDSection& bss_sect = file_format->getBSS();
LDSection& tbss_sect = file_format->getTBSS();
// get or create corresponding BSS SectionData
SectionData* bss_sect_data = NULL;
if (bss_sect.hasSectionData())
bss_sect_data = bss_sect.getSectionData();
else
bss_sect_data = IRBuilder::CreateSectionData(bss_sect);
SectionData* tbss_sect_data = NULL;
if (tbss_sect.hasSectionData())
tbss_sect_data = tbss_sect.getSectionData();
else
tbss_sect_data = IRBuilder::CreateSectionData(tbss_sect);
// remember original BSS size
uint64_t bss_offset = bss_sect.size();
uint64_t tbss_offset = tbss_sect.size();
// allocate all local common symbols
com_end = symbol_list.localEnd();
for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) {
if (ResolveInfo::Common == (*com_sym)->desc()) {
// We have to reset the description of the symbol here. When doing
// incremental linking, the output relocatable object may have common
// symbols. Therefore, we can not treat common symbols as normal symbols
// when emitting the regular name pools. We must change the symbols'
// description here.
(*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
Fragment* frag = new FillFragment(0x0, 1, (*com_sym)->size());
(*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
switch((*com_sym)->size()) {
case 1:
if (maxGPSize <= 0)
break;
ObjectBuilder::AppendFragment(*frag,
*(m_pscommon_1->getSectionData()),
(*com_sym)->value());
continue;
case 2:
if (maxGPSize <= 1)
break;
ObjectBuilder::AppendFragment(*frag,
*(m_pscommon_2->getSectionData()),
(*com_sym)->value());
continue;
case 4:
if (maxGPSize <= 3)
break;
ObjectBuilder::AppendFragment(*frag,
*(m_pscommon_4->getSectionData()),
(*com_sym)->value());
continue;
case 8:
if (maxGPSize <= 7)
break;
ObjectBuilder::AppendFragment(*frag,
*(m_pscommon_8->getSectionData()),
(*com_sym)->value());
continue;
default:
break;
}
if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
// allocate TLS common symbol in tbss section
tbss_offset += ObjectBuilder::AppendFragment(*frag,
*tbss_sect_data,
(*com_sym)->value());
}
// FIXME: how to identify small and large common symbols?
else {
bss_offset += ObjectBuilder::AppendFragment(*frag,
*bss_sect_data,
(*com_sym)->value());
}
}
}
// allocate all global common symbols
com_end = symbol_list.commonEnd();
for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
// We have to reset the description of the symbol here. When doing
// incremental linking, the output relocatable object may have common
// symbols. Therefore, we can not treat common symbols as normal symbols
// when emitting the regular name pools. We must change the symbols'
// description here.
(*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
Fragment* frag = new FillFragment(0x0, 1, (*com_sym)->size());
(*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
switch((*com_sym)->size()) {
case 1:
if (maxGPSize <= 0)
break;
ObjectBuilder::AppendFragment(*frag,
*(m_pscommon_1->getSectionData()),
(*com_sym)->value());
continue;
case 2:
if (maxGPSize <= 1)
break;
ObjectBuilder::AppendFragment(*frag,
*(m_pscommon_2->getSectionData()),
(*com_sym)->value());
continue;
case 4:
if (maxGPSize <= 3)
break;
ObjectBuilder::AppendFragment(*frag,
*(m_pscommon_4->getSectionData()),
(*com_sym)->value());
continue;
case 8:
if (maxGPSize <= 7)
break;
ObjectBuilder::AppendFragment(*frag,
*(m_pscommon_8->getSectionData()),
(*com_sym)->value());
continue;
default:
break;
}
if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
// allocate TLS common symbol in tbss section
tbss_offset += ObjectBuilder::AppendFragment(*frag,
*tbss_sect_data,
(*com_sym)->value());
}
// FIXME: how to identify small and large common symbols?
else {
bss_offset += ObjectBuilder::AppendFragment(*frag,
*bss_sect_data,
(*com_sym)->value());
}
}
bss_sect.setSize(bss_offset);
tbss_sect.setSize(tbss_offset);
symbol_list.changeCommonsToGlobal();
SetSDataSection();
return true;
}
bool HexagonLDBackend::MoveCommonData(SectionData &pFrom, SectionData &pTo)
{
SectionData::FragmentListType& to_list = pTo.getFragmentList();
SectionData::FragmentListType::iterator frag, fragEnd = to_list.end();
uint32_t pFromFlag = pFrom.getSection().align();
bool found = false;
SectionData::FragmentListType::iterator fragInsert;
for (frag = to_list.begin(); frag != fragEnd; ++frag) {
if (frag->getKind() == mcld::Fragment::Alignment) {
fragInsert = frag;
continue;
}
if ((frag->getKind() != mcld::Fragment::Region) &&
(frag->getKind() != mcld::Fragment::Fillment)) {
continue;
}
uint32_t flag = frag->getParent()->getSection().align();
if (pFromFlag < flag) {
found = true;
break;
}
}
AlignFragment* align = NULL;
if (pFrom.getSection().align() > 1) {
// if the align constraint is larger than 1, append an alignment
align = new AlignFragment(pFrom.getSection().align(), // alignment
0x0, // the filled value
1u, // the size of filled value
pFrom.getSection().align() - 1 // max bytes to emit
);
pFrom.getFragmentList().push_front(align);
}
if (found)
to_list.splice(fragInsert, pFrom.getFragmentList());
else
to_list.splice(frag, pFrom.getFragmentList());
return true;
}
bool HexagonLDBackend::readSection(Input& pInput, SectionData& pSD)
{
Fragment* frag = NULL;
uint32_t offset = pInput.fileOffset() + pSD.getSection().offset();
uint32_t size = pSD.getSection().size();
if (pSD.getSection().type() == llvm::ELF::SHT_NOBITS) {
frag = new FillFragment(0x0, 1, size);
}
else {
MemoryRegion* region = pInput.memArea()->request(offset, size);
if (NULL == region) {
// If the input section's size is zero, we got a NULL region.
// use a virtual fill fragment
frag = new FillFragment(0x0, 0, 0);
}
else {
frag = new RegionFragment(*region);
}
}
ObjectBuilder::AppendFragment(*frag, pSD);
return true;
}
/// MoveSectionData - move the fragments of pTO section data to pTo
bool HexagonLDBackend::MoveSectionDataAndSort(SectionData& pFrom, SectionData& pTo)
{
assert(&pFrom != &pTo && "Cannot move section data to itself!");
SectionData::FragmentListType& to_list = pTo.getFragmentList();
SectionData::FragmentListType::iterator frag, fragEnd = to_list.end();
uint32_t pFromFlag = pFrom.getSection().align();
bool found = false;
SectionData::FragmentListType::iterator fragInsert;
for (frag = to_list.begin(); frag != fragEnd; ++frag) {
if (frag->getKind() == mcld::Fragment::Alignment) {
fragInsert = frag;
continue;
}
if ((frag->getKind() != mcld::Fragment::Region) &&
(frag->getKind() != mcld::Fragment::Fillment)) {
continue;
}
uint32_t flag = frag->getParent()->getSection().align();
if (pFromFlag < flag) {
found = true;
break;
}
}
AlignFragment* align = NULL;
if (pFrom.getSection().align() > 1) {
// if the align constraint is larger than 1, append an alignment
align = new AlignFragment(pFrom.getSection().align(), // alignment
0x0, // the filled value
1u, // the size of filled value
pFrom.getSection().align() - 1 // max bytes to emit
);
pFrom.getFragmentList().push_front(align);
}
if (found)
to_list.splice(fragInsert, pFrom.getFragmentList());
else
to_list.splice(frag, pFrom.getFragmentList());
uint32_t offset = 0;
for (frag = to_list.begin(); frag != fragEnd; ++frag) {
frag->setOffset(offset);
offset += frag->size();
}
// set up pTo's header
pTo.getSection().setSize(offset);
if (pFrom.getSection().align() > pTo.getSection().align())
pTo.getSection().setAlign(pFrom.getSection().align());
if (pFrom.getSection().flag() > pTo.getSection().flag())
pTo.getSection().setFlag(pFrom.getSection().flag());
return true;
}
/// doCreateProgramHdrs - backend can implement this function to create the
/// target-dependent segments
void HexagonLDBackend::doCreateProgramHdrs(Module& pModule)
{
// TODO
}
namespace mcld {
//===----------------------------------------------------------------------===//
/// createHexagonLDBackend - the help funtion to create corresponding
/// HexagonLDBackend
TargetLDBackend* createHexagonLDBackend(const llvm::Target& pTarget,
const LinkerConfig& pConfig)
{
if (pConfig.targets().triple().isOSDarwin()) {
assert(0 && "MachO linker is not supported yet");
/**
return new HexagonMachOLDBackend(createHexagonMachOArchiveReader,
createHexagonMachOObjectReader,
createHexagonMachOObjectWriter);
**/
}
if (pConfig.targets().triple().isOSWindows()) {
assert(0 && "COFF linker is not supported yet");
/**
return new HexagonCOFFLDBackend(createHexagonCOFFArchiveReader,
createHexagonCOFFObjectReader,
createHexagonCOFFObjectWriter);
**/
}
return new HexagonLDBackend(pConfig, new HexagonGNUInfo(pConfig.targets()));
}
} // namespace of mcld
//===----------------------------------------------------------------------===//
// Force static initialization.
//===----------------------------------------------------------------------===//
extern "C" void MCLDInitializeHexagonLDBackend() {
// Register the linker backend
mcld::TargetRegistry::RegisterTargetLDBackend(TheHexagonTarget,
createHexagonLDBackend);
}