| //===- GNULDBackend.cpp ---------------------------------------------------===// |
| // |
| // The MCLinker Project |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| #include "mcld/Target/GNULDBackend.h" |
| |
| #include "mcld/IRBuilder.h" |
| #include "mcld/InputTree.h" |
| #include "mcld/LinkerConfig.h" |
| #include "mcld/LinkerScript.h" |
| #include "mcld/Module.h" |
| #include "mcld/ADT/SizeTraits.h" |
| #include "mcld/Config/Config.h" |
| #include "mcld/Fragment/FillFragment.h" |
| #include "mcld/LD/BranchIslandFactory.h" |
| #include "mcld/LD/EhFrame.h" |
| #include "mcld/LD/EhFrameHdr.h" |
| #include "mcld/LD/ELFDynObjFileFormat.h" |
| #include "mcld/LD/ELFExecFileFormat.h" |
| #include "mcld/LD/ELFFileFormat.h" |
| #include "mcld/LD/ELFObjectFileFormat.h" |
| #include "mcld/LD/ELFSegment.h" |
| #include "mcld/LD/ELFSegmentFactory.h" |
| #include "mcld/LD/LDContext.h" |
| #include "mcld/LD/LDSymbol.h" |
| #include "mcld/LD/RelocData.h" |
| #include "mcld/LD/RelocationFactory.h" |
| #include "mcld/LD/StubFactory.h" |
| #include "mcld/MC/Attribute.h" |
| #include "mcld/Object/ObjectBuilder.h" |
| #include "mcld/Object/SectionMap.h" |
| #include "mcld/Script/Operand.h" |
| #include "mcld/Script/OutputSectDesc.h" |
| #include "mcld/Script/RpnEvaluator.h" |
| #include "mcld/Support/FileOutputBuffer.h" |
| #include "mcld/Support/MsgHandling.h" |
| #include "mcld/Target/ELFAttribute.h" |
| #include "mcld/Target/ELFDynamic.h" |
| #include "mcld/Target/GNUInfo.h" |
| |
| #include <llvm/ADT/StringRef.h> |
| #include <llvm/Support/Host.h> |
| |
| #include <algorithm> |
| #include <cstring> |
| #include <cassert> |
| #include <map> |
| #include <string> |
| #include <vector> |
| |
| namespace { |
| |
| //===----------------------------------------------------------------------===// |
| // non-member functions |
| //===----------------------------------------------------------------------===// |
| static const std::string simple_c_identifier_allowed_chars = |
| "0123456789" |
| "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
| "abcdefghijklmnopqrstuvwxyz" |
| "_"; |
| |
| /// isCIdentifier - return if the pName is a valid C identifier |
| static bool isCIdentifier(const std::string& pName) { |
| return (pName.find_first_not_of(simple_c_identifier_allowed_chars) == |
| std::string::npos); |
| } |
| |
| } // anonymous namespace |
| |
| namespace mcld { |
| |
| //===----------------------------------------------------------------------===// |
| // GNULDBackend |
| //===----------------------------------------------------------------------===// |
| GNULDBackend::GNULDBackend(const LinkerConfig& pConfig, GNUInfo* pInfo) |
| : TargetLDBackend(pConfig), |
| m_pObjectReader(NULL), |
| m_pDynObjFileFormat(NULL), |
| m_pExecFileFormat(NULL), |
| m_pObjectFileFormat(NULL), |
| m_pInfo(pInfo), |
| m_pELFSegmentTable(NULL), |
| m_pBRIslandFactory(NULL), |
| m_pStubFactory(NULL), |
| m_pEhFrameHdr(NULL), |
| m_pAttribute(NULL), |
| m_bHasTextRel(false), |
| m_bHasStaticTLS(false), |
| f_pPreInitArrayStart(NULL), |
| f_pPreInitArrayEnd(NULL), |
| f_pInitArrayStart(NULL), |
| f_pInitArrayEnd(NULL), |
| f_pFiniArrayStart(NULL), |
| f_pFiniArrayEnd(NULL), |
| f_pStack(NULL), |
| f_pDynamic(NULL), |
| f_pTDATA(NULL), |
| f_pTBSS(NULL), |
| f_pExecutableStart(NULL), |
| f_pEText(NULL), |
| f_p_EText(NULL), |
| f_p__EText(NULL), |
| f_pEData(NULL), |
| f_p_EData(NULL), |
| f_pBSSStart(NULL), |
| f_pEnd(NULL), |
| f_p_End(NULL) { |
| m_pELFSegmentTable = new ELFSegmentFactory(); |
| m_pSymIndexMap = new HashTableType(1024); |
| m_pAttribute = new ELFAttribute(*this, pConfig); |
| } |
| |
| GNULDBackend::~GNULDBackend() { |
| delete m_pELFSegmentTable; |
| delete m_pInfo; |
| delete m_pDynObjFileFormat; |
| delete m_pExecFileFormat; |
| delete m_pObjectFileFormat; |
| delete m_pSymIndexMap; |
| delete m_pEhFrameHdr; |
| delete m_pAttribute; |
| delete m_pBRIslandFactory; |
| delete m_pStubFactory; |
| } |
| |
| size_t GNULDBackend::sectionStartOffset() const { |
| if (LinkerConfig::Binary == config().codeGenType()) |
| return 0x0; |
| |
| switch (config().targets().bitclass()) { |
| case 32u: |
| return sizeof(llvm::ELF::Elf32_Ehdr) + |
| elfSegmentTable().size() * sizeof(llvm::ELF::Elf32_Phdr); |
| case 64u: |
| return sizeof(llvm::ELF::Elf64_Ehdr) + |
| elfSegmentTable().size() * sizeof(llvm::ELF::Elf64_Phdr); |
| default: |
| fatal(diag::unsupported_bitclass) << config().targets().triple().str() |
| << config().targets().bitclass(); |
| return 0; |
| } |
| } |
| |
| uint64_t GNULDBackend::getSegmentStartAddr(const LinkerScript& pScript) const { |
| LinkerScript::AddressMap::const_iterator mapping = |
| pScript.addressMap().find(".text"); |
| if (pScript.addressMap().end() != mapping) |
| return mapping.getEntry()->value(); |
| else if (config().isCodeIndep()) |
| return 0x0; |
| else |
| return m_pInfo->defaultTextSegmentAddr(); |
| } |
| |
| GNUArchiveReader* GNULDBackend::createArchiveReader(Module& pModule) { |
| assert(m_pObjectReader != NULL); |
| return new GNUArchiveReader(pModule, *m_pObjectReader); |
| } |
| |
| ELFObjectReader* GNULDBackend::createObjectReader(IRBuilder& pBuilder) { |
| m_pObjectReader = new ELFObjectReader(*this, pBuilder, config()); |
| return m_pObjectReader; |
| } |
| |
| ELFDynObjReader* GNULDBackend::createDynObjReader(IRBuilder& pBuilder) { |
| return new ELFDynObjReader(*this, pBuilder, config()); |
| } |
| |
| ELFBinaryReader* GNULDBackend::createBinaryReader(IRBuilder& pBuilder) { |
| return new ELFBinaryReader(pBuilder, config()); |
| } |
| |
| ELFObjectWriter* GNULDBackend::createWriter() { |
| return new ELFObjectWriter(*this, config()); |
| } |
| |
| bool GNULDBackend::initStdSections(ObjectBuilder& pBuilder) { |
| switch (config().codeGenType()) { |
| case LinkerConfig::DynObj: { |
| if (m_pDynObjFileFormat == NULL) |
| m_pDynObjFileFormat = new ELFDynObjFileFormat(); |
| m_pDynObjFileFormat->initStdSections(pBuilder, |
| config().targets().bitclass()); |
| return true; |
| } |
| case LinkerConfig::Exec: |
| case LinkerConfig::Binary: { |
| if (m_pExecFileFormat == NULL) |
| m_pExecFileFormat = new ELFExecFileFormat(); |
| m_pExecFileFormat->initStdSections(pBuilder, |
| config().targets().bitclass()); |
| return true; |
| } |
| case LinkerConfig::Object: { |
| if (m_pObjectFileFormat == NULL) |
| m_pObjectFileFormat = new ELFObjectFileFormat(); |
| m_pObjectFileFormat->initStdSections(pBuilder, |
| config().targets().bitclass()); |
| return true; |
| } |
| default: |
| fatal(diag::unrecognized_output_file) << config().codeGenType(); |
| return false; |
| } |
| } |
| |
| /// initStandardSymbols - define and initialize standard symbols. |
| /// This function is called after section merging but before read relocations. |
| bool GNULDBackend::initStandardSymbols(IRBuilder& pBuilder, Module& pModule) { |
| if (LinkerConfig::Object == config().codeGenType()) |
| return true; |
| |
| // GNU extension: define __start and __stop symbols for the sections whose |
| // name can be presented as C symbol |
| Module::iterator iter, iterEnd = pModule.end(); |
| for (iter = pModule.begin(); iter != iterEnd; ++iter) { |
| LDSection* section = *iter; |
| |
| switch (section->kind()) { |
| case LDFileFormat::Relocation: |
| continue; |
| case LDFileFormat::EhFrame: |
| if (!section->hasEhFrame()) |
| continue; |
| break; |
| default: |
| if (!section->hasSectionData()) |
| continue; |
| break; |
| } // end of switch |
| |
| if (isCIdentifier(section->name())) { |
| std::string start_name = "__start_" + section->name(); |
| FragmentRef* start_fragref = |
| FragmentRef::Create(section->getSectionData()->front(), 0x0); |
| |
| pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( |
| start_name, |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Global, |
| 0x0, // size |
| 0x0, // value |
| start_fragref, // FragRef |
| ResolveInfo::Default); |
| |
| std::string stop_name = "__stop_" + section->name(); |
| FragmentRef* stop_fragref = FragmentRef::Create( |
| section->getSectionData()->front(), section->size()); |
| pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( |
| stop_name, |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Global, |
| 0x0, // size |
| 0x0, // value |
| stop_fragref, // FragRef |
| ResolveInfo::Default); |
| } |
| } |
| |
| ELFFileFormat* file_format = getOutputFormat(); |
| |
| // ----- section symbols ----- // |
| // .preinit_array |
| FragmentRef* preinit_array = NULL; |
| if (file_format->hasPreInitArray()) { |
| preinit_array = FragmentRef::Create( |
| file_format->getPreInitArray().getSectionData()->front(), 0x0); |
| } else { |
| preinit_array = FragmentRef::Null(); |
| } |
| |
| f_pPreInitArrayStart = |
| pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( |
| "__preinit_array_start", |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Global, |
| 0x0, // size |
| 0x0, // value |
| preinit_array, // FragRef |
| ResolveInfo::Hidden); |
| |
| f_pPreInitArrayEnd = |
| pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( |
| "__preinit_array_end", |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Global, |
| 0x0, // size |
| 0x0, // value |
| FragmentRef::Null(), // FragRef |
| ResolveInfo::Hidden); |
| |
| // .init_array |
| FragmentRef* init_array = NULL; |
| if (file_format->hasInitArray()) { |
| init_array = FragmentRef::Create( |
| file_format->getInitArray().getSectionData()->front(), 0x0); |
| } else { |
| init_array = FragmentRef::Null(); |
| } |
| |
| f_pInitArrayStart = |
| pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( |
| "__init_array_start", |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Global, |
| 0x0, // size |
| 0x0, // value |
| init_array, // FragRef |
| ResolveInfo::Hidden); |
| |
| f_pInitArrayEnd = |
| pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( |
| "__init_array_end", |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Global, |
| 0x0, // size |
| 0x0, // value |
| init_array, // FragRef |
| ResolveInfo::Hidden); |
| |
| // .fini_array |
| FragmentRef* fini_array = NULL; |
| if (file_format->hasFiniArray()) { |
| fini_array = FragmentRef::Create( |
| file_format->getFiniArray().getSectionData()->front(), 0x0); |
| } else { |
| fini_array = FragmentRef::Null(); |
| } |
| |
| f_pFiniArrayStart = |
| pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( |
| "__fini_array_start", |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Global, |
| 0x0, // size |
| 0x0, // value |
| fini_array, // FragRef |
| ResolveInfo::Hidden); |
| |
| f_pFiniArrayEnd = |
| pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( |
| "__fini_array_end", |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Global, |
| 0x0, // size |
| 0x0, // value |
| fini_array, // FragRef |
| ResolveInfo::Hidden); |
| |
| // .stack |
| FragmentRef* stack = NULL; |
| if (file_format->hasStack()) { |
| stack = FragmentRef::Create( |
| file_format->getStack().getSectionData()->front(), 0x0); |
| } else { |
| stack = FragmentRef::Null(); |
| } |
| |
| f_pStack = pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( |
| "__stack", |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Global, |
| 0x0, // size |
| 0x0, // value |
| stack, // FragRef |
| ResolveInfo::Hidden); |
| |
| // _DYNAMIC |
| // TODO: add SectionData for .dynamic section, and then we can get the correct |
| // symbol section index for _DYNAMIC. Now it will be ABS. |
| f_pDynamic = pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( |
| "_DYNAMIC", |
| ResolveInfo::Object, |
| ResolveInfo::Define, |
| ResolveInfo::Local, |
| 0x0, // size |
| 0x0, // value |
| FragmentRef::Null(), // FragRef |
| ResolveInfo::Hidden); |
| |
| // ----- segment symbols ----- // |
| f_pExecutableStart = |
| pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( |
| "__executable_start", |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Absolute, |
| 0x0, // size |
| 0x0, // value |
| FragmentRef::Null(), // FragRef |
| ResolveInfo::Default); |
| |
| f_pEText = pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( |
| "etext", |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Absolute, |
| 0x0, // size |
| 0x0, // value |
| FragmentRef::Null(), // FragRef |
| ResolveInfo::Default); |
| |
| f_p_EText = pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( |
| "_etext", |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Absolute, |
| 0x0, // size |
| 0x0, // value |
| FragmentRef::Null(), // FragRef |
| ResolveInfo::Default); |
| f_p__EText = pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( |
| "__etext", |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Absolute, |
| 0x0, // size |
| 0x0, // value |
| FragmentRef::Null(), // FragRef |
| ResolveInfo::Default); |
| f_pEData = pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( |
| "edata", |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Absolute, |
| 0x0, // size |
| 0x0, // value |
| FragmentRef::Null(), // FragRef |
| ResolveInfo::Default); |
| |
| f_pEnd = pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( |
| "end", |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Absolute, |
| 0x0, // size |
| 0x0, // value |
| FragmentRef::Null(), // FragRef |
| ResolveInfo::Default); |
| |
| // _edata is defined forcefully. |
| f_p_EData = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>( |
| "_edata", |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Absolute, |
| 0x0, // size |
| 0x0, // value |
| FragmentRef::Null(), // FragRef |
| ResolveInfo::Default); |
| |
| // __bss_start is defined forcefully. |
| f_pBSSStart = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>( |
| "__bss_start", |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Absolute, |
| 0x0, // size |
| 0x0, // value |
| FragmentRef::Null(), // FragRef |
| ResolveInfo::Default); |
| |
| // _end is defined forcefully. |
| f_p_End = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>( |
| "_end", |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Absolute, |
| 0x0, // size |
| 0x0, // value |
| FragmentRef::Null(), // FragRef |
| ResolveInfo::Default); |
| |
| return true; |
| } |
| |
| bool GNULDBackend::finalizeStandardSymbols() { |
| if (LinkerConfig::Object == config().codeGenType()) |
| return true; |
| |
| ELFFileFormat* file_format = getOutputFormat(); |
| |
| // ----- section symbols ----- // |
| if (f_pPreInitArrayStart != NULL) { |
| if (!f_pPreInitArrayStart->hasFragRef()) { |
| f_pPreInitArrayStart->resolveInfo()->setBinding(ResolveInfo::Absolute); |
| f_pPreInitArrayStart->setValue(0x0); |
| } |
| } |
| |
| if (f_pPreInitArrayEnd != NULL) { |
| if (f_pPreInitArrayEnd->hasFragRef()) { |
| f_pPreInitArrayEnd->setValue(f_pPreInitArrayEnd->value() + |
| file_format->getPreInitArray().size()); |
| } else { |
| f_pPreInitArrayEnd->resolveInfo()->setBinding(ResolveInfo::Absolute); |
| f_pPreInitArrayEnd->setValue(0x0); |
| } |
| } |
| |
| if (f_pInitArrayStart != NULL) { |
| if (!f_pInitArrayStart->hasFragRef()) { |
| f_pInitArrayStart->resolveInfo()->setBinding(ResolveInfo::Absolute); |
| f_pInitArrayStart->setValue(0x0); |
| } |
| } |
| |
| if (f_pInitArrayEnd != NULL) { |
| if (f_pInitArrayEnd->hasFragRef()) { |
| f_pInitArrayEnd->setValue(f_pInitArrayEnd->value() + |
| file_format->getInitArray().size()); |
| } else { |
| f_pInitArrayEnd->resolveInfo()->setBinding(ResolveInfo::Absolute); |
| f_pInitArrayEnd->setValue(0x0); |
| } |
| } |
| |
| if (f_pFiniArrayStart != NULL) { |
| if (!f_pFiniArrayStart->hasFragRef()) { |
| f_pFiniArrayStart->resolveInfo()->setBinding(ResolveInfo::Absolute); |
| f_pFiniArrayStart->setValue(0x0); |
| } |
| } |
| |
| if (f_pFiniArrayEnd != NULL) { |
| if (f_pFiniArrayEnd->hasFragRef()) { |
| f_pFiniArrayEnd->setValue(f_pFiniArrayEnd->value() + |
| file_format->getFiniArray().size()); |
| } else { |
| f_pFiniArrayEnd->resolveInfo()->setBinding(ResolveInfo::Absolute); |
| f_pFiniArrayEnd->setValue(0x0); |
| } |
| } |
| |
| if (f_pStack != NULL) { |
| if (!f_pStack->hasFragRef()) { |
| f_pStack->resolveInfo()->setBinding(ResolveInfo::Absolute); |
| f_pStack->setValue(0x0); |
| } |
| } |
| |
| if (f_pDynamic != NULL) { |
| f_pDynamic->resolveInfo()->setBinding(ResolveInfo::Local); |
| f_pDynamic->setValue(file_format->getDynamic().addr()); |
| f_pDynamic->setSize(file_format->getDynamic().size()); |
| } |
| |
| // ----- segment symbols ----- // |
| if (f_pExecutableStart != NULL) { |
| ELFSegmentFactory::const_iterator exec_start = |
| elfSegmentTable().find(llvm::ELF::PT_LOAD, 0x0, 0x0); |
| if (elfSegmentTable().end() != exec_start) { |
| if (ResolveInfo::ThreadLocal != f_pExecutableStart->type()) { |
| f_pExecutableStart->setValue(f_pExecutableStart->value() + |
| (*exec_start)->vaddr()); |
| } |
| } else { |
| f_pExecutableStart->setValue(0x0); |
| } |
| } |
| |
| if (f_pEText != NULL || f_p_EText != NULL || f_p__EText != NULL) { |
| ELFSegmentFactory::const_iterator etext = elfSegmentTable().find( |
| llvm::ELF::PT_LOAD, llvm::ELF::PF_X, llvm::ELF::PF_W); |
| if (elfSegmentTable().end() != etext) { |
| if (f_pEText != NULL && ResolveInfo::ThreadLocal != f_pEText->type()) { |
| f_pEText->setValue(f_pEText->value() + (*etext)->vaddr() + |
| (*etext)->memsz()); |
| } |
| if (f_p_EText != NULL && ResolveInfo::ThreadLocal != f_p_EText->type()) { |
| f_p_EText->setValue(f_p_EText->value() + (*etext)->vaddr() + |
| (*etext)->memsz()); |
| } |
| if (f_p__EText != NULL && |
| ResolveInfo::ThreadLocal != f_p__EText->type()) { |
| f_p__EText->setValue(f_p__EText->value() + (*etext)->vaddr() + |
| (*etext)->memsz()); |
| } |
| } else { |
| if (f_pEText != NULL) |
| f_pEText->setValue(0x0); |
| if (f_p_EText != NULL) |
| f_p_EText->setValue(0x0); |
| if (f_p__EText != NULL) |
| f_p__EText->setValue(0x0); |
| } |
| } |
| |
| if (f_pEData != NULL || f_p_EData != NULL || f_pBSSStart != NULL || |
| f_pEnd != NULL || f_p_End != NULL) { |
| ELFSegmentFactory::const_iterator edata = |
| elfSegmentTable().find(llvm::ELF::PT_LOAD, llvm::ELF::PF_W, 0x0); |
| if (elfSegmentTable().end() != edata) { |
| if (f_pEData != NULL && ResolveInfo::ThreadLocal != f_pEData->type()) { |
| f_pEData->setValue(f_pEData->value() + (*edata)->vaddr() + |
| (*edata)->filesz()); |
| } |
| if (f_p_EData != NULL && ResolveInfo::ThreadLocal != f_p_EData->type()) { |
| f_p_EData->setValue(f_p_EData->value() + (*edata)->vaddr() + |
| (*edata)->filesz()); |
| } |
| if (f_pBSSStart != NULL && |
| ResolveInfo::ThreadLocal != f_pBSSStart->type()) { |
| f_pBSSStart->setValue(f_pBSSStart->value() + (*edata)->vaddr() + |
| (*edata)->filesz()); |
| } |
| |
| if (f_pEnd != NULL && ResolveInfo::ThreadLocal != f_pEnd->type()) { |
| f_pEnd->setValue(f_pEnd->value() + (*edata)->vaddr() + |
| (*edata)->memsz()); |
| } |
| if (f_p_End != NULL && ResolveInfo::ThreadLocal != f_p_End->type()) { |
| f_p_End->setValue(f_p_End->value() + (*edata)->vaddr() + |
| (*edata)->memsz()); |
| } |
| } else { |
| if (f_pEData != NULL) |
| f_pEData->setValue(0x0); |
| if (f_p_EData != NULL) |
| f_p_EData->setValue(0x0); |
| if (f_pBSSStart != NULL) |
| f_pBSSStart->setValue(0x0); |
| |
| if (f_pEnd != NULL) |
| f_pEnd->setValue(0x0); |
| if (f_p_End != NULL) |
| f_p_End->setValue(0x0); |
| } |
| } |
| |
| return true; |
| } |
| |
| bool GNULDBackend::finalizeTLSSymbol(LDSymbol& pSymbol) { |
| // ignore if symbol has no fragRef |
| if (!pSymbol.hasFragRef()) |
| return true; |
| |
| // the value of a TLS symbol is the offset to the TLS segment |
| ELFSegmentFactory::iterator tls_seg = |
| elfSegmentTable().find(llvm::ELF::PT_TLS, llvm::ELF::PF_R, 0x0); |
| assert(tls_seg != elfSegmentTable().end()); |
| uint64_t value = pSymbol.fragRef()->getOutputOffset(); |
| uint64_t addr = pSymbol.fragRef()->frag()->getParent()->getSection().addr(); |
| pSymbol.setValue(value + addr - (*tls_seg)->vaddr()); |
| return true; |
| } |
| |
| ELFFileFormat* GNULDBackend::getOutputFormat() { |
| switch (config().codeGenType()) { |
| case LinkerConfig::DynObj: |
| assert(m_pDynObjFileFormat != NULL); |
| return m_pDynObjFileFormat; |
| case LinkerConfig::Exec: |
| case LinkerConfig::Binary: |
| assert(m_pExecFileFormat != NULL); |
| return m_pExecFileFormat; |
| case LinkerConfig::Object: |
| assert(m_pObjectFileFormat != NULL); |
| return m_pObjectFileFormat; |
| default: |
| fatal(diag::unrecognized_output_file) << config().codeGenType(); |
| return NULL; |
| } |
| } |
| |
| const ELFFileFormat* GNULDBackend::getOutputFormat() const { |
| switch (config().codeGenType()) { |
| case LinkerConfig::DynObj: |
| assert(m_pDynObjFileFormat != NULL); |
| return m_pDynObjFileFormat; |
| case LinkerConfig::Exec: |
| case LinkerConfig::Binary: |
| assert(m_pExecFileFormat != NULL); |
| return m_pExecFileFormat; |
| case LinkerConfig::Object: |
| assert(m_pObjectFileFormat != NULL); |
| return m_pObjectFileFormat; |
| default: |
| fatal(diag::unrecognized_output_file) << config().codeGenType(); |
| return NULL; |
| } |
| } |
| |
| /// sizeShstrtab - compute the size of .shstrtab |
| void GNULDBackend::sizeShstrtab(Module& pModule) { |
| size_t shstrtab = 0; |
| // compute the size of .shstrtab section. |
| Module::const_iterator sect, sectEnd = pModule.end(); |
| for (sect = pModule.begin(); sect != sectEnd; ++sect) { |
| shstrtab += (*sect)->name().size() + 1; |
| } // end of for |
| getOutputFormat()->getShStrTab().setSize(shstrtab); |
| } |
| |
| /// sizeNamePools - compute the size of regular name pools |
| /// In ELF executable files, regular name pools are .symtab, .strtab, |
| /// .dynsym, .dynstr, .hash and .shstrtab. |
| void GNULDBackend::sizeNamePools(Module& pModule) { |
| assert(LinkerConfig::Unset != config().codePosition()); |
| |
| // number of entries in symbol tables starts from 1 to hold the special entry |
| // at index 0 (STN_UNDEF). See ELF Spec Book I, p1-21. |
| size_t symtab = 1; |
| size_t dynsym = config().isCodeStatic() ? 0 : 1; |
| |
| // size of string tables starts from 1 to hold the null character in their |
| // first byte |
| size_t strtab = 1; |
| size_t dynstr = config().isCodeStatic() ? 0 : 1; |
| size_t hash = 0; |
| size_t gnuhash = 0; |
| |
| // number of local symbol in the .symtab and .dynsym |
| size_t symtab_local_cnt = 0; |
| size_t dynsym_local_cnt = 0; |
| |
| Module::SymbolTable& symbols = pModule.getSymbolTable(); |
| Module::const_sym_iterator symbol, symEnd; |
| /// Compute the size of .symtab, .strtab, and symtab_local_cnt |
| /// @{ |
| /* TODO: |
| 1. discard locals and temporary locals |
| 2. check whether the symbol is used |
| */ |
| switch (config().options().getStripSymbolMode()) { |
| case GeneralOptions::StripSymbolMode::StripAllSymbols: { |
| symtab = strtab = 0; |
| break; |
| } |
| default: { |
| symEnd = symbols.end(); |
| for (symbol = symbols.begin(); symbol != symEnd; ++symbol) { |
| ++symtab; |
| if (hasEntryInStrTab(**symbol)) |
| strtab += (*symbol)->nameSize() + 1; |
| } |
| symtab_local_cnt = 1 + symbols.numOfFiles() + symbols.numOfLocals() + |
| symbols.numOfLocalDyns(); |
| break; |
| } |
| } // end of switch |
| |
| ELFFileFormat* file_format = getOutputFormat(); |
| |
| switch (config().codeGenType()) { |
| case LinkerConfig::DynObj: { |
| // soname |
| dynstr += config().options().soname().size() + 1; |
| } |
| /** fall through **/ |
| case LinkerConfig::Exec: |
| case LinkerConfig::Binary: { |
| if (!config().isCodeStatic()) { |
| /// Compute the size of .dynsym, .dynstr, and dynsym_local_cnt |
| symEnd = symbols.dynamicEnd(); |
| for (symbol = symbols.localDynBegin(); symbol != symEnd; ++symbol) { |
| ++dynsym; |
| if (hasEntryInStrTab(**symbol)) |
| dynstr += (*symbol)->nameSize() + 1; |
| } |
| dynsym_local_cnt = 1 + symbols.numOfLocalDyns(); |
| |
| // compute .gnu.hash |
| if (config().options().hasGNUHash()) { |
| // count the number of dynsym to hash |
| size_t hashed_sym_cnt = 0; |
| symEnd = symbols.dynamicEnd(); |
| for (symbol = symbols.dynamicBegin(); symbol != symEnd; ++symbol) { |
| if (DynsymCompare().needGNUHash(**symbol)) |
| ++hashed_sym_cnt; |
| } |
| // Special case for empty .dynsym |
| if (hashed_sym_cnt == 0) |
| gnuhash = 5 * 4 + config().targets().bitclass() / 8; |
| else { |
| size_t nbucket = getHashBucketCount(hashed_sym_cnt, true); |
| gnuhash = (4 + nbucket + hashed_sym_cnt) * 4; |
| gnuhash += (1U << getGNUHashMaskbitslog2(hashed_sym_cnt)) / 8; |
| } |
| } |
| |
| // compute .hash |
| if (config().options().hasSysVHash()) { |
| // Both Elf32_Word and Elf64_Word are 4 bytes |
| hash = (2 + getHashBucketCount(dynsym, false) + dynsym) * |
| sizeof(llvm::ELF::Elf32_Word); |
| } |
| |
| // add DT_NEEDED |
| Module::const_lib_iterator lib, libEnd = pModule.lib_end(); |
| for (lib = pModule.lib_begin(); lib != libEnd; ++lib) { |
| if (!(*lib)->attribute()->isAsNeeded() || (*lib)->isNeeded()) { |
| dynstr += (*lib)->name().size() + 1; |
| dynamic().reserveNeedEntry(); |
| } |
| } |
| |
| // add DT_RPATH |
| if (!config().options().getRpathList().empty()) { |
| dynamic().reserveNeedEntry(); |
| GeneralOptions::const_rpath_iterator rpath, |
| rpathEnd = config().options().rpath_end(); |
| for (rpath = config().options().rpath_begin(); rpath != rpathEnd; |
| ++rpath) |
| dynstr += (*rpath).size() + 1; |
| } |
| |
| // set size |
| if (config().targets().is32Bits()) { |
| file_format->getDynSymTab().setSize(dynsym * |
| sizeof(llvm::ELF::Elf32_Sym)); |
| } else { |
| file_format->getDynSymTab().setSize(dynsym * |
| sizeof(llvm::ELF::Elf64_Sym)); |
| } |
| file_format->getDynStrTab().setSize(dynstr); |
| file_format->getHashTab().setSize(hash); |
| file_format->getGNUHashTab().setSize(gnuhash); |
| |
| // set .dynsym sh_info to one greater than the symbol table |
| // index of the last local symbol |
| file_format->getDynSymTab().setInfo(dynsym_local_cnt); |
| |
| // Because some entries in .dynamic section need information of .dynsym, |
| // .dynstr, .symtab, .strtab and .hash, we can not reserve non-DT_NEEDED |
| // entries until we get the size of the sections mentioned above |
| dynamic().reserveEntries(*file_format); |
| file_format->getDynamic().setSize(dynamic().numOfBytes()); |
| } |
| } |
| /* fall through */ |
| case LinkerConfig::Object: { |
| if (config().targets().is32Bits()) |
| file_format->getSymTab().setSize(symtab * sizeof(llvm::ELF::Elf32_Sym)); |
| else |
| file_format->getSymTab().setSize(symtab * sizeof(llvm::ELF::Elf64_Sym)); |
| file_format->getStrTab().setSize(strtab); |
| |
| // set .symtab sh_info to one greater than the symbol table |
| // index of the last local symbol |
| file_format->getSymTab().setInfo(symtab_local_cnt); |
| |
| // The size of .shstrtab should be decided after output sections are all |
| // set, so we just set it to 1 here. |
| file_format->getShStrTab().setSize(0x1); |
| break; |
| } |
| default: |
| fatal(diag::fatal_illegal_codegen_type) << pModule.name(); |
| break; |
| } // end of switch |
| } |
| |
| /// emitSymbol32 - emit an ELF32 symbol |
| void GNULDBackend::emitSymbol32(llvm::ELF::Elf32_Sym& pSym, |
| LDSymbol& pSymbol, |
| char* pStrtab, |
| size_t pStrtabsize, |
| size_t pSymtabIdx) { |
| // FIXME: check the endian between host and target |
| // write out symbol |
| if (hasEntryInStrTab(pSymbol)) { |
| pSym.st_name = pStrtabsize; |
| ::memcpy((pStrtab + pStrtabsize), pSymbol.name(), pSymbol.nameSize()); |
| } else { |
| pSym.st_name = 0; |
| } |
| pSym.st_value = pSymbol.value(); |
| pSym.st_size = getSymbolSize(pSymbol); |
| pSym.st_info = getSymbolInfo(pSymbol); |
| pSym.st_other = pSymbol.visibility(); |
| pSym.st_shndx = getSymbolShndx(pSymbol); |
| } |
| |
| /// emitSymbol64 - emit an ELF64 symbol |
| void GNULDBackend::emitSymbol64(llvm::ELF::Elf64_Sym& pSym, |
| LDSymbol& pSymbol, |
| char* pStrtab, |
| size_t pStrtabsize, |
| size_t pSymtabIdx) { |
| // FIXME: check the endian between host and target |
| // write out symbol |
| if (hasEntryInStrTab(pSymbol)) { |
| pSym.st_name = pStrtabsize; |
| ::memcpy((pStrtab + pStrtabsize), pSymbol.name(), pSymbol.nameSize()); |
| } else { |
| pSym.st_name = 0; |
| } |
| pSym.st_value = pSymbol.value(); |
| pSym.st_size = getSymbolSize(pSymbol); |
| pSym.st_info = getSymbolInfo(pSymbol); |
| pSym.st_other = pSymbol.visibility(); |
| pSym.st_shndx = getSymbolShndx(pSymbol); |
| } |
| |
| /// emitRegNamePools - emit regular name pools - .symtab, .strtab |
| /// |
| /// the size of these tables should be computed before layout |
| /// layout should computes the start offset of these tables |
| void GNULDBackend::emitRegNamePools(const Module& pModule, |
| FileOutputBuffer& pOutput) { |
| ELFFileFormat* file_format = getOutputFormat(); |
| if (!file_format->hasSymTab()) |
| return; |
| |
| LDSection& symtab_sect = file_format->getSymTab(); |
| LDSection& strtab_sect = file_format->getStrTab(); |
| |
| MemoryRegion symtab_region = |
| pOutput.request(symtab_sect.offset(), symtab_sect.size()); |
| MemoryRegion strtab_region = |
| pOutput.request(strtab_sect.offset(), strtab_sect.size()); |
| |
| // set up symtab_region |
| llvm::ELF::Elf32_Sym* symtab32 = NULL; |
| llvm::ELF::Elf64_Sym* symtab64 = NULL; |
| if (config().targets().is32Bits()) |
| symtab32 = (llvm::ELF::Elf32_Sym*)symtab_region.begin(); |
| else if (config().targets().is64Bits()) |
| symtab64 = (llvm::ELF::Elf64_Sym*)symtab_region.begin(); |
| else { |
| fatal(diag::unsupported_bitclass) << config().targets().triple().str() |
| << config().targets().bitclass(); |
| } |
| |
| // set up strtab_region |
| char* strtab = reinterpret_cast<char*>(strtab_region.begin()); |
| |
| // emit the first ELF symbol |
| if (config().targets().is32Bits()) |
| emitSymbol32(symtab32[0], *LDSymbol::Null(), strtab, 0, 0); |
| else |
| emitSymbol64(symtab64[0], *LDSymbol::Null(), strtab, 0, 0); |
| |
| bool sym_exist = false; |
| HashTableType::entry_type* entry = NULL; |
| if (LinkerConfig::Object == config().codeGenType()) { |
| entry = m_pSymIndexMap->insert(LDSymbol::Null(), sym_exist); |
| entry->setValue(0); |
| } |
| |
| size_t symIdx = 1; |
| size_t strtabsize = 1; |
| |
| const Module::SymbolTable& symbols = pModule.getSymbolTable(); |
| Module::const_sym_iterator symbol, symEnd; |
| |
| symEnd = symbols.end(); |
| for (symbol = symbols.begin(); symbol != symEnd; ++symbol) { |
| if (LinkerConfig::Object == config().codeGenType()) { |
| entry = m_pSymIndexMap->insert(*symbol, sym_exist); |
| entry->setValue(symIdx); |
| } |
| if (config().targets().is32Bits()) |
| emitSymbol32(symtab32[symIdx], **symbol, strtab, strtabsize, symIdx); |
| else |
| emitSymbol64(symtab64[symIdx], **symbol, strtab, strtabsize, symIdx); |
| ++symIdx; |
| if (hasEntryInStrTab(**symbol)) |
| strtabsize += (*symbol)->nameSize() + 1; |
| } |
| } |
| |
| /// emitDynNamePools - emit dynamic name pools - .dyntab, .dynstr, .hash |
| /// |
| /// the size of these tables should be computed before layout |
| /// layout should computes the start offset of these tables |
| void GNULDBackend::emitDynNamePools(Module& pModule, |
| FileOutputBuffer& pOutput) { |
| ELFFileFormat* file_format = getOutputFormat(); |
| if (!file_format->hasDynSymTab() || !file_format->hasDynStrTab() || |
| !file_format->hasDynamic()) |
| return; |
| |
| bool sym_exist = false; |
| HashTableType::entry_type* entry = 0; |
| |
| LDSection& symtab_sect = file_format->getDynSymTab(); |
| LDSection& strtab_sect = file_format->getDynStrTab(); |
| LDSection& dyn_sect = file_format->getDynamic(); |
| |
| MemoryRegion symtab_region = |
| pOutput.request(symtab_sect.offset(), symtab_sect.size()); |
| MemoryRegion strtab_region = |
| pOutput.request(strtab_sect.offset(), strtab_sect.size()); |
| MemoryRegion dyn_region = pOutput.request(dyn_sect.offset(), dyn_sect.size()); |
| // set up symtab_region |
| llvm::ELF::Elf32_Sym* symtab32 = NULL; |
| llvm::ELF::Elf64_Sym* symtab64 = NULL; |
| if (config().targets().is32Bits()) |
| symtab32 = (llvm::ELF::Elf32_Sym*)symtab_region.begin(); |
| else if (config().targets().is64Bits()) |
| symtab64 = (llvm::ELF::Elf64_Sym*)symtab_region.begin(); |
| else { |
| fatal(diag::unsupported_bitclass) << config().targets().triple().str() |
| << config().targets().bitclass(); |
| } |
| |
| // set up strtab_region |
| char* strtab = reinterpret_cast<char*>(strtab_region.begin()); |
| |
| // emit the first ELF symbol |
| if (config().targets().is32Bits()) |
| emitSymbol32(symtab32[0], *LDSymbol::Null(), strtab, 0, 0); |
| else |
| emitSymbol64(symtab64[0], *LDSymbol::Null(), strtab, 0, 0); |
| |
| size_t symIdx = 1; |
| size_t strtabsize = 1; |
| |
| Module::SymbolTable& symbols = pModule.getSymbolTable(); |
| // emit .gnu.hash |
| if (config().options().hasGNUHash()) |
| emitGNUHashTab(symbols, pOutput); |
| |
| // emit .hash |
| if (config().options().hasSysVHash()) |
| emitELFHashTab(symbols, pOutput); |
| |
| // emit .dynsym, and .dynstr (emit LocalDyn and Dynamic category) |
| Module::const_sym_iterator symbol, symEnd = symbols.dynamicEnd(); |
| for (symbol = symbols.localDynBegin(); symbol != symEnd; ++symbol) { |
| if (config().targets().is32Bits()) |
| emitSymbol32(symtab32[symIdx], **symbol, strtab, strtabsize, symIdx); |
| else |
| emitSymbol64(symtab64[symIdx], **symbol, strtab, strtabsize, symIdx); |
| // maintain output's symbol and index map |
| entry = m_pSymIndexMap->insert(*symbol, sym_exist); |
| entry->setValue(symIdx); |
| // sum up counters |
| ++symIdx; |
| if (hasEntryInStrTab(**symbol)) |
| strtabsize += (*symbol)->nameSize() + 1; |
| } |
| |
| // emit DT_NEED |
| // add DT_NEED strings into .dynstr |
| ELFDynamic::iterator dt_need = dynamic().needBegin(); |
| Module::const_lib_iterator lib, libEnd = pModule.lib_end(); |
| for (lib = pModule.lib_begin(); lib != libEnd; ++lib) { |
| if (!(*lib)->attribute()->isAsNeeded() || (*lib)->isNeeded()) { |
| ::memcpy((strtab + strtabsize), |
| (*lib)->name().c_str(), |
| (*lib)->name().size()); |
| (*dt_need)->setValue(llvm::ELF::DT_NEEDED, strtabsize); |
| strtabsize += (*lib)->name().size() + 1; |
| ++dt_need; |
| } |
| } |
| |
| if (!config().options().getRpathList().empty()) { |
| if (!config().options().hasNewDTags()) |
| (*dt_need)->setValue(llvm::ELF::DT_RPATH, strtabsize); |
| else |
| (*dt_need)->setValue(llvm::ELF::DT_RUNPATH, strtabsize); |
| ++dt_need; |
| |
| GeneralOptions::const_rpath_iterator rpath, |
| rpathEnd = config().options().rpath_end(); |
| for (rpath = config().options().rpath_begin(); rpath != rpathEnd; ++rpath) { |
| memcpy((strtab + strtabsize), (*rpath).data(), (*rpath).size()); |
| strtabsize += (*rpath).size(); |
| strtab[strtabsize++] = (rpath + 1 == rpathEnd ? '\0' : ':'); |
| } |
| } |
| |
| // initialize value of ELF .dynamic section |
| if (LinkerConfig::DynObj == config().codeGenType()) { |
| // set pointer to SONAME entry in dynamic string table. |
| dynamic().applySoname(strtabsize); |
| } |
| dynamic().applyEntries(*file_format); |
| dynamic().emit(dyn_sect, dyn_region); |
| |
| // emit soname |
| if (LinkerConfig::DynObj == config().codeGenType()) { |
| ::memcpy((strtab + strtabsize), |
| config().options().soname().c_str(), |
| config().options().soname().size()); |
| strtabsize += config().options().soname().size() + 1; |
| } |
| } |
| |
| /// emitELFHashTab - emit .hash |
| void GNULDBackend::emitELFHashTab(const Module::SymbolTable& pSymtab, |
| FileOutputBuffer& pOutput) { |
| ELFFileFormat* file_format = getOutputFormat(); |
| if (!file_format->hasHashTab()) |
| return; |
| LDSection& hash_sect = file_format->getHashTab(); |
| MemoryRegion hash_region = |
| pOutput.request(hash_sect.offset(), hash_sect.size()); |
| // both 32 and 64 bits hash table use 32-bit entry |
| // set up hash_region |
| uint32_t* word_array = reinterpret_cast<uint32_t*>(hash_region.begin()); |
| uint32_t& nbucket = word_array[0]; |
| uint32_t& nchain = word_array[1]; |
| |
| size_t dynsymSize = 1 + pSymtab.numOfLocalDyns() + pSymtab.numOfDynamics(); |
| nbucket = getHashBucketCount(dynsymSize, false); |
| nchain = dynsymSize; |
| |
| uint32_t* bucket = (word_array + 2); |
| uint32_t* chain = (bucket + nbucket); |
| |
| // initialize bucket |
| memset(reinterpret_cast<void*>(bucket), 0, nbucket); |
| |
| hash::StringHash<hash::ELF> hash_func; |
| |
| size_t idx = 1; |
| Module::const_sym_iterator symbol, symEnd = pSymtab.dynamicEnd(); |
| for (symbol = pSymtab.localDynBegin(); symbol != symEnd; ++symbol) { |
| llvm::StringRef name((*symbol)->name()); |
| size_t bucket_pos = hash_func(name) % nbucket; |
| chain[idx] = bucket[bucket_pos]; |
| bucket[bucket_pos] = idx; |
| ++idx; |
| } |
| } |
| |
| /// emitGNUHashTab - emit .gnu.hash |
| void GNULDBackend::emitGNUHashTab(Module::SymbolTable& pSymtab, |
| FileOutputBuffer& pOutput) { |
| ELFFileFormat* file_format = getOutputFormat(); |
| if (!file_format->hasGNUHashTab()) |
| return; |
| |
| MemoryRegion gnuhash_region = |
| pOutput.request(file_format->getGNUHashTab().offset(), |
| file_format->getGNUHashTab().size()); |
| |
| uint32_t* word_array = reinterpret_cast<uint32_t*>(gnuhash_region.begin()); |
| // fixed-length fields |
| uint32_t& nbucket = word_array[0]; |
| uint32_t& symidx = word_array[1]; |
| uint32_t& maskwords = word_array[2]; |
| uint32_t& shift2 = word_array[3]; |
| // variable-length fields |
| uint8_t* bitmask = reinterpret_cast<uint8_t*>(word_array + 4); |
| uint32_t* bucket = NULL; |
| uint32_t* chain = NULL; |
| |
| // count the number of dynsym to hash |
| size_t unhashed_sym_cnt = pSymtab.numOfLocalDyns(); |
| size_t hashed_sym_cnt = pSymtab.numOfDynamics(); |
| Module::const_sym_iterator symbol, symEnd = pSymtab.dynamicEnd(); |
| for (symbol = pSymtab.dynamicBegin(); symbol != symEnd; ++symbol) { |
| if (DynsymCompare().needGNUHash(**symbol)) |
| break; |
| ++unhashed_sym_cnt; |
| --hashed_sym_cnt; |
| } |
| |
| // special case for the empty hash table |
| if (hashed_sym_cnt == 0) { |
| nbucket = 1; // one empty bucket |
| symidx = 1 + unhashed_sym_cnt; // symidx above unhashed symbols |
| maskwords = 1; // bitmask length |
| shift2 = 0; // bloom filter |
| |
| if (config().targets().is32Bits()) { |
| uint32_t* maskval = reinterpret_cast<uint32_t*>(bitmask); |
| *maskval = 0; // no valid hashes |
| } else { |
| // must be 64 |
| uint64_t* maskval = reinterpret_cast<uint64_t*>(bitmask); |
| *maskval = 0; // no valid hashes |
| } |
| bucket = reinterpret_cast<uint32_t*>(bitmask + |
| config().targets().bitclass() / 8); |
| *bucket = 0; // no hash in the only bucket |
| return; |
| } |
| |
| uint32_t maskbitslog2 = getGNUHashMaskbitslog2(hashed_sym_cnt); |
| uint32_t maskbits = 1u << maskbitslog2; |
| uint32_t shift1 = config().targets().is32Bits() ? 5 : 6; |
| uint32_t mask = (1u << shift1) - 1; |
| |
| nbucket = getHashBucketCount(hashed_sym_cnt, true); |
| symidx = 1 + unhashed_sym_cnt; |
| maskwords = 1 << (maskbitslog2 - shift1); |
| shift2 = maskbitslog2; |
| |
| // setup bucket and chain |
| bucket = reinterpret_cast<uint32_t*>(bitmask + maskbits / 8); |
| chain = (bucket + nbucket); |
| |
| // build the gnu style hash table |
| typedef std::multimap<uint32_t, std::pair<LDSymbol*, uint32_t> > SymMapType; |
| SymMapType symmap; |
| symEnd = pSymtab.dynamicEnd(); |
| for (symbol = pSymtab.localDynBegin() + symidx - 1; symbol != symEnd; |
| ++symbol) { |
| hash::StringHash<hash::DJB> hasher; |
| uint32_t djbhash = hasher((*symbol)->name()); |
| uint32_t hash = djbhash % nbucket; |
| symmap.insert(std::make_pair(hash, std::make_pair(*symbol, djbhash))); |
| } |
| |
| // compute bucket, chain, and bitmask |
| std::vector<uint64_t> bitmasks(maskwords); |
| size_t hashedidx = symidx; |
| for (size_t idx = 0; idx < nbucket; ++idx) { |
| size_t count = 0; |
| std::pair<SymMapType::iterator, SymMapType::iterator> ret; |
| ret = symmap.equal_range(idx); |
| for (SymMapType::iterator it = ret.first; it != ret.second;) { |
| // rearrange the hashed symbol ordering |
| *(pSymtab.localDynBegin() + hashedidx - 1) = it->second.first; |
| uint32_t djbhash = it->second.second; |
| uint32_t val = ((djbhash >> shift1) & ((maskbits >> shift1) - 1)); |
| bitmasks[val] |= 1u << (djbhash & mask); |
| bitmasks[val] |= 1u << ((djbhash >> shift2) & mask); |
| val = djbhash & ~1u; |
| // advance the iterator and check if we're dealing w/ the last elment |
| if (++it == ret.second) { |
| // last element terminates the chain |
| val |= 1; |
| } |
| chain[hashedidx - symidx] = val; |
| |
| ++hashedidx; |
| ++count; |
| } |
| |
| if (count == 0) |
| bucket[idx] = 0; |
| else |
| bucket[idx] = hashedidx - count; |
| } |
| |
| // write the bitmasks |
| if (config().targets().is32Bits()) { |
| uint32_t* maskval = reinterpret_cast<uint32_t*>(bitmask); |
| for (size_t i = 0; i < maskwords; ++i) |
| std::memcpy(maskval + i, &bitmasks[i], 4); |
| } else { |
| // must be 64 |
| uint64_t* maskval = reinterpret_cast<uint64_t*>(bitmask); |
| for (size_t i = 0; i < maskwords; ++i) |
| std::memcpy(maskval + i, &bitmasks[i], 8); |
| } |
| } |
| |
| /// sizeInterp - compute the size of the .interp section |
| void GNULDBackend::sizeInterp() { |
| const char* dyld_name; |
| if (config().options().hasDyld()) |
| dyld_name = config().options().dyld().c_str(); |
| else |
| dyld_name = m_pInfo->dyld(); |
| |
| LDSection& interp = getOutputFormat()->getInterp(); |
| interp.setSize(std::strlen(dyld_name) + 1); |
| } |
| |
| /// emitInterp - emit the .interp |
| void GNULDBackend::emitInterp(FileOutputBuffer& pOutput) { |
| if (getOutputFormat()->hasInterp()) { |
| const LDSection& interp = getOutputFormat()->getInterp(); |
| MemoryRegion region = pOutput.request(interp.offset(), interp.size()); |
| const char* dyld_name; |
| if (config().options().hasDyld()) |
| dyld_name = config().options().dyld().c_str(); |
| else |
| dyld_name = m_pInfo->dyld(); |
| |
| std::memcpy(region.begin(), dyld_name, interp.size()); |
| } |
| } |
| |
| bool GNULDBackend::hasEntryInStrTab(const LDSymbol& pSym) const { |
| return ResolveInfo::Section != pSym.type(); |
| } |
| |
| void GNULDBackend::orderSymbolTable(Module& pModule) { |
| Module::SymbolTable& symbols = pModule.getSymbolTable(); |
| |
| if (config().options().hasGNUHash()) { |
| // Currently we may add output symbols after sizeNamePools(), and a |
| // non-stable sort is used in SymbolCategory::arrange(), so we just |
| // sort .dynsym right before emitting .gnu.hash |
| std::stable_sort( |
| symbols.dynamicBegin(), symbols.dynamicEnd(), DynsymCompare()); |
| } |
| } |
| |
| /// getSectionOrder |
| unsigned int GNULDBackend::getSectionOrder(const LDSection& pSectHdr) const { |
| const ELFFileFormat* file_format = getOutputFormat(); |
| |
| // NULL section should be the "1st" section |
| if (LDFileFormat::Null == pSectHdr.kind()) |
| return SHO_NULL; |
| |
| if (&pSectHdr == &file_format->getStrTab()) |
| return SHO_STRTAB; |
| |
| // if the section is not ALLOC, lay it out until the last possible moment |
| if (0 == (pSectHdr.flag() & llvm::ELF::SHF_ALLOC)) |
| return SHO_UNDEFINED; |
| |
| bool is_write = (pSectHdr.flag() & llvm::ELF::SHF_WRITE) != 0; |
| bool is_exec = (pSectHdr.flag() & llvm::ELF::SHF_EXECINSTR) != 0; |
| // TODO: need to take care other possible output sections |
| switch (pSectHdr.kind()) { |
| case LDFileFormat::TEXT: |
| case LDFileFormat::DATA: |
| if (is_exec) { |
| if (&pSectHdr == &file_format->getInit()) |
| return SHO_INIT; |
| if (&pSectHdr == &file_format->getFini()) |
| return SHO_FINI; |
| return SHO_TEXT; |
| } else if (!is_write) { |
| return SHO_RO; |
| } else { |
| if (config().options().hasRelro()) { |
| if (&pSectHdr == &file_format->getPreInitArray() || |
| &pSectHdr == &file_format->getInitArray() || |
| &pSectHdr == &file_format->getFiniArray() || |
| &pSectHdr == &file_format->getCtors() || |
| &pSectHdr == &file_format->getDtors() || |
| &pSectHdr == &file_format->getJCR() || |
| &pSectHdr == &file_format->getDataRelRo()) |
| return SHO_RELRO; |
| |
| if (&pSectHdr == &file_format->getDataRelRoLocal()) |
| return SHO_RELRO_LOCAL; |
| |
| // Make special sections that end with .rel.ro suffix as RELRO. |
| llvm::StringRef name(pSectHdr.name()); |
| if (name.endswith(".rel.ro")) { |
| return SHO_RELRO; |
| } |
| } |
| if ((pSectHdr.flag() & llvm::ELF::SHF_TLS) != 0x0) { |
| return SHO_TLS_DATA; |
| } |
| return SHO_DATA; |
| } |
| |
| case LDFileFormat::BSS: |
| if ((pSectHdr.flag() & llvm::ELF::SHF_TLS) != 0x0) |
| return SHO_TLS_BSS; |
| return SHO_BSS; |
| |
| case LDFileFormat::NamePool: { |
| if (&pSectHdr == &file_format->getDynamic()) |
| return SHO_RELRO; |
| return SHO_NAMEPOOL; |
| } |
| case LDFileFormat::Relocation: |
| if (&pSectHdr == &file_format->getRelPlt() || |
| &pSectHdr == &file_format->getRelaPlt()) |
| return SHO_REL_PLT; |
| return SHO_RELOCATION; |
| |
| // get the order from target for target specific sections |
| case LDFileFormat::Target: |
| return getTargetSectionOrder(pSectHdr); |
| |
| // handle .interp and .note.* sections |
| case LDFileFormat::Note: |
| if (file_format->hasInterp() && (&pSectHdr == &file_format->getInterp())) |
| return SHO_INTERP; |
| else if (is_write) |
| return SHO_RW_NOTE; |
| else |
| return SHO_RO_NOTE; |
| |
| case LDFileFormat::EhFrame: |
| // set writable .eh_frame as relro |
| if (is_write) |
| return SHO_RELRO; |
| case LDFileFormat::EhFrameHdr: |
| case LDFileFormat::GCCExceptTable: |
| return SHO_EXCEPTION; |
| |
| case LDFileFormat::MetaData: |
| case LDFileFormat::Debug: |
| case LDFileFormat::DebugString: |
| default: |
| return SHO_UNDEFINED; |
| } |
| } |
| |
| /// getSymbolSize |
| uint64_t GNULDBackend::getSymbolSize(const LDSymbol& pSymbol) const { |
| // undefined and dynamic symbols should have zero size. |
| if (pSymbol.isDyn() || pSymbol.desc() == ResolveInfo::Undefined) |
| return 0x0; |
| return pSymbol.resolveInfo()->size(); |
| } |
| |
| /// getSymbolInfo |
| uint64_t GNULDBackend::getSymbolInfo(const LDSymbol& pSymbol) const { |
| // set binding |
| uint8_t bind = 0x0; |
| if (pSymbol.resolveInfo()->isLocal()) |
| bind = llvm::ELF::STB_LOCAL; |
| else if (pSymbol.resolveInfo()->isGlobal()) |
| bind = llvm::ELF::STB_GLOBAL; |
| else if (pSymbol.resolveInfo()->isWeak()) |
| bind = llvm::ELF::STB_WEAK; |
| else if (pSymbol.resolveInfo()->isAbsolute()) { |
| // (Luba) Is a absolute but not global (weak or local) symbol meaningful? |
| bind = llvm::ELF::STB_GLOBAL; |
| } |
| |
| if (config().codeGenType() != LinkerConfig::Object && |
| (pSymbol.visibility() == llvm::ELF::STV_INTERNAL || |
| pSymbol.visibility() == llvm::ELF::STV_HIDDEN)) |
| bind = llvm::ELF::STB_LOCAL; |
| |
| uint32_t type = pSymbol.resolveInfo()->type(); |
| // if the IndirectFunc symbol (i.e., STT_GNU_IFUNC) is from dynobj, change |
| // its type to Function |
| if (type == ResolveInfo::IndirectFunc && pSymbol.isDyn()) |
| type = ResolveInfo::Function; |
| return (type | (bind << 4)); |
| } |
| |
| /// getSymbolValue - this function is called after layout() |
| uint64_t GNULDBackend::getSymbolValue(const LDSymbol& pSymbol) const { |
| if (pSymbol.isDyn()) |
| return 0x0; |
| |
| return pSymbol.value(); |
| } |
| |
| /// getSymbolShndx - this function is called after layout() |
| uint64_t GNULDBackend::getSymbolShndx(const LDSymbol& pSymbol) const { |
| if (pSymbol.resolveInfo()->isAbsolute()) |
| return llvm::ELF::SHN_ABS; |
| if (pSymbol.resolveInfo()->isCommon()) |
| return llvm::ELF::SHN_COMMON; |
| if (pSymbol.resolveInfo()->isUndef() || pSymbol.isDyn()) |
| return llvm::ELF::SHN_UNDEF; |
| |
| if (pSymbol.resolveInfo()->isDefine() && !pSymbol.hasFragRef()) |
| return llvm::ELF::SHN_ABS; |
| |
| assert(pSymbol.hasFragRef() && |
| "symbols must have fragment reference to get its index"); |
| return pSymbol.fragRef()->frag()->getParent()->getSection().index(); |
| } |
| |
| /// getSymbolIdx - called by emitRelocation to get the ouput symbol table index |
| size_t GNULDBackend::getSymbolIdx(const LDSymbol* pSymbol) const { |
| HashTableType::iterator entry = |
| m_pSymIndexMap->find(const_cast<LDSymbol*>(pSymbol)); |
| assert(entry != m_pSymIndexMap->end() && |
| "symbol not found in the symbol table"); |
| return entry.getEntry()->value(); |
| } |
| |
| /// isTemporary - Whether pSymbol is a local label. |
| bool GNULDBackend::isTemporary(const LDSymbol& pSymbol) const { |
| if (ResolveInfo::Local != pSymbol.binding()) |
| return false; |
| |
| if (pSymbol.nameSize() < 2) |
| return false; |
| |
| const char* name = pSymbol.name(); |
| if ('.' == name[0] && 'L' == name[1]) |
| return true; |
| |
| // UnixWare 2.1 cc generate DWARF debugging symbols with `..' prefix. |
| if (name[0] == '.' && name[1] == '.') |
| return true; |
| |
| // Work arround for gcc's bug |
| // gcc sometimes generate symbols with '_.L_' prefix. |
| if (pSymbol.nameSize() < 4) |
| return false; |
| |
| if (name[0] == '_' && name[1] == '.' && name[2] == 'L' && name[3] == '_') |
| return true; |
| |
| return false; |
| } |
| |
| /// allocateCommonSymbols - allocate common symbols in the corresponding |
| /// sections. This is executed at pre-layout stage. |
| bool GNULDBackend::allocateCommonSymbols(Module& pModule) { |
| SymbolCategory& symbol_list = pModule.getSymbolTable(); |
| |
| if (symbol_list.emptyCommons() && symbol_list.emptyFiles() && |
| symbol_list.emptyLocals() && symbol_list.emptyLocalDyns()) |
| return true; |
| |
| SymbolCategory::iterator com_sym, com_end; |
| |
| // FIXME: If the order of common symbols is defined, then sort common symbols |
| // std::sort(com_sym, com_end, some kind of order); |
| |
| // 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()); |
| |
| if (ResolveInfo::ThreadLocal == (*com_sym)->type()) { |
| // allocate TLS common symbol in tbss section |
| tbss_offset += ObjectBuilder::AppendFragment( |
| *frag, *tbss_sect_data, (*com_sym)->value()); |
| ObjectBuilder::UpdateSectionAlign(tbss_sect, (*com_sym)->value()); |
| (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0)); |
| } else { |
| bss_offset += ObjectBuilder::AppendFragment( |
| *frag, *bss_sect_data, (*com_sym)->value()); |
| ObjectBuilder::UpdateSectionAlign(bss_sect, (*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()); |
| |
| if (ResolveInfo::ThreadLocal == (*com_sym)->type()) { |
| // allocate TLS common symbol in tbss section |
| tbss_offset += ObjectBuilder::AppendFragment( |
| *frag, *tbss_sect_data, (*com_sym)->value()); |
| ObjectBuilder::UpdateSectionAlign(tbss_sect, (*com_sym)->value()); |
| (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0)); |
| } else { |
| bss_offset += ObjectBuilder::AppendFragment( |
| *frag, *bss_sect_data, (*com_sym)->value()); |
| ObjectBuilder::UpdateSectionAlign(bss_sect, (*com_sym)->value()); |
| (*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0)); |
| } |
| } |
| |
| bss_sect.setSize(bss_offset); |
| tbss_sect.setSize(tbss_offset); |
| symbol_list.changeCommonsToGlobal(); |
| return true; |
| } |
| |
| /// updateSectionFlags - update pTo's flags when merging pFrom |
| /// update the output section flags based on input section flags. |
| bool GNULDBackend::updateSectionFlags(LDSection& pTo, const LDSection& pFrom) { |
| // union the flags from input |
| uint32_t flags = pTo.flag(); |
| flags |= (pFrom.flag() & (llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC | |
| llvm::ELF::SHF_EXECINSTR)); |
| |
| // if there is an input section is not SHF_MERGE, clean this flag |
| if (0 == (pFrom.flag() & llvm::ELF::SHF_MERGE)) |
| flags &= ~llvm::ELF::SHF_MERGE; |
| |
| // if there is an input section is not SHF_STRINGS, clean this flag |
| if (0 == (pFrom.flag() & llvm::ELF::SHF_STRINGS)) |
| flags &= ~llvm::ELF::SHF_STRINGS; |
| |
| pTo.setFlag(flags); |
| return true; |
| } |
| |
| /// readRelocation - read ELF32_Rel entry |
| bool GNULDBackend::readRelocation(const llvm::ELF::Elf32_Rel& pRel, |
| Relocation::Type& pType, |
| uint32_t& pSymIdx, |
| uint32_t& pOffset) const { |
| uint32_t r_info = 0x0; |
| if (llvm::sys::IsLittleEndianHost) { |
| pOffset = pRel.r_offset; |
| r_info = pRel.r_info; |
| } else { |
| pOffset = mcld::bswap32(pRel.r_offset); |
| r_info = mcld::bswap32(pRel.r_info); |
| } |
| |
| pType = static_cast<unsigned char>(r_info); |
| pSymIdx = (r_info >> 8); |
| return true; |
| } |
| |
| /// readRelocation - read ELF32_Rela entry |
| bool GNULDBackend::readRelocation(const llvm::ELF::Elf32_Rela& pRel, |
| Relocation::Type& pType, |
| uint32_t& pSymIdx, |
| uint32_t& pOffset, |
| int32_t& pAddend) const { |
| uint32_t r_info = 0x0; |
| if (llvm::sys::IsLittleEndianHost) { |
| pOffset = pRel.r_offset; |
| r_info = pRel.r_info; |
| pAddend = pRel.r_addend; |
| } else { |
| pOffset = mcld::bswap32(pRel.r_offset); |
| r_info = mcld::bswap32(pRel.r_info); |
| pAddend = mcld::bswap32(pRel.r_addend); |
| } |
| |
| pType = static_cast<unsigned char>(r_info); |
| pSymIdx = (r_info >> 8); |
| return true; |
| } |
| |
| /// readRelocation - read ELF64_Rel entry |
| bool GNULDBackend::readRelocation(const llvm::ELF::Elf64_Rel& pRel, |
| Relocation::Type& pType, |
| uint32_t& pSymIdx, |
| uint64_t& pOffset) const { |
| uint64_t r_info = 0x0; |
| if (llvm::sys::IsLittleEndianHost) { |
| pOffset = pRel.r_offset; |
| r_info = pRel.r_info; |
| } else { |
| pOffset = mcld::bswap64(pRel.r_offset); |
| r_info = mcld::bswap64(pRel.r_info); |
| } |
| |
| pType = static_cast<uint32_t>(r_info); |
| pSymIdx = (r_info >> 32); |
| return true; |
| } |
| |
| /// readRel - read ELF64_Rela entry |
| bool GNULDBackend::readRelocation(const llvm::ELF::Elf64_Rela& pRel, |
| Relocation::Type& pType, |
| uint32_t& pSymIdx, |
| uint64_t& pOffset, |
| int64_t& pAddend) const { |
| uint64_t r_info = 0x0; |
| if (llvm::sys::IsLittleEndianHost) { |
| pOffset = pRel.r_offset; |
| r_info = pRel.r_info; |
| pAddend = pRel.r_addend; |
| } else { |
| pOffset = mcld::bswap64(pRel.r_offset); |
| r_info = mcld::bswap64(pRel.r_info); |
| pAddend = mcld::bswap64(pRel.r_addend); |
| } |
| |
| pType = static_cast<uint32_t>(r_info); |
| pSymIdx = (r_info >> 32); |
| return true; |
| } |
| |
| /// emitRelocation - write data to the ELF32_Rel entry |
| void GNULDBackend::emitRelocation(llvm::ELF::Elf32_Rel& pRel, |
| Relocation::Type pType, |
| uint32_t pSymIdx, |
| uint32_t pOffset) const { |
| pRel.r_offset = pOffset; |
| pRel.setSymbolAndType(pSymIdx, pType); |
| } |
| |
| /// emitRelocation - write data to the ELF32_Rela entry |
| void GNULDBackend::emitRelocation(llvm::ELF::Elf32_Rela& pRel, |
| Relocation::Type pType, |
| uint32_t pSymIdx, |
| uint32_t pOffset, |
| int32_t pAddend) const { |
| pRel.r_offset = pOffset; |
| pRel.r_addend = pAddend; |
| pRel.setSymbolAndType(pSymIdx, pType); |
| } |
| |
| /// emitRelocation - write data to the ELF64_Rel entry |
| void GNULDBackend::emitRelocation(llvm::ELF::Elf64_Rel& pRel, |
| Relocation::Type pType, |
| uint32_t pSymIdx, |
| uint64_t pOffset) const { |
| pRel.r_offset = pOffset; |
| pRel.setSymbolAndType(pSymIdx, pType); |
| } |
| |
| /// emitRelocation - write data to the ELF64_Rela entry |
| void GNULDBackend::emitRelocation(llvm::ELF::Elf64_Rela& pRel, |
| Relocation::Type pType, |
| uint32_t pSymIdx, |
| uint64_t pOffset, |
| int64_t pAddend) const { |
| pRel.r_offset = pOffset; |
| pRel.r_addend = pAddend; |
| pRel.setSymbolAndType(pSymIdx, pType); |
| } |
| |
| /// createProgramHdrs - base on output sections to create the program headers |
| void GNULDBackend::createProgramHdrs(Module& pModule) { |
| ELFFileFormat* file_format = getOutputFormat(); |
| |
| // make PT_INTERP |
| if (file_format->hasInterp()) { |
| // make PT_PHDR |
| elfSegmentTable().produce(llvm::ELF::PT_PHDR); |
| |
| ELFSegment* interp_seg = elfSegmentTable().produce(llvm::ELF::PT_INTERP); |
| interp_seg->append(&file_format->getInterp()); |
| } |
| |
| uint32_t cur_flag, prev_flag = 0x0; |
| ELFSegment* load_seg = NULL; |
| // make possible PT_LOAD segments |
| LinkerScript& ldscript = pModule.getScript(); |
| LinkerScript::AddressMap::iterator addrEnd = ldscript.addressMap().end(); |
| SectionMap::iterator out, prev, outBegin, outEnd; |
| outBegin = ldscript.sectionMap().begin(); |
| outEnd = ldscript.sectionMap().end(); |
| for (out = outBegin, prev = outEnd; out != outEnd; prev = out, ++out) { |
| LDSection* sect = (*out)->getSection(); |
| |
| if (0 == (sect->flag() & llvm::ELF::SHF_ALLOC) && |
| LDFileFormat::Null != sect->kind()) |
| break; |
| |
| // bypass empty sections |
| if (!(*out)->hasContent() && |
| (*out)->getSection()->kind() != LDFileFormat::Null) |
| continue; |
| |
| cur_flag = getSegmentFlag(sect->flag()); |
| bool createPT_LOAD = false; |
| if (LDFileFormat::Null == sect->kind()) { |
| // 1. create text segment |
| createPT_LOAD = true; |
| } else if (!config().options().omagic() && |
| (prev_flag & llvm::ELF::PF_W) ^ (cur_flag & llvm::ELF::PF_W)) { |
| // 2. create data segment if w/o omagic set |
| createPT_LOAD = true; |
| } else if (sect->kind() == LDFileFormat::BSS && load_seg->isDataSegment() && |
| addrEnd != ldscript.addressMap().find(".bss")) { |
| // 3. create bss segment if w/ -Tbss and there is a data segment |
| createPT_LOAD = true; |
| } else if ((sect != &(file_format->getText())) && |
| (sect != &(file_format->getData())) && |
| (sect != &(file_format->getBSS())) && |
| (addrEnd != ldscript.addressMap().find(sect->name()))) { |
| // 4. create PT_LOAD for sections in address map except for text, data, |
| // and bss |
| createPT_LOAD = true; |
| } else if (LDFileFormat::Null == (*prev)->getSection()->kind() && |
| !config().options().getScriptList().empty()) { |
| // 5. create PT_LOAD to hold NULL section if there is a default ldscript |
| createPT_LOAD = true; |
| } |
| |
| if (createPT_LOAD) { |
| // create new PT_LOAD segment |
| load_seg = elfSegmentTable().produce(llvm::ELF::PT_LOAD, cur_flag); |
| if (!config().options().nmagic() && !config().options().omagic()) |
| load_seg->setAlign(abiPageSize()); |
| } |
| |
| assert(load_seg != NULL); |
| load_seg->append(sect); |
| if (cur_flag != prev_flag) |
| load_seg->updateFlag(cur_flag); |
| |
| prev_flag = cur_flag; |
| } |
| |
| // make PT_DYNAMIC |
| if (file_format->hasDynamic()) { |
| ELFSegment* dyn_seg = elfSegmentTable().produce( |
| llvm::ELF::PT_DYNAMIC, llvm::ELF::PF_R | llvm::ELF::PF_W); |
| dyn_seg->append(&file_format->getDynamic()); |
| } |
| |
| if (config().options().hasRelro()) { |
| // make PT_GNU_RELRO |
| ELFSegment* relro_seg = elfSegmentTable().produce(llvm::ELF::PT_GNU_RELRO); |
| for (ELFSegmentFactory::iterator seg = elfSegmentTable().begin(), |
| segEnd = elfSegmentTable().end(); |
| seg != segEnd; |
| ++seg) { |
| if (llvm::ELF::PT_LOAD != (*seg)->type()) |
| continue; |
| |
| for (ELFSegment::iterator sect = (*seg)->begin(), sectEnd = (*seg)->end(); |
| sect != sectEnd; |
| ++sect) { |
| unsigned int order = getSectionOrder(**sect); |
| if (SHO_RELRO_LOCAL == order || SHO_RELRO == order || |
| SHO_RELRO_LAST == order) { |
| relro_seg->append(*sect); |
| } |
| } |
| } |
| } |
| |
| // make PT_GNU_EH_FRAME |
| if (file_format->hasEhFrameHdr()) { |
| ELFSegment* eh_seg = elfSegmentTable().produce(llvm::ELF::PT_GNU_EH_FRAME); |
| eh_seg->append(&file_format->getEhFrameHdr()); |
| } |
| |
| // make PT_TLS |
| if (file_format->hasTData() || file_format->hasTBSS()) { |
| ELFSegment* tls_seg = elfSegmentTable().produce(llvm::ELF::PT_TLS); |
| if (file_format->hasTData()) |
| tls_seg->append(&file_format->getTData()); |
| if (file_format->hasTBSS()) |
| tls_seg->append(&file_format->getTBSS()); |
| } |
| |
| // make PT_GNU_STACK |
| if (file_format->hasStackNote()) { |
| uint32_t flag = getSegmentFlag(file_format->getStackNote().flag()); |
| elfSegmentTable().produce(llvm::ELF::PT_GNU_STACK, |
| llvm::ELF::PF_R | llvm::ELF::PF_W | flag); |
| } |
| |
| // make PT_NOTE |
| ELFSegment* note_seg = NULL; |
| prev_flag = 0x0; |
| Module::iterator sect, sectBegin, sectEnd; |
| sectBegin = pModule.begin(); |
| sectEnd = pModule.end(); |
| for (sect = sectBegin; sect != sectEnd; ++sect) { |
| if ((*sect)->type() != llvm::ELF::SHT_NOTE || |
| ((*sect)->flag() & llvm::ELF::SHF_ALLOC) == 0) |
| continue; |
| |
| cur_flag = getSegmentFlag((*sect)->flag()); |
| // we have different section orders for read-only and writable notes, so |
| // create 2 segments if needed. |
| if (note_seg == NULL || |
| (cur_flag & llvm::ELF::PF_W) != (prev_flag & llvm::ELF::PF_W)) |
| note_seg = elfSegmentTable().produce(llvm::ELF::PT_NOTE, cur_flag); |
| |
| note_seg->append(*sect); |
| prev_flag = cur_flag; |
| } |
| |
| // create target dependent segments |
| doCreateProgramHdrs(pModule); |
| } |
| |
| /// setupProgramHdrs - set up the attributes of segments |
| void GNULDBackend::setupProgramHdrs(const LinkerScript& pScript) { |
| // update segment info |
| for (ELFSegmentFactory::iterator seg = elfSegmentTable().begin(), |
| segEnd = elfSegmentTable().end(); |
| seg != segEnd; |
| ++seg) { |
| // bypass if there is no section in this segment (e.g., PT_GNU_STACK) |
| if ((*seg)->size() == 0) |
| continue; |
| |
| // bypass the PT_LOAD that only has NULL section now |
| if ((*seg)->type() == llvm::ELF::PT_LOAD && |
| (*seg)->front()->kind() == LDFileFormat::Null && (*seg)->size() == 1) |
| continue; |
| |
| (*seg)->setOffset((*seg)->front()->offset()); |
| if ((*seg)->type() == llvm::ELF::PT_LOAD && |
| (*seg)->front()->kind() == LDFileFormat::Null) { |
| const LDSection* second = *((*seg)->begin() + 1); |
| assert(second != NULL); |
| (*seg)->setVaddr(second->addr() - second->offset()); |
| } else { |
| (*seg)->setVaddr((*seg)->front()->addr()); |
| } |
| (*seg)->setPaddr((*seg)->vaddr()); |
| |
| ELFSegment::reverse_iterator sect, sectREnd = (*seg)->rend(); |
| for (sect = (*seg)->rbegin(); sect != sectREnd; ++sect) { |
| if ((*sect)->kind() != LDFileFormat::BSS) |
| break; |
| } |
| if (sect != sectREnd) { |
| (*seg)->setFilesz((*sect)->offset() + (*sect)->size() - (*seg)->offset()); |
| } else { |
| (*seg)->setFilesz(0x0); |
| } |
| |
| (*seg)->setMemsz((*seg)->back()->addr() + (*seg)->back()->size() - |
| (*seg)->vaddr()); |
| } // end of for |
| |
| // handle the case if text segment only has NULL section |
| LDSection* null_sect = &getOutputFormat()->getNULLSection(); |
| ELFSegmentFactory::iterator null_seg = |
| elfSegmentTable().find(llvm::ELF::PT_LOAD, null_sect); |
| |
| if ((*null_seg)->size() == 1) { |
| // find 2nd PT_LOAD |
| ELFSegmentFactory::iterator seg, segEnd = elfSegmentTable().end(); |
| for (seg = null_seg + 1; seg != segEnd; ++seg) { |
| if ((*seg)->type() == llvm::ELF::PT_LOAD) |
| break; |
| } |
| if (seg != segEnd) { |
| uint64_t addr = (*seg)->front()->addr() - (*seg)->front()->offset(); |
| uint64_t size = sectionStartOffset(); |
| if (addr + size == (*seg)->front()->addr()) { |
| // if there is no space between the 2 segments, we can merge them. |
| (*seg)->setOffset(0x0); |
| (*seg)->setVaddr(addr); |
| (*seg)->setPaddr(addr); |
| |
| ELFSegment::iterator sect, sectEnd = (*seg)->end(); |
| for (sect = (*seg)->begin(); sect != sectEnd; ++sect) { |
| if ((*sect)->kind() == LDFileFormat::BSS) { |
| --sect; |
| break; |
| } |
| } |
| if (sect == sectEnd) { |
| (*seg)->setFilesz((*seg)->back()->offset() + (*seg)->back()->size() - |
| (*seg)->offset()); |
| } else if (*sect != (*seg)->front()) { |
| --sect; |
| (*seg)->setFilesz((*sect)->offset() + (*sect)->size() - |
| (*seg)->offset()); |
| } else { |
| (*seg)->setFilesz(0x0); |
| } |
| |
| (*seg)->setMemsz((*seg)->back()->addr() + (*seg)->back()->size() - |
| (*seg)->vaddr()); |
| |
| (*seg)->insert((*seg)->begin(), null_sect); |
| elfSegmentTable().erase(null_seg); |
| |
| } else if (addr + size < (*seg)->vaddr()) { |
| (*null_seg)->setOffset(0x0); |
| (*null_seg)->setVaddr(addr); |
| (*null_seg)->setPaddr(addr); |
| (*null_seg)->setFilesz(size); |
| (*null_seg)->setMemsz(size); |
| } else { |
| // erase the non valid segment contains NULL. |
| elfSegmentTable().erase(null_seg); |
| } |
| } |
| } |
| |
| // set up PT_PHDR |
| ELFSegmentFactory::iterator phdr = |
| elfSegmentTable().find(llvm::ELF::PT_PHDR, llvm::ELF::PF_R, 0x0); |
| |
| if (phdr != elfSegmentTable().end()) { |
| ELFSegmentFactory::iterator null_seg = |
| elfSegmentTable().find(llvm::ELF::PT_LOAD, null_sect); |
| if (null_seg != elfSegmentTable().end()) { |
| uint64_t offset = 0x0, phdr_size = 0x0; |
| if (config().targets().is32Bits()) { |
| offset = sizeof(llvm::ELF::Elf32_Ehdr); |
| phdr_size = sizeof(llvm::ELF::Elf32_Phdr); |
| } else { |
| offset = sizeof(llvm::ELF::Elf64_Ehdr); |
| phdr_size = sizeof(llvm::ELF::Elf64_Phdr); |
| } |
| (*phdr)->setOffset(offset); |
| (*phdr)->setVaddr((*null_seg)->vaddr() + offset); |
| (*phdr)->setPaddr((*phdr)->vaddr()); |
| (*phdr)->setFilesz(elfSegmentTable().size() * phdr_size); |
| (*phdr)->setMemsz(elfSegmentTable().size() * phdr_size); |
| (*phdr)->setAlign(config().targets().bitclass() / 8); |
| } else { |
| elfSegmentTable().erase(phdr); |
| } |
| } |
| } |
| |
| /// getSegmentFlag - give a section flag and return the corresponding segment |
| /// flag |
| uint32_t GNULDBackend::getSegmentFlag(const uint32_t pSectionFlag) { |
| uint32_t flag = 0x0; |
| if ((pSectionFlag & llvm::ELF::SHF_ALLOC) != 0x0) |
| flag |= llvm::ELF::PF_R; |
| if ((pSectionFlag & llvm::ELF::SHF_WRITE) != 0x0) |
| flag |= llvm::ELF::PF_W; |
| if ((pSectionFlag & llvm::ELF::SHF_EXECINSTR) != 0x0) |
| flag |= llvm::ELF::PF_X; |
| return flag; |
| } |
| |
| /// setupGNUStackInfo - setup the section flag of .note.GNU-stack in output |
| void GNULDBackend::setupGNUStackInfo(Module& pModule) { |
| uint32_t flag = 0x0; |
| if (config().options().hasStackSet()) { |
| // 1. check the command line option (-z execstack or -z noexecstack) |
| if (config().options().hasExecStack()) |
| flag = llvm::ELF::SHF_EXECINSTR; |
| } else { |
| // 2. check the stack info from the input objects |
| // FIXME: since we alway emit .note.GNU-stack in output now, we may be able |
| // to check this from the output .note.GNU-stack directly after section |
| // merging is done |
| size_t object_count = 0, stack_note_count = 0; |
| Module::const_obj_iterator obj, objEnd = pModule.obj_end(); |
| for (obj = pModule.obj_begin(); obj != objEnd; ++obj) { |
| ++object_count; |
| const LDSection* sect = (*obj)->context()->getSection(".note.GNU-stack"); |
| if (sect != NULL) { |
| ++stack_note_count; |
| // 2.1 found a stack note that is set as executable |
| if (0 != (llvm::ELF::SHF_EXECINSTR & sect->flag())) { |
| flag = llvm::ELF::SHF_EXECINSTR; |
| break; |
| } |
| } |
| } |
| |
| // 2.2 there are no stack note sections in all input objects |
| if (0 == stack_note_count) |
| return; |
| |
| // 2.3 a special case. Use the target default to decide if the stack should |
| // be executable |
| if (llvm::ELF::SHF_EXECINSTR != flag && object_count != stack_note_count) |
| if (m_pInfo->isDefaultExecStack()) |
| flag = llvm::ELF::SHF_EXECINSTR; |
| } |
| |
| if (getOutputFormat()->hasStackNote()) { |
| getOutputFormat()->getStackNote().setFlag(flag); |
| } |
| } |
| |
| /// setOutputSectionOffset - helper function to set output sections' offset. |
| void GNULDBackend::setOutputSectionOffset(Module& pModule) { |
| LinkerScript& script = pModule.getScript(); |
| uint64_t offset = 0x0; |
| LDSection* cur = NULL; |
| LDSection* prev = NULL; |
| SectionMap::iterator out, outBegin, outEnd; |
| outBegin = script.sectionMap().begin(); |
| outEnd = script.sectionMap().end(); |
| for (out = outBegin; out != outEnd; ++out, prev = cur) { |
| cur = (*out)->getSection(); |
| if (cur->kind() == LDFileFormat::Null) { |
| cur->setOffset(0x0); |
| continue; |
| } |
| |
| switch (prev->kind()) { |
| case LDFileFormat::Null: |
| offset = sectionStartOffset(); |
| break; |
| case LDFileFormat::BSS: |
| offset = prev->offset(); |
| break; |
| default: |
| offset = prev->offset() + prev->size(); |
| break; |
| } |
| alignAddress(offset, cur->align()); |
| cur->setOffset(offset); |
| } |
| } |
| |
| /// setOutputSectionAddress - helper function to set output sections' address. |
| void GNULDBackend::setOutputSectionAddress(Module& pModule) { |
| RpnEvaluator evaluator(pModule, *this); |
| LinkerScript& script = pModule.getScript(); |
| uint64_t vma = 0x0, offset = 0x0; |
| LDSection* cur = NULL; |
| LDSection* prev = NULL; |
| LinkerScript::AddressMap::iterator addr, addrEnd = script.addressMap().end(); |
| ELFSegmentFactory::iterator seg, segEnd = elfSegmentTable().end(); |
| SectionMap::Output::dot_iterator dot; |
| SectionMap::iterator out, outBegin, outEnd; |
| outBegin = script.sectionMap().begin(); |
| outEnd = script.sectionMap().end(); |
| for (out = outBegin; out != outEnd; prev = cur, ++out) { |
| cur = (*out)->getSection(); |
| |
| if (cur->kind() == LDFileFormat::Null) { |
| cur->setOffset(0x0); |
| continue; |
| } |
| |
| // process dot assignments between 2 output sections |
| for (SectionMap::Output::dot_iterator it = (*out)->dot_begin(), |
| ie = (*out)->dot_end(); |
| it != ie; |
| ++it) { |
| (*it).assign(evaluator); |
| } |
| |
| seg = elfSegmentTable().find(llvm::ELF::PT_LOAD, cur); |
| if (seg != segEnd && cur == (*seg)->front()) { |
| if ((*seg)->isBssSegment()) |
| addr = script.addressMap().find(".bss"); |
| else if ((*seg)->isDataSegment()) |
| addr = script.addressMap().find(".data"); |
| else |
| addr = script.addressMap().find(cur->name()); |
| } else |
| addr = addrEnd; |
| |
| if (addr != addrEnd) { |
| // use address mapping in script options |
| vma = addr.getEntry()->value(); |
| } else if ((*out)->prolog().hasVMA()) { |
| // use address from output section description |
| evaluator.eval((*out)->prolog().vma(), vma); |
| } else if ((dot = (*out)->find_last_explicit_dot()) != (*out)->dot_end()) { |
| // assign address based on `.' symbol in ldscript |
| vma = (*dot).symbol().value(); |
| alignAddress(vma, cur->align()); |
| } else { |
| if ((*out)->prolog().type() == OutputSectDesc::NOLOAD) { |
| vma = prev->addr() + prev->size(); |
| } else if ((cur->flag() & llvm::ELF::SHF_ALLOC) != 0) { |
| if (prev->kind() == LDFileFormat::Null) { |
| // Let SECTIONS starts at 0 if we have a default ldscript but don't |
| // have any initial value (VMA or `.'). |
| if (!config().options().getScriptList().empty()) |
| vma = 0x0; |
| else |
| vma = getSegmentStartAddr(script) + sectionStartOffset(); |
| } else { |
| if ((prev->kind() == LDFileFormat::BSS)) |
| vma = prev->addr(); |
| else |
| vma = prev->addr() + prev->size(); |
| } |
| alignAddress(vma, cur->align()); |
| if (config().options().getScriptList().empty()) { |
| if (seg != segEnd && cur == (*seg)->front()) { |
| // Try to align p_vaddr at page boundary if not in script options. |
| // To do so will add more padding in file, but can save one page |
| // at runtime. |
| // Avoid doing this optimization if -z relro is given, because there |
| // seems to be too many padding. |
| if (!config().options().hasRelro()) { |
| alignAddress(vma, (*seg)->align()); |
| } else { |
| vma += abiPageSize(); |
| } |
| } |
| } |
| } else { |
| vma = 0x0; |
| } |
| } |
| |
| if (config().options().hasRelro()) { |
| // if -z relro is given, we need to adjust sections' offset again, and |
| // let PT_GNU_RELRO end on a abi page boundary |
| |
| // check if current is the first non-relro section |
| SectionMap::iterator relro_last = out - 1; |
| if (relro_last != outEnd && (*relro_last)->order() <= SHO_RELRO_LAST && |
| (*out)->order() > SHO_RELRO_LAST) { |
| // align the first non-relro section to page boundary |
| alignAddress(vma, abiPageSize()); |
| |
| // It seems that compiler think .got and .got.plt are continuous (w/o |
| // any padding between). If .got is the last section in PT_RELRO and |
| // it's not continuous to its next section (i.e. .got.plt), we need to |
| // add padding in front of .got instead. |
| // FIXME: Maybe we can handle this in a more general way. |
| LDSection& got = getOutputFormat()->getGOT(); |
| if ((getSectionOrder(got) == SHO_RELRO_LAST) && |
| (got.addr() + got.size() < vma)) { |
| uint64_t diff = vma - got.addr() - got.size(); |
| got.setAddr(vma - got.size()); |
| got.setOffset(got.offset() + diff); |
| } |
| } |
| } // end of if - for relro processing |
| |
| cur->setAddr(vma); |
| |
| switch (prev->kind()) { |
| case LDFileFormat::Null: |
| offset = sectionStartOffset(); |
| break; |
| case LDFileFormat::BSS: |
| offset = prev->offset(); |
| break; |
| default: |
| offset = prev->offset() + prev->size(); |
| break; |
| } |
| alignAddress(offset, cur->align()); |
| // in p75, http://www.sco.com/developers/devspecs/gabi41.pdf |
| // p_align: As "Program Loading" describes in this chapter of the |
| // processor supplement, loadable process segments must have congruent |
| // values for p_vaddr and p_offset, modulo the page size. |
| // FIXME: Now make all sh_addr and sh_offset are congruent, modulo the page |
| // size. Otherwise, old objcopy (e.g., binutils 2.17) may fail with our |
| // output! |
| if ((cur->flag() & llvm::ELF::SHF_ALLOC) != 0 && |
| (vma & (abiPageSize() - 1)) != (offset & (abiPageSize() - 1))) { |
| uint64_t padding = abiPageSize() + (vma & (abiPageSize() - 1)) - |
| (offset & (abiPageSize() - 1)); |
| offset += padding; |
| } |
| |
| cur->setOffset(offset); |
| |
| // process dot assignments in the output section |
| bool changed = false; |
| Fragment* invalid = NULL; |
| for (SectionMap::Output::iterator in = (*out)->begin(), |
| inEnd = (*out)->end(); |
| in != inEnd; |
| ++in) { |
| if (invalid != NULL && !(*in)->dotAssignments().empty()) { |
| while (invalid != (*in)->dotAssignments().front().first) { |
| Fragment* prev = invalid->getPrevNode(); |
| invalid->setOffset(prev->getOffset() + prev->size()); |
| invalid = invalid->getNextNode(); |
| } |
| invalid = NULL; |
| } |
| |
| for (SectionMap::Input::dot_iterator it = (*in)->dot_begin(), |
| ie = (*in)->dot_end(); |
| it != ie; |
| ++it) { |
| (*it).second.assign(evaluator); |
| if ((*it).first != NULL) { |
| uint64_t new_offset = (*it).second.symbol().value() - vma; |
| if (new_offset != (*it).first->getOffset()) { |
| (*it).first->setOffset(new_offset); |
| invalid = (*it).first->getNextNode(); |
| changed = true; |
| } |
| } |
| } // for each dot assignment |
| } // for each input description |
| |
| if (changed) { |
| while (invalid != NULL) { |
| Fragment* prev = invalid->getPrevNode(); |
| invalid->setOffset(prev->getOffset() + prev->size()); |
| invalid = invalid->getNextNode(); |
| } |
| |
| cur->setSize(cur->getSectionData()->back().getOffset() + |
| cur->getSectionData()->back().size()); |
| } |
| } // for each output section description |
| } |
| |
| /// placeOutputSections - place output sections based on SectionMap |
| void GNULDBackend::placeOutputSections(Module& pModule) { |
| typedef std::vector<LDSection*> Orphans; |
| Orphans orphans; |
| SectionMap& sectionMap = pModule.getScript().sectionMap(); |
| |
| for (Module::iterator it = pModule.begin(), ie = pModule.end(); it != ie; |
| ++it) { |
| bool wanted = false; |
| |
| switch ((*it)->kind()) { |
| // take NULL and StackNote directly |
| case LDFileFormat::Null: |
| case LDFileFormat::StackNote: |
| wanted = true; |
| break; |
| // ignore if section size is 0 |
| case LDFileFormat::EhFrame: |
| if (((*it)->size() != 0) || |
| ((*it)->hasEhFrame() && |
| config().codeGenType() == LinkerConfig::Object)) |
| wanted = true; |
| break; |
| case LDFileFormat::Relocation: |
| if (((*it)->size() != 0) || |
| ((*it)->hasRelocData() && |
| config().codeGenType() == LinkerConfig::Object)) |
| wanted = true; |
| break; |
| case LDFileFormat::TEXT: |
| case LDFileFormat::DATA: |
| case LDFileFormat::Target: |
| case LDFileFormat::MetaData: |
| case LDFileFormat::BSS: |
| case LDFileFormat::Debug: |
| case LDFileFormat::DebugString: |
| case LDFileFormat::GCCExceptTable: |
| case LDFileFormat::Note: |
| case LDFileFormat::NamePool: |
| case LDFileFormat::EhFrameHdr: |
| if (((*it)->size() != 0) || |
| ((*it)->hasSectionData() && |
| config().codeGenType() == LinkerConfig::Object)) |
| wanted = true; |
| break; |
| case LDFileFormat::Group: |
| if (LinkerConfig::Object == config().codeGenType()) { |
| // TODO: support incremental linking |
| } |
| break; |
| case LDFileFormat::Version: |
| if ((*it)->size() != 0) { |
| wanted = true; |
| warning(diag::warn_unsupported_symbolic_versioning) << (*it)->name(); |
| } |
| break; |
| default: |
| if ((*it)->size() != 0) { |
| error(diag::err_unsupported_section) << (*it)->name() |
| << (*it)->kind(); |
| } |
| break; |
| } // end of switch |
| |
| if (wanted) { |
| SectionMap::iterator out, outBegin, outEnd; |
| outBegin = sectionMap.begin(); |
| outEnd = sectionMap.end(); |
| for (out = outBegin; out != outEnd; ++out) { |
| bool matched = false; |
| if ((*it)->name().compare((*out)->name()) == 0) { |
| switch ((*out)->prolog().constraint()) { |
| case OutputSectDesc::NO_CONSTRAINT: |
| matched = true; |
| break; |
| case OutputSectDesc::ONLY_IF_RO: |
| matched = ((*it)->flag() & llvm::ELF::SHF_WRITE) == 0; |
| break; |
| case OutputSectDesc::ONLY_IF_RW: |
| matched = ((*it)->flag() & llvm::ELF::SHF_WRITE) != 0; |
| break; |
| } // end of switch |
| |
| if (matched) |
| break; |
| } |
| } // for each output section description |
| |
| if (out != outEnd) { |
| // set up the section |
| (*out)->setSection(*it); |
| (*out)->setOrder(getSectionOrder(**it)); |
| } else { |
| orphans.push_back(*it); |
| } |
| } |
| } // for each section in Module |
| |
| // set up sections in SectionMap but do not exist at all. |
| uint32_t flag = 0x0; |
| unsigned int order = SHO_UNDEFINED; |
| OutputSectDesc::Type type = OutputSectDesc::LOAD; |
| for (SectionMap::reverse_iterator out = sectionMap.rbegin(), |
| outEnd = sectionMap.rend(); |
| out != outEnd; |
| ++out) { |
| if ((*out)->hasContent() || |
| (*out)->getSection()->kind() == LDFileFormat::Null || |
| (*out)->getSection()->kind() == LDFileFormat::StackNote) { |
| flag = (*out)->getSection()->flag(); |
| order = (*out)->order(); |
| type = (*out)->prolog().type(); |
| } else { |
| (*out)->getSection()->setFlag(flag); |
| (*out)->setOrder(order); |
| (*out)->prolog().setType(type); |
| } |
| } // for each output section description |
| |
| // place orphan sections |
| for (Orphans::iterator it = orphans.begin(), ie = orphans.end(); it != ie; |
| ++it) { |
| size_t order = getSectionOrder(**it); |
| SectionMap::iterator out, outBegin, outEnd; |
| outBegin = sectionMap.begin(); |
| outEnd = sectionMap.end(); |
| |
| if ((*it)->kind() == LDFileFormat::Null) |
| out = sectionMap.insert(outBegin, *it); |
| else { |
| for (out = outBegin; out != outEnd; ++out) { |
| if ((*out)->order() > order) |
| break; |
| } |
| out = sectionMap.insert(out, *it); |
| } |
| (*out)->setOrder(order); |
| } // for each orphan section |
| |
| // sort output section orders if there is no default ldscript |
| if (config().options().getScriptList().empty()) { |
| std::stable_sort( |
| sectionMap.begin(), sectionMap.end(), SectionMap::SHOCompare()); |
| } |
| |
| // when section ordering is fixed, now we can make sure dot assignments are |
| // all set appropriately |
| sectionMap.fixupDotSymbols(); |
| } |
| |
| /// layout - layout method |
| void GNULDBackend::layout(Module& pModule) { |
| // 1. place output sections based on SectionMap from SECTIONS command |
| placeOutputSections(pModule); |
| |
| // 2. update output sections in Module |
| SectionMap& sectionMap = pModule.getScript().sectionMap(); |
| pModule.getSectionTable().clear(); |
| for (SectionMap::iterator out = sectionMap.begin(), outEnd = sectionMap.end(); |
| out != outEnd; |
| ++out) { |
| if ((*out)->hasContent() || |
| (*out)->getSection()->kind() == LDFileFormat::Null || |
| (*out)->getSection()->kind() == LDFileFormat::StackNote || |
| config().codeGenType() == LinkerConfig::Object) { |
| (*out)->getSection()->setIndex(pModule.size()); |
| pModule.getSectionTable().push_back((*out)->getSection()); |
| } |
| } // for each output section description |
| |
| // 3. update the size of .shstrtab |
| sizeShstrtab(pModule); |
| |
| // 4. create program headers |
| if (LinkerConfig::Object != config().codeGenType()) { |
| createProgramHdrs(pModule); |
| } |
| |
| // 5. set output section address/offset |
| if (LinkerConfig::Object != config().codeGenType()) |
| setOutputSectionAddress(pModule); |
| else |
| setOutputSectionOffset(pModule); |
| } |
| |
| void GNULDBackend::createAndSizeEhFrameHdr(Module& pModule) { |
| if (LinkerConfig::Object != config().codeGenType() && |
| config().options().hasEhFrameHdr() && getOutputFormat()->hasEhFrame()) { |
| // init EhFrameHdr and size the output section |
| ELFFileFormat* format = getOutputFormat(); |
| m_pEhFrameHdr = |
| new EhFrameHdr(format->getEhFrameHdr(), format->getEhFrame()); |
| m_pEhFrameHdr->sizeOutput(); |
| } |
| } |
| |
| /// mayHaveUnsafeFunctionPointerAccess - check if the section may have unsafe |
| /// function pointer access |
| bool GNULDBackend::mayHaveUnsafeFunctionPointerAccess( |
| const LDSection& pSection) const { |
| llvm::StringRef name(pSection.name()); |
| return !name.startswith(".rodata._ZTV") && |
| !name.startswith(".data.rel.ro._ZTV") && |
| !name.startswith(".rodata._ZTC") && |
| !name.startswith(".data.rel.ro._ZTC") && !name.startswith(".eh_frame"); |
| } |
| |
| /// preLayout - Backend can do any needed modification before layout |
| void GNULDBackend::preLayout(Module& pModule, IRBuilder& pBuilder) { |
| // prelayout target first |
| doPreLayout(pBuilder); |
| |
| // change .tbss and .tdata section symbol from Local to LocalDyn category |
| if (f_pTDATA != NULL) |
| pModule.getSymbolTable().changeToDynamic(*f_pTDATA); |
| |
| if (f_pTBSS != NULL) |
| pModule.getSymbolTable().changeToDynamic(*f_pTBSS); |
| |
| // To merge input's relocation sections into output's relocation sections. |
| // |
| // If we are generating relocatables (-r), move input relocation sections |
| // to corresponding output relocation sections. |
| if (LinkerConfig::Object == config().codeGenType()) { |
| 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) { |
| // get the output relocation LDSection with identical name. |
| LDSection* output_sect = pModule.getSection((*rs)->name()); |
| if (output_sect == NULL) { |
| output_sect = LDSection::Create( |
| (*rs)->name(), (*rs)->kind(), (*rs)->type(), (*rs)->flag()); |
| |
| output_sect->setAlign((*rs)->align()); |
| pModule.getSectionTable().push_back(output_sect); |
| } |
| |
| // set output relocation section link |
| const LDSection* input_link = (*rs)->getLink(); |
| assert(input_link != NULL && "Illegal input relocation section."); |
| |
| // get the linked output section |
| LDSection* output_link = pModule.getSection(input_link->name()); |
| assert(output_link != NULL); |
| |
| output_sect->setLink(output_link); |
| |
| // get output relcoationData, create one if not exist |
| if (!output_sect->hasRelocData()) |
| IRBuilder::CreateRelocData(*output_sect); |
| |
| RelocData* out_reloc_data = output_sect->getRelocData(); |
| |
| // move relocations from input's to output's RelcoationData |
| RelocData::RelocationListType& out_list = |
| out_reloc_data->getRelocationList(); |
| RelocData::RelocationListType& in_list = |
| (*rs)->getRelocData()->getRelocationList(); |
| out_list.splice(out_list.end(), in_list); |
| |
| // size output |
| if (llvm::ELF::SHT_REL == output_sect->type()) |
| output_sect->setSize(out_reloc_data->size() * getRelEntrySize()); |
| else if (llvm::ELF::SHT_RELA == output_sect->type()) |
| output_sect->setSize(out_reloc_data->size() * getRelaEntrySize()); |
| else { |
| fatal(diag::unknown_reloc_section_type) << output_sect->type() |
| << output_sect->name(); |
| } |
| } // end of for each relocation section |
| } // end of for each input |
| } // end of if |
| |
| // set up the section flag of .note.GNU-stack section |
| setupGNUStackInfo(pModule); |
| } |
| |
| /// postLayout - Backend can do any needed modification after layout |
| void GNULDBackend::postLayout(Module& pModule, IRBuilder& pBuilder) { |
| if (LinkerConfig::Object != config().codeGenType()) { |
| // do relaxation |
| relax(pModule, pBuilder); |
| // set up the attributes of program headers |
| setupProgramHdrs(pModule.getScript()); |
| } |
| |
| doPostLayout(pModule, pBuilder); |
| } |
| |
| void GNULDBackend::postProcessing(FileOutputBuffer& pOutput) { |
| if (LinkerConfig::Object != config().codeGenType() && |
| config().options().hasEhFrameHdr() && getOutputFormat()->hasEhFrame()) { |
| // emit eh_frame_hdr |
| m_pEhFrameHdr->emitOutput<32>(pOutput); |
| } |
| } |
| |
| /// getHashBucketCount - calculate hash bucket count. |
| unsigned GNULDBackend::getHashBucketCount(unsigned pNumOfSymbols, |
| bool pIsGNUStyle) { |
| static const unsigned int buckets[] = { |
| 1, 3, 17, 37, 67, 97, 131, 197, 263, 521, 1031, 2053, 4099, 8209, 16411, |
| 32771, 65537, 131101, 262147 |
| }; |
| const unsigned buckets_count = sizeof buckets / sizeof buckets[0]; |
| |
| unsigned int result = 1; |
| for (unsigned i = 0; i < buckets_count; ++i) { |
| if (pNumOfSymbols < buckets[i]) |
| break; |
| result = buckets[i]; |
| } |
| |
| if (pIsGNUStyle && result < 2) |
| result = 2; |
| |
| return result; |
| } |
| |
| /// getGNUHashMaskbitslog2 - calculate the number of mask bits in log2 |
| unsigned GNULDBackend::getGNUHashMaskbitslog2(unsigned pNumOfSymbols) const { |
| uint32_t maskbitslog2 = 1; |
| for (uint32_t x = pNumOfSymbols >> 1; x != 0; x >>= 1) |
| ++maskbitslog2; |
| |
| if (maskbitslog2 < 3) |
| maskbitslog2 = 5; |
| else if (((1U << (maskbitslog2 - 2)) & pNumOfSymbols) != 0) |
| maskbitslog2 += 3; |
| else |
| maskbitslog2 += 2; |
| |
| if (config().targets().bitclass() == 64 && maskbitslog2 == 5) |
| maskbitslog2 = 6; |
| |
| return maskbitslog2; |
| } |
| |
| /// isDynamicSymbol |
| bool GNULDBackend::isDynamicSymbol(const LDSymbol& pSymbol) const { |
| // If a local symbol is in the LDContext's symbol table, it's a real local |
| // symbol. We should not add it |
| if (pSymbol.binding() == ResolveInfo::Local) |
| return false; |
| |
| // If we are building shared object, and the visibility is external, we |
| // need to add it. |
| if (LinkerConfig::DynObj == config().codeGenType() || |
| LinkerConfig::Exec == config().codeGenType() || |
| LinkerConfig::Binary == config().codeGenType()) { |
| if (pSymbol.resolveInfo()->visibility() == ResolveInfo::Default || |
| pSymbol.resolveInfo()->visibility() == ResolveInfo::Protected) |
| return true; |
| } |
| return false; |
| } |
| |
| /// isDynamicSymbol |
| bool GNULDBackend::isDynamicSymbol(const ResolveInfo& pResolveInfo) const { |
| // If a local symbol is in the LDContext's symbol table, it's a real local |
| // symbol. We should not add it |
| if (pResolveInfo.binding() == ResolveInfo::Local) |
| return false; |
| |
| // If we are building shared object, and the visibility is external, we |
| // need to add it. |
| if (LinkerConfig::DynObj == config().codeGenType() || |
| LinkerConfig::Exec == config().codeGenType() || |
| LinkerConfig::Binary == config().codeGenType()) { |
| if (pResolveInfo.visibility() == ResolveInfo::Default || |
| pResolveInfo.visibility() == ResolveInfo::Protected) |
| return true; |
| } |
| return false; |
| } |
| |
| /// elfSegmentTable - return the reference of the elf segment table |
| ELFSegmentFactory& GNULDBackend::elfSegmentTable() { |
| assert(m_pELFSegmentTable != NULL && "Do not create ELFSegmentTable!"); |
| return *m_pELFSegmentTable; |
| } |
| |
| /// elfSegmentTable - return the reference of the elf segment table |
| const ELFSegmentFactory& GNULDBackend::elfSegmentTable() const { |
| assert(m_pELFSegmentTable != NULL && "Do not create ELFSegmentTable!"); |
| return *m_pELFSegmentTable; |
| } |
| |
| /// commonPageSize - the common page size of the target machine. |
| uint64_t GNULDBackend::commonPageSize() const { |
| if (config().options().commPageSize() > 0) |
| return std::min(config().options().commPageSize(), abiPageSize()); |
| else |
| return std::min(m_pInfo->commonPageSize(), abiPageSize()); |
| } |
| |
| /// abiPageSize - the abi page size of the target machine. |
| uint64_t GNULDBackend::abiPageSize() const { |
| if (config().options().maxPageSize() > 0) |
| return config().options().maxPageSize(); |
| else |
| return m_pInfo->abiPageSize(); |
| } |
| |
| /// isSymbolPreemtible - whether the symbol can be preemted by other |
| /// link unit |
| bool GNULDBackend::isSymbolPreemptible(const ResolveInfo& pSym) const { |
| if (pSym.other() != ResolveInfo::Default) |
| return false; |
| |
| // This is because the codeGenType of pie is DynObj. And gold linker check |
| // the "shared" option instead. |
| if (config().options().isPIE()) |
| return false; |
| |
| if (LinkerConfig::DynObj != config().codeGenType()) |
| return false; |
| |
| if (config().options().Bsymbolic()) |
| return false; |
| |
| // A local defined symbol should be non-preemptible. |
| // This issue is found when linking libstdc++ on freebsd. A R_386_GOT32 |
| // relocation refers to a local defined symbol, and we should generate a |
| // relative dynamic relocation when applying the relocation. |
| if (pSym.isDefine() && pSym.binding() == ResolveInfo::Local) |
| return false; |
| |
| return true; |
| } |
| |
| /// symbolNeedsDynRel - return whether the symbol needs a dynamic relocation |
| bool GNULDBackend::symbolNeedsDynRel(const ResolveInfo& pSym, |
| bool pSymHasPLT, |
| bool isAbsReloc) const { |
| // an undefined reference in the executables should be statically |
| // resolved to 0 and no need a dynamic relocation |
| if (pSym.isUndef() && !pSym.isDyn() && |
| (LinkerConfig::Exec == config().codeGenType() || |
| LinkerConfig::Binary == config().codeGenType())) |
| return false; |
| |
| // An absolute symbol can be resolved directly if it is either local |
| // or we are linking statically. Otherwise it can still be overridden |
| // at runtime. |
| if (pSym.isAbsolute() && |
| (pSym.binding() == ResolveInfo::Local || config().isCodeStatic())) |
| return false; |
| if (config().isCodeIndep() && isAbsReloc) |
| return true; |
| if (pSymHasPLT && ResolveInfo::Function == pSym.type()) |
| return false; |
| if (!config().isCodeIndep() && pSymHasPLT) |
| return false; |
| if (pSym.isDyn() || pSym.isUndef() || isSymbolPreemptible(pSym)) |
| return true; |
| |
| return false; |
| } |
| |
| /// symbolNeedsPLT - return whether the symbol needs a PLT entry |
| bool GNULDBackend::symbolNeedsPLT(const ResolveInfo& pSym) const { |
| if (pSym.isUndef() && !pSym.isDyn() && |
| LinkerConfig::DynObj != config().codeGenType()) |
| return false; |
| |
| // An IndirectFunc symbol (i.e., STT_GNU_IFUNC) always needs a plt entry |
| if (pSym.type() == ResolveInfo::IndirectFunc) |
| return true; |
| |
| if (pSym.type() != ResolveInfo::Function) |
| return false; |
| |
| if (config().isCodeStatic()) |
| return false; |
| |
| if (config().options().isPIE()) |
| return false; |
| |
| return (pSym.isDyn() || pSym.isUndef() || isSymbolPreemptible(pSym)); |
| } |
| |
| /// symbolHasFinalValue - return true if the symbol's value can be decided at |
| /// link time |
| bool GNULDBackend::symbolFinalValueIsKnown(const ResolveInfo& pSym) const { |
| // if the output is pic code or if not executables, symbols' value may change |
| // at runtime |
| // FIXME: CodeIndep() || LinkerConfig::Relocatable == CodeGenType |
| if (config().isCodeIndep() || |
| (LinkerConfig::Exec != config().codeGenType() && |
| LinkerConfig::Binary != config().codeGenType())) |
| return false; |
| |
| // if the symbol is from dynamic object, then its value is unknown |
| if (pSym.isDyn()) |
| return false; |
| |
| // if the symbol is not in dynamic object and is not undefined, then its value |
| // is known |
| if (!pSym.isUndef()) |
| return true; |
| |
| // if the symbol is undefined and not in dynamic objects, for example, a weak |
| // undefined symbol, then whether the symbol's final value can be known |
| // depends on whrther we're doing static link |
| return config().isCodeStatic(); |
| } |
| |
| /// symbolNeedsCopyReloc - return whether the symbol needs a copy relocation |
| bool GNULDBackend::symbolNeedsCopyReloc(const Relocation& pReloc, |
| const ResolveInfo& pSym) const { |
| // only the reference from dynamic executable to non-function symbol in |
| // the dynamic objects may need copy relocation |
| if (config().isCodeIndep() || !pSym.isDyn() || |
| pSym.type() == ResolveInfo::Function || pSym.size() == 0) |
| return false; |
| |
| // check if the option -z nocopyreloc is given |
| if (config().options().hasNoCopyReloc()) |
| return false; |
| |
| // TODO: Is this check necessary? |
| // if relocation target place is readonly, a copy relocation is needed |
| uint32_t flag = pReloc.targetRef().frag()->getParent()->getSection().flag(); |
| if (0 == (flag & llvm::ELF::SHF_WRITE)) |
| return true; |
| |
| return false; |
| } |
| |
| LDSymbol& GNULDBackend::getTDATASymbol() { |
| assert(f_pTDATA != NULL); |
| return *f_pTDATA; |
| } |
| |
| const LDSymbol& GNULDBackend::getTDATASymbol() const { |
| assert(f_pTDATA != NULL); |
| return *f_pTDATA; |
| } |
| |
| LDSymbol& GNULDBackend::getTBSSSymbol() { |
| assert(f_pTBSS != NULL); |
| return *f_pTBSS; |
| } |
| |
| const LDSymbol& GNULDBackend::getTBSSSymbol() const { |
| assert(f_pTBSS != NULL); |
| return *f_pTBSS; |
| } |
| |
| llvm::StringRef GNULDBackend::getEntry(const Module& pModule) const { |
| if (pModule.getScript().hasEntry()) |
| return pModule.getScript().entry(); |
| else |
| return getInfo().entry(); |
| } |
| |
| void GNULDBackend::checkAndSetHasTextRel(const LDSection& pSection) { |
| if (m_bHasTextRel) |
| return; |
| |
| // if the target section of the dynamic relocation is ALLOCATE but is not |
| // writable, than we should set DF_TEXTREL |
| const uint32_t flag = pSection.flag(); |
| if (0 == (flag & llvm::ELF::SHF_WRITE) && (flag & llvm::ELF::SHF_ALLOC)) |
| m_bHasTextRel = true; |
| |
| return; |
| } |
| |
| /// sortRelocation - sort the dynamic relocations to let dynamic linker |
| /// process relocations more efficiently |
| void GNULDBackend::sortRelocation(LDSection& pSection) { |
| if (!config().options().hasCombReloc()) |
| return; |
| |
| assert(pSection.kind() == LDFileFormat::Relocation); |
| |
| switch (config().codeGenType()) { |
| case LinkerConfig::DynObj: |
| case LinkerConfig::Exec: |
| if (&pSection == &getOutputFormat()->getRelDyn() || |
| &pSection == &getOutputFormat()->getRelaDyn()) { |
| if (pSection.hasRelocData()) |
| pSection.getRelocData()->sort(RelocCompare(*this)); |
| } |
| default: |
| return; |
| } |
| } |
| |
| unsigned GNULDBackend::stubGroupSize() const { |
| const unsigned group_size = config().targets().getStubGroupSize(); |
| if (group_size == 0) { |
| return m_pInfo->stubGroupSize(); |
| } else { |
| return group_size; |
| } |
| } |
| |
| /// initBRIslandFactory - initialize the branch island factory for relaxation |
| bool GNULDBackend::initBRIslandFactory() { |
| if (m_pBRIslandFactory == NULL) { |
| m_pBRIslandFactory = new BranchIslandFactory(maxFwdBranchOffset(), |
| maxBwdBranchOffset(), |
| stubGroupSize()); |
| } |
| return true; |
| } |
| |
| /// initStubFactory - initialize the stub factory for relaxation |
| bool GNULDBackend::initStubFactory() { |
| if (m_pStubFactory == NULL) { |
| m_pStubFactory = new StubFactory(); |
| } |
| return true; |
| } |
| |
| bool GNULDBackend::relax(Module& pModule, IRBuilder& pBuilder) { |
| if (!mayRelax()) |
| return true; |
| |
| getBRIslandFactory()->group(pModule); |
| |
| bool finished = true; |
| do { |
| if (doRelax(pModule, pBuilder, finished)) { |
| setOutputSectionAddress(pModule); |
| } |
| } while (!finished); |
| |
| return true; |
| } |
| |
| bool GNULDBackend::DynsymCompare::needGNUHash(const LDSymbol& X) const { |
| // FIXME: in bfd and gold linker, an undefined symbol might be hashed |
| // when the ouput is not PIC, if the symbol is referred by a non pc-relative |
| // reloc, and its value is set to the addr of the plt entry. |
| return !X.resolveInfo()->isUndef() && !X.isDyn(); |
| } |
| |
| bool GNULDBackend::DynsymCompare::operator()(const LDSymbol* X, |
| const LDSymbol* Y) const { |
| return !needGNUHash(*X) && needGNUHash(*Y); |
| } |
| |
| bool GNULDBackend::RelocCompare::operator()(const Relocation& X, |
| const Relocation& Y) const { |
| // 1. compare if relocation is relative |
| if (X.symInfo() == NULL) { |
| if (Y.symInfo() != NULL) |
| return true; |
| } else if (Y.symInfo() == NULL) { |
| return false; |
| } else { |
| // 2. compare the symbol index |
| size_t symIdxX = m_Backend.getSymbolIdx(X.symInfo()->outSymbol()); |
| size_t symIdxY = m_Backend.getSymbolIdx(Y.symInfo()->outSymbol()); |
| if (symIdxX < symIdxY) |
| return true; |
| if (symIdxX > symIdxY) |
| return false; |
| } |
| |
| // 3. compare the relocation address |
| if (X.place() < Y.place()) |
| return true; |
| if (X.place() > Y.place()) |
| return false; |
| |
| // 4. compare the relocation type |
| if (X.type() < Y.type()) |
| return true; |
| if (X.type() > Y.type()) |
| return false; |
| |
| // 5. compare the addend |
| if (X.addend() < Y.addend()) |
| return true; |
| if (X.addend() > Y.addend()) |
| return false; |
| |
| return false; |
| } |
| |
| } // namespace mcld |