You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1066 lines
35 KiB
1066 lines
35 KiB
//===- 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 "mcld/IRBuilder.h"
|
|
#include "mcld/LinkerConfig.h"
|
|
#include "mcld/Fragment/AlignFragment.h"
|
|
#include "mcld/Fragment/FillFragment.h"
|
|
#include "mcld/Fragment/RegionFragment.h"
|
|
#include "mcld/Fragment/Stub.h"
|
|
#include "mcld/LD/BranchIslandFactory.h"
|
|
#include "mcld/LD/ELFFileFormat.h"
|
|
#include "mcld/LD/ELFSegmentFactory.h"
|
|
#include "mcld/LD/ELFSegment.h"
|
|
#include "mcld/LD/LDContext.h"
|
|
#include "mcld/LD/StubFactory.h"
|
|
#include "mcld/Object/ObjectBuilder.h"
|
|
#include "mcld/Support/MemoryArea.h"
|
|
#include "mcld/Support/MsgHandling.h"
|
|
#include "mcld/Support/TargetRegistry.h"
|
|
|
|
#include <llvm/ADT/Triple.h>
|
|
#include <llvm/Support/Casting.h>
|
|
|
|
#include <cstring>
|
|
#include <vector>
|
|
|
|
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 (m_pRelocator == NULL) {
|
|
m_pRelocator = new HexagonRelocator(*this, config());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
const Relocator* HexagonLDBackend::getRelocator() const {
|
|
assert(m_pRelocator != NULL);
|
|
return m_pRelocator;
|
|
}
|
|
|
|
Relocator* HexagonLDBackend::getRelocator() {
|
|
assert(m_pRelocator != NULL);
|
|
return m_pRelocator;
|
|
}
|
|
|
|
void HexagonLDBackend::doPreLayout(IRBuilder& pBuilder) {
|
|
// initialize .dynamic data
|
|
if (!config().isCodeStatic() && m_pDynamic == NULL)
|
|
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(m_pDynamic != NULL);
|
|
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(m_pDynamic != NULL);
|
|
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 (FileFormat->hasPLT() && (&pSection == &(FileFormat->getPLT()))) {
|
|
unsigned char* buffer = pRegion.begin();
|
|
|
|
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 (FileFormat->hasGOT() && (&pSection == &(FileFormat->getGOT()))) {
|
|
RegionSize += emitGOTSectionData(pRegion);
|
|
return RegionSize;
|
|
} else if (FileFormat->hasGOTPLT() &&
|
|
(&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.begin();
|
|
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 (fill_frag.getValueSize() == 0) {
|
|
// 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 char* start = region_frag.getRegion().begin();
|
|
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(m_pGOT != NULL);
|
|
return *m_pGOT;
|
|
}
|
|
|
|
const HexagonGOT& HexagonLDBackend::getGOT() const {
|
|
assert(m_pGOT != NULL);
|
|
return *m_pGOT;
|
|
}
|
|
|
|
HexagonPLT& HexagonLDBackend::getPLT() {
|
|
assert(m_pPLT != NULL && "PLT section not exist");
|
|
return *m_pPLT;
|
|
}
|
|
|
|
const HexagonPLT& HexagonLDBackend::getPLT() const {
|
|
assert(m_pPLT != NULL && "PLT section not exist");
|
|
return *m_pPLT;
|
|
}
|
|
|
|
OutputRelocSection& HexagonLDBackend::getRelaDyn() {
|
|
assert(m_pRelaDyn != NULL && ".rela.dyn section not exist");
|
|
return *m_pRelaDyn;
|
|
}
|
|
|
|
const OutputRelocSection& HexagonLDBackend::getRelaDyn() const {
|
|
assert(m_pRelaDyn != NULL && ".rela.dyn section not exist");
|
|
return *m_pRelaDyn;
|
|
}
|
|
|
|
OutputRelocSection& HexagonLDBackend::getRelaPLT() {
|
|
assert(m_pRelaPLT != NULL && ".rela.plt section not exist");
|
|
return *m_pRelaPLT;
|
|
}
|
|
|
|
const OutputRelocSection& HexagonLDBackend::getRelaPLT() const {
|
|
assert(m_pRelaPLT != NULL && ".rela.plt section not exist");
|
|
return *m_pRelaPLT;
|
|
}
|
|
|
|
HexagonGOTPLT& HexagonLDBackend::getGOTPLT() {
|
|
assert(m_pGOTPLT != NULL);
|
|
return *m_pGOTPLT;
|
|
}
|
|
|
|
const HexagonGOTPLT& HexagonLDBackend::getGOTPLT() const {
|
|
assert(m_pGOTPLT != NULL);
|
|
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() ||
|
|
m_pGOTSymbol != NULL) {
|
|
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.begin());
|
|
|
|
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 != NULL &&
|
|
"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.begin());
|
|
|
|
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 (file_format->hasGOT() && (&pSectHdr == &file_format->getGOT())) {
|
|
if (config().options().hasNow())
|
|
return SHO_RELRO;
|
|
return SHO_RELRO_LAST;
|
|
}
|
|
|
|
if (file_format->hasGOTPLT() && (&pSectHdr == &file_format->getGOTPLT())) {
|
|
if (config().options().hasNow())
|
|
return SHO_RELRO;
|
|
return SHO_NON_RELRO_FIRST;
|
|
}
|
|
|
|
if (file_format->hasPLT() && (&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 (getStubFactory() != NULL) {
|
|
getStubFactory()->addPrototype(
|
|
new HexagonAbsoluteStub(config().isCodeIndep()));
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool HexagonLDBackend::initBRIslandFactory() {
|
|
if (m_pBRIslandFactory == NULL) {
|
|
m_pBRIslandFactory =
|
|
new BranchIslandFactory(maxFwdBranchOffset(), maxBwdBranchOffset(), 0);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool HexagonLDBackend::initStubFactory() {
|
|
if (m_pStubFactory == NULL) {
|
|
m_pStubFactory = new StubFactory();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool HexagonLDBackend::doRelax(Module& pModule,
|
|
IRBuilder& pBuilder,
|
|
bool& pFinished) {
|
|
assert(getStubFactory() != NULL && getBRIslandFactory() != NULL);
|
|
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 (stub != NULL) {
|
|
assert(stub->symInfo() != NULL);
|
|
// reset the branch target of the reloc to this stub instead
|
|
relocation->setSymInfo(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
|
|
std::vector<Fragment*> invalid_frags;
|
|
pFinished = true;
|
|
for (BranchIslandFactory::iterator island = getBRIslandFactory()->begin(),
|
|
island_end = getBRIslandFactory()->end();
|
|
island != island_end;
|
|
++island) {
|
|
if ((*island).size() > stubGroupSize()) {
|
|
error(diag::err_no_space_to_place_stubs) << stubGroupSize();
|
|
return false;
|
|
}
|
|
|
|
if ((*island).numOfStubs() == 0) {
|
|
continue;
|
|
}
|
|
|
|
Fragment* exit = &*(*island).end();
|
|
if (exit == (*island).begin()->getParent()->end()) {
|
|
continue;
|
|
}
|
|
|
|
if (((*island).offset() + (*island).size()) > exit->getOffset()) {
|
|
if (invalid_frags.empty() ||
|
|
(invalid_frags.back()->getParent() != (*island).getParent())) {
|
|
invalid_frags.push_back(exit);
|
|
pFinished = false;
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// reset the offset of invalid fragments
|
|
for (auto it = invalid_frags.begin(), ie = invalid_frags.end(); it != ie;
|
|
++it) {
|
|
Fragment* invalid = *it;
|
|
while (invalid != NULL) {
|
|
invalid->setOffset(invalid->getPrevNode()->getOffset() +
|
|
invalid->getPrevNode()->size());
|
|
invalid = invalid->getNextNode();
|
|
}
|
|
}
|
|
|
|
// reset the size of section that has stubs inserted.
|
|
if (isRelaxed) {
|
|
SectionData* prev = NULL;
|
|
for (BranchIslandFactory::iterator island = getBRIslandFactory()->begin(),
|
|
island_end = getBRIslandFactory()->end();
|
|
island != island_end;
|
|
++island) {
|
|
SectionData* sd = (*island).begin()->getParent();
|
|
if ((*island).numOfStubs() != 0) {
|
|
if (sd != prev) {
|
|
sd->getSection().setSize(sd->back().getOffset() + sd->back().size());
|
|
}
|
|
}
|
|
prev = sd;
|
|
}
|
|
}
|
|
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());
|
|
|
|
ELFSegmentFactory::const_iterator edata = elfSegmentTable().find(
|
|
llvm::ELF::PT_LOAD, llvm::ELF::PF_W, llvm::ELF::PF_X);
|
|
if (elfSegmentTable().end() != edata) {
|
|
if (f_pEData != NULL && ResolveInfo::ThreadLocal != f_pEData->type()) {
|
|
f_pEData->setValue((*edata)->vaddr() + (*edata)->filesz());
|
|
}
|
|
if (f_p_EData != NULL && ResolveInfo::ThreadLocal != f_p_EData->type()) {
|
|
f_p_EData->setValue((*edata)->vaddr() + (*edata)->filesz());
|
|
}
|
|
if (f_pBSSStart != NULL &&
|
|
ResolveInfo::ThreadLocal != f_pBSSStart->type()) {
|
|
f_pBSSStart->setValue((*edata)->vaddr() + (*edata)->filesz());
|
|
}
|
|
if (f_pEnd != NULL && ResolveInfo::ThreadLocal != f_pEnd->type()) {
|
|
f_pEnd->setValue((((*edata)->vaddr() + (*edata)->memsz()) + 7) & ~7);
|
|
}
|
|
if (f_p_End != NULL && 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,
|
|
const Input& pInputFile,
|
|
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(pModule);
|
|
builder.MergeSection(pInputFile, 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.
|
|
bool HexagonLDBackend::allocateCommonSymbols(Module& pModule) {
|
|
SymbolCategory& symbol_list = pModule.getSymbolTable();
|
|
|
|
if (symbol_list.emptyCommons() && symbol_list.emptyLocals()) {
|
|
SetSDataSection();
|
|
return true;
|
|
}
|
|
|
|
int8_t maxGPSize = config().targets().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());
|
|
|
|
switch ((*com_sym)->size()) {
|
|
case 1:
|
|
if (maxGPSize <= 0)
|
|
break;
|
|
ObjectBuilder::AppendFragment(
|
|
*frag, *(m_pscommon_1->getSectionData()), (*com_sym)->value());
|
|
(*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
|
|
continue;
|
|
case 2:
|
|
if (maxGPSize <= 1)
|
|
break;
|
|
ObjectBuilder::AppendFragment(
|
|
*frag, *(m_pscommon_2->getSectionData()), (*com_sym)->value());
|
|
(*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
|
|
continue;
|
|
case 4:
|
|
if (maxGPSize <= 3)
|
|
break;
|
|
ObjectBuilder::AppendFragment(
|
|
*frag, *(m_pscommon_4->getSectionData()), (*com_sym)->value());
|
|
(*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
|
|
continue;
|
|
case 8:
|
|
if (maxGPSize <= 7)
|
|
break;
|
|
ObjectBuilder::AppendFragment(
|
|
*frag, *(m_pscommon_8->getSectionData()), (*com_sym)->value());
|
|
(*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
|
|
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());
|
|
(*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
|
|
} else {
|
|
// FIXME: how to identify small and large common symbols?
|
|
bss_offset += ObjectBuilder::AppendFragment(
|
|
*frag, *bss_sect_data, (*com_sym)->value());
|
|
(*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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());
|
|
|
|
switch ((*com_sym)->size()) {
|
|
case 1:
|
|
if (maxGPSize <= 0)
|
|
break;
|
|
ObjectBuilder::AppendFragment(
|
|
*frag, *(m_pscommon_1->getSectionData()), (*com_sym)->value());
|
|
(*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
|
|
continue;
|
|
case 2:
|
|
if (maxGPSize <= 1)
|
|
break;
|
|
ObjectBuilder::AppendFragment(
|
|
*frag, *(m_pscommon_2->getSectionData()), (*com_sym)->value());
|
|
(*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
|
|
continue;
|
|
case 4:
|
|
if (maxGPSize <= 3)
|
|
break;
|
|
ObjectBuilder::AppendFragment(
|
|
*frag, *(m_pscommon_4->getSectionData()), (*com_sym)->value());
|
|
(*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
|
|
continue;
|
|
case 8:
|
|
if (maxGPSize <= 7)
|
|
break;
|
|
ObjectBuilder::AppendFragment(
|
|
*frag, *(m_pscommon_8->getSectionData()), (*com_sym)->value());
|
|
(*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
|
|
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());
|
|
(*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
|
|
} else {
|
|
// FIXME: how to identify small and large common symbols?
|
|
bss_offset += ObjectBuilder::AppendFragment(
|
|
*frag, *bss_sect_data, (*com_sym)->value());
|
|
(*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
|
|
}
|
|
}
|
|
|
|
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
|
|
unsigned int alignment = pFrom.getSection().align();
|
|
align = new AlignFragment(/*alignment*/alignment,
|
|
/*the filled value*/0x0,
|
|
/*the size of filled value*/1u,
|
|
/*max bytes to emit*/alignment - 1);
|
|
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 {
|
|
llvm::StringRef region = pInput.memArea()->request(offset, size);
|
|
if (region.size() == 0) {
|
|
// 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
|
|
unsigned int alignment = pFrom.getSection().align();
|
|
align = new AlignFragment(/*alignment*/alignment,
|
|
/*the filled value*/0x0,
|
|
/*the size of filled value*/1u,
|
|
/*max bytes to emit*/alignment - 1);
|
|
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
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
/// createHexagonLDBackend - the help funtion to create corresponding
|
|
/// HexagonLDBackend
|
|
TargetLDBackend* createHexagonLDBackend(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 mcld
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Force static initialization.
|
|
//===----------------------------------------------------------------------===//
|
|
extern "C" void MCLDInitializeHexagonLDBackend() {
|
|
// Register the linker backend
|
|
mcld::TargetRegistry::RegisterTargetLDBackend(mcld::TheHexagonTarget,
|
|
mcld::createHexagonLDBackend);
|
|
}
|