//===- GNULDBackend.cpp ---------------------------------------------------===// // // The MCLinker Project // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include <llvm/Support/ELF.h> #include <mcld/ADT/SizeTraits.h> #include <mcld/Target/GNULDBackend.h> #include <mcld/MC/MCLDInfo.h> #include <mcld/MC/MCLDOutput.h> #include <mcld/MC/MCLDInputTree.h> #include <mcld/MC/SymbolCategory.h> #include <mcld/LD/LDSymbol.h> #include <mcld/LD/Layout.h> #include <mcld/Support/MemoryArea.h> #include <mcld/Support/MemoryRegion.h> #include <string> #include <cstring> #include <cassert> using namespace mcld; //===----------------------------------------------------------------------===// // GNULDBackend GNULDBackend::GNULDBackend() : m_pArchiveReader(0), m_pObjectReader(0), m_pDynObjReader(0), m_pObjectWriter(0), m_pDynObjWriter(0), m_pDynObjFileFormat(0), m_pExecFileFormat(0), m_ELFSegmentTable(9)// magic number { m_pSymIndexMap = new HashTableType(1024); } GNULDBackend::~GNULDBackend() { if (m_pArchiveReader) delete m_pArchiveReader; if (m_pObjectReader) delete m_pObjectReader; if (m_pDynObjReader) delete m_pDynObjReader; if (m_pObjectWriter) delete m_pObjectWriter; if (m_pDynObjWriter) delete m_pDynObjWriter; if (m_pDynObjFileFormat) delete m_pDynObjFileFormat; if (m_pExecFileFormat) delete m_pExecFileFormat; if(m_pSymIndexMap) delete m_pSymIndexMap; } size_t GNULDBackend::sectionStartOffset() const { // FIXME: use fixed offset, we need 10 segments by default return sizeof(llvm::ELF::Elf64_Ehdr)+10*sizeof(llvm::ELF::Elf64_Phdr); } bool GNULDBackend::initArchiveReader(MCLinker&, MCLDInfo &pInfo) { if (0 == m_pArchiveReader) { LDReader::Endian isLittleEndian = LDReader::LittleEndian; m_pArchiveReader = new GNUArchiveReader(pInfo, isLittleEndian); } return true; } bool GNULDBackend::initObjectReader(MCLinker& pLinker) { if (0 == m_pObjectReader) m_pObjectReader = new ELFObjectReader(*this, pLinker); return true; } bool GNULDBackend::initDynObjReader(MCLinker& pLinker) { if (0 == m_pDynObjReader) m_pDynObjReader = new ELFDynObjReader(*this, pLinker); return true; } bool GNULDBackend::initObjectWriter(MCLinker&) { // TODO return true; } bool GNULDBackend::initDynObjWriter(MCLinker& pLinker) { if (0 == m_pDynObjWriter) m_pDynObjWriter = new ELFDynObjWriter(*this, pLinker); return true; } bool GNULDBackend::initExecSections(MCLinker& pMCLinker) { if (0 == m_pExecFileFormat) m_pExecFileFormat = new ELFExecFileFormat(*this); // initialize standard sections m_pExecFileFormat->initStdSections(pMCLinker); return true; } bool GNULDBackend::initDynObjSections(MCLinker& pMCLinker) { if (0 == m_pDynObjFileFormat) m_pDynObjFileFormat = new ELFDynObjFileFormat(*this); // initialize standard sections m_pDynObjFileFormat->initStdSections(pMCLinker); return true; } bool GNULDBackend::initStandardSymbols(MCLinker& pLinker) { return true; } GNUArchiveReader *GNULDBackend::getArchiveReader() { assert(0 != m_pArchiveReader); return m_pArchiveReader; } GNUArchiveReader *GNULDBackend::getArchiveReader() const { assert(0 != m_pArchiveReader); return m_pArchiveReader; } ELFObjectReader *GNULDBackend::getObjectReader() { assert(0 != m_pObjectReader); return m_pObjectReader; } ELFObjectReader *GNULDBackend::getObjectReader() const { assert(0 != m_pObjectReader); return m_pObjectReader; } ELFDynObjReader *GNULDBackend::getDynObjReader() { assert(0 != m_pDynObjReader); return m_pDynObjReader; } ELFDynObjReader *GNULDBackend::getDynObjReader() const { assert(0 != m_pDynObjReader); return m_pDynObjReader; } ELFObjectWriter *GNULDBackend::getObjectWriter() { // TODO return NULL; } ELFObjectWriter *GNULDBackend::getObjectWriter() const { // TODO return NULL; } ELFDynObjWriter *GNULDBackend::getDynObjWriter() { assert(0 != m_pDynObjWriter); return m_pDynObjWriter; } ELFDynObjWriter *GNULDBackend::getDynObjWriter() const { assert(0 != m_pDynObjWriter); return m_pDynObjWriter; } ELFDynObjFileFormat* GNULDBackend::getDynObjFileFormat() { assert(0 != m_pDynObjFileFormat); return m_pDynObjFileFormat; } ELFDynObjFileFormat* GNULDBackend::getDynObjFileFormat() const { assert(0 != m_pDynObjFileFormat); return m_pDynObjFileFormat; } ELFExecFileFormat* GNULDBackend::getExecFileFormat() { assert(0 != m_pExecFileFormat); return m_pExecFileFormat; } ELFExecFileFormat* GNULDBackend::getExecFileFormat() const { assert(0 != m_pExecFileFormat); return m_pExecFileFormat; } /// sizeNamePools - compute the size of regular name pools /// In ELF executable files, regular name pools are .symtab, .strtab, /// .dynsym, .dynstr, and .hash void GNULDBackend::sizeNamePools(const Output& pOutput, const SymbolCategory& pSymbols, const MCLDInfo& pLDInfo) { // size of string tables starts from 1 to hold the null character in their // first byte size_t symtab = 1; size_t dynsym = 1; // 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 strtab = 1; size_t dynstr = 1; size_t hash = 0; // compute size of .symtab, .dynsym and .strtab SymbolCategory::const_iterator symbol; SymbolCategory::const_iterator symEnd = pSymbols.end(); for (symbol = pSymbols.begin(); symbol != symEnd; ++symbol) { size_t str_size = (*symbol)->nameSize() + 1; if (isDynamicSymbol(**symbol, pOutput)) { ++dynsym; dynstr += str_size; } ++symtab; strtab += str_size; } ELFFileFormat* file_format = NULL; switch(pOutput.type()) { // compute size of .dynstr and .hash case Output::DynObj: file_format = getDynObjFileFormat(); break; case Output::Exec: file_format = getExecFileFormat(); break; case Output::Object: default: // TODO: not support yet return; } switch(pOutput.type()) { // compute size of .dynstr and .hash case Output::DynObj: case Output::Exec: { // add DT_NEED strings into .dynstr and .dynamic // Rules: // 1. ignore --no-add-needed // 2. force count in --no-as-needed // 3. judge --as-needed InputTree::const_bfs_iterator input, inputEnd = pLDInfo.inputs().bfs_end(); for (input = pLDInfo.inputs().bfs_begin(); input != inputEnd; ++input) { if (Input::DynObj == (*input)->type()) { // --add-needed if ((*input)->attribute()->isAddNeeded()) { // --no-as-needed if (!(*input)->attribute()->isAsNeeded()) { dynstr += (*input)->name().size() + 1; dynamic().reserveNeedEntry(); } // --as-needed else if ((*input)->isNeeded()) { dynstr += (*input)->name().size() + 1; dynamic().reserveNeedEntry(); } } } } // for // compute .hash // Both Elf32_Word and Elf64_Word are 4 bytes hash = (2 + getHashBucketCount(dynsym, false) + dynsym) * sizeof(llvm::ELF::Elf32_Word); // set size dynstr += pOutput.name().size() + 1; if (32 == bitclass()) 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); } /* fall through */ case Output::Object: { if (32 == bitclass()) 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); break; } } // end of switch // reserve fixed entries in the .dynamic section. if (Output::DynObj == pOutput.type() || Output::Exec == pOutput.type()) { // 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(pLDInfo, *file_format); file_format->getDynamic().setSize(dynamic().numOfBytes()); } } /// 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(Output& pOutput, SymbolCategory& pSymbols, const Layout& pLayout, const MCLDInfo& pLDInfo) { assert(pOutput.hasMemArea()); bool sym_exist = false; HashTableType::entry_type* entry = 0; ELFFileFormat* file_format = NULL; switch(pOutput.type()) { // compute size of .dynstr and .hash case Output::DynObj: file_format = getDynObjFileFormat(); break; case Output::Exec: file_format = getExecFileFormat(); break; case Output::Object: default: // add first symbol into m_pSymIndexMap entry = m_pSymIndexMap->insert(NULL, sym_exist); entry->setValue(0); // TODO: not support yet return; } LDSection& symtab_sect = file_format->getSymTab(); LDSection& strtab_sect = file_format->getStrTab(); MemoryRegion* symtab_region = pOutput.memArea()->request(symtab_sect.offset(), symtab_sect.size()); MemoryRegion* strtab_region = pOutput.memArea()->request(strtab_sect.offset(), strtab_sect.size()); // set up symtab_region llvm::ELF::Elf32_Sym* symtab32 = NULL; llvm::ELF::Elf64_Sym* symtab64 = NULL; if (32 == bitclass()) symtab32 = (llvm::ELF::Elf32_Sym*)symtab_region->start(); else if (64 == bitclass()) symtab64 = (llvm::ELF::Elf64_Sym*)symtab_region->start(); else llvm::report_fatal_error(llvm::Twine("unsupported bitclass ") + llvm::Twine(bitclass()) + llvm::Twine(".\n")); // set up strtab_region char* strtab = (char*)strtab_region->start(); strtab[0] = '\0'; // initialize the first ELF symbol if (32 == bitclass()) { symtab32[0].st_name = 0; symtab32[0].st_value = 0; symtab32[0].st_size = 0; symtab32[0].st_info = 0; symtab32[0].st_other = 0; symtab32[0].st_shndx = 0; } else { // must 64 symtab64[0].st_name = 0; symtab64[0].st_value = 0; symtab64[0].st_size = 0; symtab64[0].st_info = 0; symtab64[0].st_other = 0; symtab64[0].st_shndx = 0; } size_t symtabIdx = 1; size_t strtabsize = 1; // compute size of .symtab, .dynsym and .strtab SymbolCategory::iterator symbol; SymbolCategory::iterator symEnd = pSymbols.end(); for (symbol = pSymbols.begin(); symbol != symEnd; ++symbol) { // maintain output's symbol and index map if building .o file if (Output::Object == pOutput.type()) { entry = m_pSymIndexMap->insert(NULL, sym_exist); entry->setValue(symtabIdx); } // FIXME: check the endian between host and target // write out symbol if (32 == bitclass()) { symtab32[symtabIdx].st_name = strtabsize; symtab32[symtabIdx].st_value = getSymbolValue(**symbol); symtab32[symtabIdx].st_size = getSymbolSize(**symbol); symtab32[symtabIdx].st_info = getSymbolInfo(**symbol); symtab32[symtabIdx].st_other = (*symbol)->visibility(); symtab32[symtabIdx].st_shndx = getSymbolShndx(**symbol, pLayout); } else { // must 64 symtab64[symtabIdx].st_name = strtabsize; symtab64[symtabIdx].st_value = getSymbolValue(**symbol); symtab64[symtabIdx].st_size = getSymbolSize(**symbol); symtab64[symtabIdx].st_info = getSymbolInfo(**symbol); symtab64[symtabIdx].st_other = (*symbol)->visibility(); symtab64[symtabIdx].st_shndx = getSymbolShndx(**symbol, pLayout); } // write out string strcpy((strtab + strtabsize), (*symbol)->name()); // write out // sum up counters ++symtabIdx; strtabsize += (*symbol)->nameSize() + 1; } } /// emitNamePools - 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(Output& pOutput, SymbolCategory& pSymbols, const Layout& pLayout, const MCLDInfo& pLDInfo) { assert(pOutput.hasMemArea()); ELFFileFormat* file_format = NULL; bool sym_exist = false; HashTableType::entry_type* entry = 0; switch(pOutput.type()) { // compute size of .dynstr and .hash case Output::DynObj: file_format = getDynObjFileFormat(); break; case Output::Exec: file_format = getExecFileFormat(); break; case Output::Object: default: // TODO: not support yet return; } LDSection& symtab_sect = file_format->getDynSymTab(); LDSection& strtab_sect = file_format->getDynStrTab(); LDSection& hash_sect = file_format->getHashTab(); LDSection& dyn_sect = file_format->getDynamic(); MemoryRegion* symtab_region = pOutput.memArea()->request(symtab_sect.offset(), symtab_sect.size()); MemoryRegion* strtab_region = pOutput.memArea()->request(strtab_sect.offset(), strtab_sect.size()); MemoryRegion* hash_region = pOutput.memArea()->request(hash_sect.offset(), hash_sect.size()); MemoryRegion* dyn_region = pOutput.memArea()->request(dyn_sect.offset(), dyn_sect.size()); // set up symtab_region llvm::ELF::Elf32_Sym* symtab32 = NULL; llvm::ELF::Elf64_Sym* symtab64 = NULL; if (32 == bitclass()) symtab32 = (llvm::ELF::Elf32_Sym*)symtab_region->start(); else if (64 == bitclass()) symtab64 = (llvm::ELF::Elf64_Sym*)symtab_region->start(); else llvm::report_fatal_error(llvm::Twine("unsupported bitclass ") + llvm::Twine(bitclass()) + llvm::Twine(".\n")); // initialize the first ELF symbol if (32 == bitclass()) { symtab32[0].st_name = 0; symtab32[0].st_value = 0; symtab32[0].st_size = 0; symtab32[0].st_info = 0; symtab32[0].st_other = 0; symtab32[0].st_shndx = 0; } else { // must 64 symtab64[0].st_name = 0; symtab64[0].st_value = 0; symtab64[0].st_size = 0; symtab64[0].st_info = 0; symtab64[0].st_other = 0; symtab64[0].st_shndx = 0; } // set up strtab_region char* strtab = (char*)strtab_region->start(); strtab[0] = '\0'; // add the first symbol into m_pSymIndexMap entry = m_pSymIndexMap->insert(NULL, sym_exist); entry->setValue(0); size_t symtabIdx = 1; size_t strtabsize = 1; // emit of .dynsym, and .dynstr SymbolCategory::iterator symbol; SymbolCategory::iterator symEnd = pSymbols.end(); for (symbol = pSymbols.begin(); symbol != symEnd; ++symbol) { if (!isDynamicSymbol(**symbol, pOutput)) continue; // maintain output's symbol and index map entry = m_pSymIndexMap->insert(*symbol, sym_exist); entry->setValue(symtabIdx); // FIXME: check the endian between host and target // write out symbol if (32 == bitclass()) { symtab32[symtabIdx].st_name = strtabsize; symtab32[symtabIdx].st_value = (*symbol)->value(); symtab32[symtabIdx].st_size = getSymbolSize(**symbol); symtab32[symtabIdx].st_info = getSymbolInfo(**symbol); symtab32[symtabIdx].st_other = (*symbol)->visibility(); symtab32[symtabIdx].st_shndx = getSymbolShndx(**symbol, pLayout); } else { // must 64 symtab64[symtabIdx].st_name = strtabsize; symtab64[symtabIdx].st_value = (*symbol)->value(); symtab64[symtabIdx].st_size = getSymbolSize(**symbol); symtab64[symtabIdx].st_info = getSymbolInfo(**symbol); symtab64[symtabIdx].st_other = (*symbol)->visibility(); symtab64[symtabIdx].st_shndx = getSymbolShndx(**symbol, pLayout); } // write out string strcpy((strtab + strtabsize), (*symbol)->name()); // sum up counters ++symtabIdx; strtabsize += (*symbol)->nameSize() + 1; } // emit DT_NEED // add DT_NEED strings into .dynstr // Rules: // 1. ignore --no-add-needed // 2. force count in --no-as-needed // 3. judge --as-needed ELFDynamic::iterator dt_need = dynamic().needBegin(); InputTree::const_bfs_iterator input, inputEnd = pLDInfo.inputs().bfs_end(); for (input = pLDInfo.inputs().bfs_begin(); input != inputEnd; ++input) { if (Input::DynObj == (*input)->type()) { // --add-needed if ((*input)->attribute()->isAddNeeded()) { // --no-as-needed if (!(*input)->attribute()->isAsNeeded()) { strcpy((strtab + strtabsize), (*input)->name().c_str()); (*dt_need)->setValue(llvm::ELF::DT_NEEDED, strtabsize); strtabsize += (*input)->name().size() + 1; ++dt_need; } // --as-needed else if ((*input)->isNeeded()) { strcpy((strtab + strtabsize), (*input)->name().c_str()); (*dt_need)->setValue(llvm::ELF::DT_NEEDED, strtabsize); strtabsize += (*input)->name().size() + 1; ++dt_need; } } } } // for // emit soname // initialize value of ELF .dynamic section dynamic().applySoname(strtabsize); dynamic().applyEntries(pLDInfo, *file_format); dynamic().emit(dyn_sect, *dyn_region); strcpy((strtab + strtabsize), pOutput.name().c_str()); strtabsize += pOutput.name().size() + 1; // emit hash table // FIXME: this verion only emit SVR4 hash section. // Please add GNU new hash section // both 32 and 64 bits hash table use 32-bit entry // set up hash_region uint32_t* word_array = (uint32_t*)hash_region->start(); uint32_t& nbucket = word_array[0]; uint32_t& nchain = word_array[1]; nbucket = getHashBucketCount(symtabIdx, false); nchain = symtabIdx; uint32_t* bucket = (word_array + 2); uint32_t* chain = (bucket + nbucket); // initialize bucket bzero((void*)bucket, nbucket); StringHash<ELF> hash_func; if (32 == bitclass()) { for (size_t sym_idx=0; sym_idx < symtabIdx; ++sym_idx) { llvm::StringRef name(strtab + symtab32[sym_idx].st_name); size_t bucket_pos = hash_func(name) % nbucket; chain[sym_idx] = bucket[bucket_pos]; bucket[bucket_pos] = sym_idx; } } else if (64 == bitclass()) { for (size_t sym_idx=0; sym_idx < symtabIdx; ++sym_idx) { llvm::StringRef name(strtab + symtab64[sym_idx].st_name); size_t bucket_pos = hash_func(name) % nbucket; chain[sym_idx] = bucket[bucket_pos]; bucket[bucket_pos] = sym_idx; } } } /// getSectionOrder unsigned int GNULDBackend::getSectionOrder(const Output& pOutput, const LDSection& pSectHdr) const { // NULL section should be the "1st" section if (LDFileFormat::Null == pSectHdr.kind()) return 0; // 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; ELFFileFormat* file_format = NULL; switch (pOutput.type()) { case Output::DynObj: file_format = getDynObjFileFormat(); break; case Output::Exec: file_format = getExecFileFormat(); break; case Output::Object: default: assert(0 && "Not support yet.\n"); break; } // TODO: need to take care other possible output sections switch (pSectHdr.kind()) { case LDFileFormat::Regular: 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 (pSectHdr.type() == llvm::ELF::SHT_PREINIT_ARRAY || pSectHdr.type() == llvm::ELF::SHT_INIT_ARRAY || pSectHdr.type() == llvm::ELF::SHT_FINI_ARRAY || &pSectHdr == &file_format->getCtors() || &pSectHdr == &file_format->getDtors()) return SHO_RELRO; return SHO_DATA; } case LDFileFormat::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(pOutput, pSectHdr); // handle .interp case LDFileFormat::Note: return SHO_INTERP; case LDFileFormat::Exception: return SHO_EHFRAME; case LDFileFormat::MetaData: case LDFileFormat::Debug: default: return SHO_UNDEFINED; } } /// getSymbolSize uint64_t GNULDBackend::getSymbolSize(const LDSymbol& pSymbol) const { // @ref Google gold linker: symtab.cc: 2780 // 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 (pSymbol.visibility() == llvm::ELF::STV_INTERNAL || pSymbol.visibility() == llvm::ELF::STV_HIDDEN) bind = llvm::ELF::STB_LOCAL; return (pSymbol.resolveInfo()->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 Layout& pLayout) 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()->isLocal()) { switch (pSymbol.type()) { case ResolveInfo::NoType: case ResolveInfo::File: return llvm::ELF::SHN_ABS; } } assert(pSymbol.hasFragRef()); return pLayout.getOutputLDSection(*pSymbol.fragRef()->frag())->index(); } /// getSymbolIdx - called by emitRelocation to get the ouput symbol table index size_t GNULDBackend::getSymbolIdx(LDSymbol* pSymbol) const { HashTableType::iterator entry = m_pSymIndexMap->find(pSymbol); return entry.getEntry()->value(); } /// emitProgramHdrs - emit ELF program headers void GNULDBackend::emitProgramHdrs(Output& pOutput) { assert(NULL != pOutput.context()); createProgramHdrs(*pOutput.context()); if (32 == bitclass()) writeELF32ProgramHdrs(pOutput); else writeELF64ProgramHdrs(pOutput); } /// createProgramHdrs - base on output sections to create the program headers void GNULDBackend::createProgramHdrs(LDContext& pContext) { // make PT_PHDR m_ELFSegmentTable.produce(llvm::ELF::PT_PHDR); // make PT_INTERP LDSection* interp = pContext.getSection(".interp"); if (NULL != interp) { ELFSegment* interp_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_INTERP); interp_seg->addSection(interp); interp_seg->setAlign(bitclass() / 8); } uint32_t cur_seg_flag, prev_seg_flag = getSegmentFlag(0); uint64_t padding = 0; ELFSegment* load_seg = NULL; // make possible PT_LOAD segments LDContext::sect_iterator sect, sect_end = pContext.sectEnd(); for (sect = pContext.sectBegin(); sect != sect_end; ++sect) { if (0 == ((*sect)->flag() & llvm::ELF::SHF_ALLOC) && LDFileFormat::Null != (*sect)->kind()) continue; // FIXME: Now only separate writable and non-writable PT_LOAD cur_seg_flag = getSegmentFlag((*sect)->flag()); if ((prev_seg_flag & llvm::ELF::PF_W) ^ (cur_seg_flag & llvm::ELF::PF_W) || LDFileFormat::Null == (*sect)->kind()) { // create new PT_LOAD segment load_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_LOAD); load_seg->setAlign(pagesize()); // check if this segment needs padding padding = 0; if (((*sect)->offset() & (load_seg->align() - 1)) != 0) padding = load_seg->align(); } assert(NULL != load_seg); load_seg->addSection(*sect); load_seg->updateFlag(cur_seg_flag); // FIXME: set section's vma // need to handle start vma for user-defined one or for executable. (*sect)->setAddr((*sect)->offset() + padding); prev_seg_flag = cur_seg_flag; } // make PT_DYNAMIC LDSection* dynamic = pContext.getSection(".dynamic"); if (NULL != dynamic) { ELFSegment* dyn_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_DYNAMIC); dyn_seg->setFlag(llvm::ELF::PF_R | llvm::ELF::PF_W); dyn_seg->addSection(dynamic); dyn_seg->setAlign(bitclass() / 8); } // update segment info uint64_t file_size = 0; ELFSegmentFactory::iterator seg, seg_end = m_ELFSegmentTable.end(); for (seg = m_ELFSegmentTable.begin(); seg != seg_end; ++seg) { ELFSegment& segment = *seg; // update PT_PHDR if (llvm::ELF::PT_PHDR == segment.type()) { uint64_t offset, phdr_size; if (32 == bitclass()) { 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); } segment.setOffset(offset); segment.setVaddr(offset); segment.setPaddr(segment.vaddr()); segment.setFilesz(numOfSegments() * phdr_size); segment.setMemsz(numOfSegments() * phdr_size); segment.setAlign(bitclass() / 8); continue; } assert(NULL != segment.getFirstSection()); segment.setOffset(segment.getFirstSection()->offset()); segment.setVaddr(segment.getFirstSection()->addr()); segment.setPaddr(segment.vaddr()); const LDSection* last_sect = segment.getLastSection(); assert(NULL != last_sect); file_size = last_sect->offset() - segment.offset(); if (LDFileFormat::BSS != last_sect->kind()) file_size += last_sect->size(); segment.setFilesz(file_size); segment.setMemsz(last_sect->addr() - segment.vaddr() + last_sect->size()); } } /// writeELF32ProgramHdrs - write out the ELF32 program headers void GNULDBackend::writeELF32ProgramHdrs(Output& pOutput) { assert(pOutput.hasMemArea()); uint64_t start_offset, phdr_size; start_offset = sizeof(llvm::ELF::Elf32_Ehdr); phdr_size = sizeof(llvm::ELF::Elf32_Phdr); // Program header must start directly after ELF header MemoryRegion *region = pOutput.memArea()->request(start_offset, numOfSegments()*phdr_size); llvm::ELF::Elf32_Phdr* phdr = (llvm::ELF::Elf32_Phdr*)region->start(); size_t index = 0; ELFSegmentFactory::iterator seg, segEnd = m_ELFSegmentTable.end(); for (seg = m_ELFSegmentTable.begin(); seg != segEnd; ++seg, ++index) { phdr[index].p_type = (*seg).type(); phdr[index].p_flags = (*seg).flag(); phdr[index].p_offset = (*seg).offset(); phdr[index].p_vaddr = (*seg).vaddr(); phdr[index].p_paddr = (*seg).paddr(); phdr[index].p_filesz = (*seg).filesz(); phdr[index].p_memsz = (*seg).memsz(); phdr[index].p_align = (*seg).align(); } } /// writeELF64ProgramHdrs - write out the ELF64 program headers void GNULDBackend::writeELF64ProgramHdrs(Output& pOutput) { assert(pOutput.hasMemArea()); uint64_t start_offset, phdr_size; start_offset = sizeof(llvm::ELF::Elf64_Ehdr); phdr_size = sizeof(llvm::ELF::Elf64_Phdr); // Program header must start directly after ELF header MemoryRegion *region = pOutput.memArea()->request(start_offset, numOfSegments() *phdr_size); llvm::ELF::Elf64_Phdr* phdr = (llvm::ELF::Elf64_Phdr*)region->start(); size_t index = 0; ELFSegmentFactory::iterator seg, segEnd = m_ELFSegmentTable.end(); for (seg = m_ELFSegmentTable.begin(); seg != segEnd; ++seg, ++index) { phdr[index].p_type = (*seg).type(); phdr[index].p_flags = (*seg).flag(); phdr[index].p_offset = (*seg).offset(); phdr[index].p_vaddr = (*seg).vaddr(); phdr[index].p_paddr = (*seg).paddr(); phdr[index].p_filesz = (*seg).filesz(); phdr[index].p_memsz = (*seg).memsz(); phdr[index].p_align = (*seg).align(); } } /// preLayout - Backend can do any needed modification before layout void GNULDBackend::preLayout(const Output& pOutput, const MCLDInfo& pLDInfo, MCLinker& pLinker) { // prelayout target first doPreLayout(pOutput, pLDInfo, pLinker); } /// postLayout -Backend can do any needed modification after layout void GNULDBackend::postLayout(const Output& pOutput, const MCLDInfo& pInfo, MCLinker& pLinker) { // post layout target first doPostLayout(pOutput, pInfo, pLinker); } /// getHashBucketCount - calculate hash bucket count. /// @ref Google gold linker, dynobj.cc:791 unsigned GNULDBackend::getHashBucketCount(unsigned pNumOfSymbols, bool pIsGNUStyle) { // @ref Google gold, dynobj.cc:loc 791 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; } /// isDynamicSymbol /// @ref Google gold linker: symtab.cc:311 bool GNULDBackend::isDynamicSymbol(const LDSymbol& pSymbol, const Output& pOutput) { // 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 (Output::DynObj == pOutput.type()) if (pSymbol.resolveInfo()->visibility() == ResolveInfo::Default || pSymbol.resolveInfo()->visibility() == ResolveInfo::Protected) return true; return false; }