//===- 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 #include #include #include #include #include #include #include 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( 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( 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( "__preinit_array_start", ResolveInfo::NoType, ResolveInfo::Define, ResolveInfo::Global, 0x0, // size 0x0, // value preinit_array, // FragRef ResolveInfo::Hidden); f_pPreInitArrayEnd = pBuilder.AddSymbol( "__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( "__init_array_start", ResolveInfo::NoType, ResolveInfo::Define, ResolveInfo::Global, 0x0, // size 0x0, // value init_array, // FragRef ResolveInfo::Hidden); f_pInitArrayEnd = pBuilder.AddSymbol( "__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( "__fini_array_start", ResolveInfo::NoType, ResolveInfo::Define, ResolveInfo::Global, 0x0, // size 0x0, // value fini_array, // FragRef ResolveInfo::Hidden); f_pFiniArrayEnd = pBuilder.AddSymbol( "__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( "__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( "_DYNAMIC", ResolveInfo::Object, ResolveInfo::Define, ResolveInfo::Local, 0x0, // size 0x0, // value FragmentRef::Null(), // FragRef ResolveInfo::Hidden); // ----- segment symbols ----- // f_pExecutableStart = pBuilder.AddSymbol( "__executable_start", ResolveInfo::NoType, ResolveInfo::Define, ResolveInfo::Absolute, 0x0, // size 0x0, // value FragmentRef::Null(), // FragRef ResolveInfo::Default); f_pEText = pBuilder.AddSymbol( "etext", ResolveInfo::NoType, ResolveInfo::Define, ResolveInfo::Absolute, 0x0, // size 0x0, // value FragmentRef::Null(), // FragRef ResolveInfo::Default); f_p_EText = pBuilder.AddSymbol( "_etext", ResolveInfo::NoType, ResolveInfo::Define, ResolveInfo::Absolute, 0x0, // size 0x0, // value FragmentRef::Null(), // FragRef ResolveInfo::Default); f_p__EText = pBuilder.AddSymbol( "__etext", ResolveInfo::NoType, ResolveInfo::Define, ResolveInfo::Absolute, 0x0, // size 0x0, // value FragmentRef::Null(), // FragRef ResolveInfo::Default); f_pEData = pBuilder.AddSymbol( "edata", ResolveInfo::NoType, ResolveInfo::Define, ResolveInfo::Absolute, 0x0, // size 0x0, // value FragmentRef::Null(), // FragRef ResolveInfo::Default); f_pEnd = pBuilder.AddSymbol( "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( "_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( "__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( "_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(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(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(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(bucket), 0, nbucket); hash::StringHash 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(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(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(bitmask); *maskval = 0; // no valid hashes } else { // must be 64 uint64_t* maskval = reinterpret_cast(bitmask); *maskval = 0; // no valid hashes } bucket = reinterpret_cast(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(bitmask + maskbits / 8); chain = (bucket + nbucket); // build the gnu style hash table typedef std::multimap > SymMapType; SymMapType symmap; symEnd = pSymtab.dynamicEnd(); for (symbol = pSymtab.localDynBegin() + symidx - 1; symbol != symEnd; ++symbol) { hash::StringHash 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 bitmasks(maskwords); size_t hashedidx = symidx; for (size_t idx = 0; idx < nbucket; ++idx) { size_t count = 0; std::pair 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(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(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(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(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(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(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(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 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