| //===- 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> |
| |
| 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); |
| // 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 (invalid != NULL) { |
| 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()); |
| |
| 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().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()); |
| |
| 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); |
| } |