| //===- 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 <string> |
| #include <cstring> |
| #include <cassert> |
| |
| #include <llvm/Support/ELF.h> |
| |
| #include <mcld/ADT/SizeTraits.h> |
| #include <mcld/LD/LDSymbol.h> |
| #include <mcld/LD/Layout.h> |
| #include <mcld/LD/FillFragment.h> |
| #include <mcld/MC/MCLDInfo.h> |
| #include <mcld/MC/MCLDOutput.h> |
| #include <mcld/MC/InputTree.h> |
| #include <mcld/MC/SymbolCategory.h> |
| #include <mcld/MC/MCLinker.h> |
| #include <mcld/Support/MemoryArea.h> |
| #include <mcld/Support/MemoryRegion.h> |
| #include <mcld/Support/MsgHandling.h> |
| #include <mcld/Support/MemoryAreaFactory.h> |
| |
| using namespace mcld; |
| |
| //===----------------------------------------------------------------------===// |
| // GNULDBackend |
| //===----------------------------------------------------------------------===// |
| GNULDBackend::GNULDBackend() |
| : m_pArchiveReader(NULL), |
| m_pObjectReader(NULL), |
| m_pDynObjReader(NULL), |
| m_pObjectWriter(NULL), |
| m_pDynObjWriter(NULL), |
| m_pExecWriter(NULL), |
| m_pDynObjFileFormat(NULL), |
| m_pExecFileFormat(NULL), |
| m_ELFSegmentTable(9), // magic number |
| m_pEhFrameHdr(NULL), |
| f_pPreInitArrayStart(NULL), |
| f_pPreInitArrayEnd(NULL), |
| f_pInitArrayStart(NULL), |
| f_pInitArrayEnd(NULL), |
| f_pFiniArrayStart(NULL), |
| f_pFiniArrayEnd(NULL), |
| f_pStack(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_pSymIndexMap = new HashTableType(1024); |
| } |
| |
| GNULDBackend::~GNULDBackend() |
| { |
| if (NULL != m_pArchiveReader) |
| delete m_pArchiveReader; |
| if (NULL != m_pObjectReader) |
| delete m_pObjectReader; |
| if (NULL != m_pDynObjReader) |
| delete m_pDynObjReader; |
| if (NULL != m_pObjectWriter) |
| delete m_pObjectWriter; |
| if (NULL != m_pDynObjWriter) |
| delete m_pDynObjWriter; |
| if (NULL != m_pExecWriter) |
| delete m_pExecWriter; |
| if (NULL != m_pDynObjFileFormat) |
| delete m_pDynObjFileFormat; |
| if (NULL != m_pExecFileFormat) |
| delete m_pExecFileFormat; |
| if (NULL != m_pSymIndexMap) |
| delete m_pSymIndexMap; |
| if (NULL != m_pEhFrameHdr) |
| delete m_pEhFrameHdr; |
| } |
| |
| 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); |
| } |
| |
| uint64_t GNULDBackend::segmentStartAddr(const Output& pOutput, |
| const MCLDInfo& pInfo) const |
| { |
| // TODO: handle the user option: -TText= |
| if (isOutputPIC(pOutput, pInfo)) |
| return 0x0; |
| else |
| return defaultTextSegmentAddr(); |
| } |
| |
| bool GNULDBackend::initArchiveReader(MCLinker& pLinker, |
| MCLDInfo& pInfo, |
| MemoryAreaFactory& pMemAreaFactory) |
| { |
| if (NULL == m_pArchiveReader) { |
| assert(NULL != m_pObjectReader); |
| m_pArchiveReader = new GNUArchiveReader(pInfo, |
| pMemAreaFactory, |
| *m_pObjectReader); |
| } |
| return true; |
| } |
| |
| bool GNULDBackend::initObjectReader(MCLinker& pLinker) |
| { |
| if (NULL == m_pObjectReader) |
| m_pObjectReader = new ELFObjectReader(*this, pLinker); |
| return true; |
| } |
| |
| bool GNULDBackend::initDynObjReader(MCLinker& pLinker) |
| { |
| if (NULL == m_pDynObjReader) |
| m_pDynObjReader = new ELFDynObjReader(*this, pLinker); |
| return true; |
| } |
| |
| bool GNULDBackend::initObjectWriter(MCLinker&) |
| { |
| // TODO |
| return true; |
| } |
| |
| bool GNULDBackend::initDynObjWriter(MCLinker& pLinker) |
| { |
| if (NULL == m_pDynObjWriter) |
| m_pDynObjWriter = new ELFDynObjWriter(*this, pLinker); |
| return true; |
| } |
| |
| bool GNULDBackend::initExecWriter(MCLinker& pLinker) |
| { |
| if (NULL == m_pExecWriter) |
| m_pExecWriter = new ELFExecWriter(*this, pLinker); |
| return true; |
| } |
| |
| bool GNULDBackend::initExecSections(MCLinker& pMCLinker) |
| { |
| if (NULL == m_pExecFileFormat) |
| m_pExecFileFormat = new ELFExecFileFormat(*this); |
| |
| // initialize standard sections |
| m_pExecFileFormat->initStdSections(pMCLinker); |
| return true; |
| } |
| |
| bool GNULDBackend::initDynObjSections(MCLinker& pMCLinker) |
| { |
| if (NULL == m_pDynObjFileFormat) |
| m_pDynObjFileFormat = new ELFDynObjFileFormat(*this); |
| |
| // initialize standard sections |
| m_pDynObjFileFormat->initStdSections(pMCLinker); |
| return true; |
| } |
| |
| bool GNULDBackend::initStandardSymbols(MCLinker& pLinker, const Output& pOutput) |
| { |
| ELFFileFormat* file_format = getOutputFormat(pOutput); |
| |
| // ----- section symbols ----- // |
| // .preinit_array |
| FragmentRef* preinit_array = NULL; |
| if (file_format->hasPreInitArray()) { |
| preinit_array = pLinker.getLayout().getFragmentRef( |
| *(file_format->getPreInitArray().getSectionData()->begin()), |
| 0x0); |
| } |
| f_pPreInitArrayStart = |
| pLinker.defineSymbol<MCLinker::AsRefered, |
| MCLinker::Resolve>("__preinit_array_start", |
| false, // isDyn |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Global, |
| 0x0, // size |
| 0x0, // value |
| preinit_array, // FragRef |
| ResolveInfo::Hidden); |
| f_pPreInitArrayEnd = |
| pLinker.defineSymbol<MCLinker::AsRefered, |
| MCLinker::Resolve>("__preinit_array_end", |
| false, // isDyn |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Global, |
| 0x0, // size |
| 0x0, // value |
| NULL, // FragRef |
| ResolveInfo::Hidden); |
| |
| // .init_array |
| FragmentRef* init_array = NULL; |
| if (file_format->hasInitArray()) { |
| init_array = pLinker.getLayout().getFragmentRef( |
| *(file_format->getInitArray().getSectionData()->begin()), |
| 0x0); |
| } |
| |
| f_pInitArrayStart = |
| pLinker.defineSymbol<MCLinker::AsRefered, |
| MCLinker::Resolve>("__init_array_start", |
| false, // isDyn |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Global, |
| 0x0, // size |
| 0x0, // value |
| init_array, // FragRef |
| ResolveInfo::Hidden); |
| f_pInitArrayEnd = |
| pLinker.defineSymbol<MCLinker::AsRefered, |
| MCLinker::Resolve>("__init_array_end", |
| false, // isDyn |
| 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 = pLinker.getLayout().getFragmentRef( |
| *(file_format->getFiniArray().getSectionData()->begin()), |
| 0x0); |
| } |
| |
| f_pFiniArrayStart = |
| pLinker.defineSymbol<MCLinker::AsRefered, |
| MCLinker::Resolve>("__fini_array_start", |
| false, // isDyn |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Global, |
| 0x0, // size |
| 0x0, // value |
| fini_array, // FragRef |
| ResolveInfo::Hidden); |
| f_pFiniArrayEnd = |
| pLinker.defineSymbol<MCLinker::AsRefered, |
| MCLinker::Resolve>("__fini_array_end", |
| false, // isDyn |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Global, |
| 0x0, // size |
| 0x0, // value |
| fini_array, // FragRef |
| ResolveInfo::Hidden); |
| |
| // .stack |
| FragmentRef* stack = NULL; |
| if (file_format->hasStack()) { |
| stack = pLinker.getLayout().getFragmentRef( |
| *(file_format->getStack().getSectionData()->begin()), |
| 0x0); |
| } |
| f_pStack = |
| pLinker.defineSymbol<MCLinker::AsRefered, |
| MCLinker::Resolve>("__stack", |
| false, // isDyn |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Global, |
| 0x0, // size |
| 0x0, // value |
| stack, // FragRef |
| ResolveInfo::Hidden); |
| |
| // ----- segment symbols ----- // |
| f_pExecutableStart = |
| pLinker.defineSymbol<MCLinker::AsRefered, |
| MCLinker::Resolve>("__executable_start", |
| false, // isDyn |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Absolute, |
| 0x0, // size |
| 0x0, // value |
| NULL, // FragRef |
| ResolveInfo::Default); |
| f_pEText = |
| pLinker.defineSymbol<MCLinker::AsRefered, |
| MCLinker::Resolve>("etext", |
| false, // isDyn |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Absolute, |
| 0x0, // size |
| 0x0, // value |
| NULL, // FragRef |
| ResolveInfo::Default); |
| f_p_EText = |
| pLinker.defineSymbol<MCLinker::AsRefered, |
| MCLinker::Resolve>("_etext", |
| false, // isDyn |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Absolute, |
| 0x0, // size |
| 0x0, // value |
| NULL, // FragRef |
| ResolveInfo::Default); |
| f_p__EText = |
| pLinker.defineSymbol<MCLinker::AsRefered, |
| MCLinker::Resolve>("__etext", |
| false, // isDyn |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Absolute, |
| 0x0, // size |
| 0x0, // value |
| NULL, // FragRef |
| ResolveInfo::Default); |
| f_pEData = |
| pLinker.defineSymbol<MCLinker::AsRefered, |
| MCLinker::Resolve>("edata", |
| false, // isDyn |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Absolute, |
| 0x0, // size |
| 0x0, // value |
| NULL, // FragRef |
| ResolveInfo::Default); |
| |
| f_pEnd = |
| pLinker.defineSymbol<MCLinker::AsRefered, |
| MCLinker::Resolve>("end", |
| false, // isDyn |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Absolute, |
| 0x0, // size |
| 0x0, // value |
| NULL, // FragRef |
| ResolveInfo::Default); |
| |
| // _edata is defined forcefully. |
| // @ref Google gold linker: defstd.cc: 186 |
| f_p_EData = |
| pLinker.defineSymbol<MCLinker::Force, |
| MCLinker::Resolve>("_edata", |
| false, // isDyn |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Absolute, |
| 0x0, // size |
| 0x0, // value |
| NULL, // FragRef |
| ResolveInfo::Default); |
| |
| // __bss_start is defined forcefully. |
| // @ref Google gold linker: defstd.cc: 214 |
| f_pBSSStart = |
| pLinker.defineSymbol<MCLinker::Force, |
| MCLinker::Resolve>("__bss_start", |
| false, // isDyn |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Absolute, |
| 0x0, // size |
| 0x0, // value |
| NULL, // FragRef |
| ResolveInfo::Default); |
| |
| // _end is defined forcefully. |
| // @ref Google gold linker: defstd.cc: 228 |
| f_p_End = |
| pLinker.defineSymbol<MCLinker::Force, |
| MCLinker::Resolve>("_end", |
| false, // isDyn |
| ResolveInfo::NoType, |
| ResolveInfo::Define, |
| ResolveInfo::Absolute, |
| 0x0, // size |
| 0x0, // value |
| NULL, // FragRef |
| ResolveInfo::Default); |
| |
| return true; |
| } |
| |
| bool |
| GNULDBackend::finalizeStandardSymbols(MCLinker& pLinker, const Output& pOutput) |
| { |
| ELFFileFormat* file_format = getOutputFormat(pOutput); |
| |
| // ----- section symbols ----- // |
| if (NULL != f_pPreInitArrayStart) { |
| if (!f_pPreInitArrayStart->hasFragRef()) { |
| f_pPreInitArrayStart->resolveInfo()->setBinding(ResolveInfo::Absolute); |
| f_pPreInitArrayStart->setValue(0x0); |
| } |
| } |
| |
| if (NULL != f_pPreInitArrayEnd) { |
| 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 (NULL != f_pInitArrayStart) { |
| if (!f_pInitArrayStart->hasFragRef()) { |
| f_pInitArrayStart->resolveInfo()->setBinding(ResolveInfo::Absolute); |
| f_pInitArrayStart->setValue(0x0); |
| } |
| } |
| |
| if (NULL != f_pInitArrayEnd) { |
| 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 (NULL != f_pFiniArrayStart) { |
| if (!f_pFiniArrayStart->hasFragRef()) { |
| f_pFiniArrayStart->resolveInfo()->setBinding(ResolveInfo::Absolute); |
| f_pFiniArrayStart->setValue(0x0); |
| } |
| } |
| |
| if (NULL != f_pFiniArrayEnd) { |
| 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 (NULL != f_pStack) { |
| if (!f_pStack->hasFragRef()) { |
| f_pStack->resolveInfo()->setBinding(ResolveInfo::Absolute); |
| f_pStack->setValue(0x0); |
| } |
| } |
| |
| // ----- segment symbols ----- // |
| if (NULL != f_pExecutableStart) { |
| ELFSegment* exec_start = m_ELFSegmentTable.find(llvm::ELF::PT_LOAD, 0x0, 0x0); |
| if (NULL != exec_start) { |
| if (ResolveInfo::ThreadLocal != f_pExecutableStart->type()) { |
| f_pExecutableStart->setValue(f_pExecutableStart->value() + |
| exec_start->vaddr()); |
| } |
| } |
| else |
| f_pExecutableStart->setValue(0x0); |
| } |
| |
| if (NULL != f_pEText || NULL != f_p_EText || NULL !=f_p__EText) { |
| ELFSegment* etext = m_ELFSegmentTable.find(llvm::ELF::PT_LOAD, |
| llvm::ELF::PF_X, |
| llvm::ELF::PF_W); |
| if (NULL != etext) { |
| if (NULL != f_pEText && ResolveInfo::ThreadLocal != f_pEText->type()) { |
| f_pEText->setValue(f_pEText->value() + |
| etext->vaddr() + |
| etext->memsz()); |
| } |
| if (NULL != f_p_EText && ResolveInfo::ThreadLocal != f_p_EText->type()) { |
| f_p_EText->setValue(f_p_EText->value() + |
| etext->vaddr() + |
| etext->memsz()); |
| } |
| if (NULL != f_p__EText && ResolveInfo::ThreadLocal != f_p__EText->type()) { |
| f_p__EText->setValue(f_p__EText->value() + |
| etext->vaddr() + |
| etext->memsz()); |
| } |
| } |
| else { |
| if (NULL != f_pEText) |
| f_pEText->setValue(0x0); |
| if (NULL != f_p_EText) |
| f_p_EText->setValue(0x0); |
| if (NULL != f_p__EText) |
| f_p__EText->setValue(0x0); |
| } |
| } |
| |
| if (NULL != f_pEData || NULL != f_p_EData || NULL != f_pBSSStart || |
| NULL != f_pEnd || NULL != f_p_End) { |
| ELFSegment* edata = m_ELFSegmentTable.find(llvm::ELF::PT_LOAD, |
| llvm::ELF::PF_W, |
| 0x0); |
| if (NULL != edata) { |
| if (NULL != f_pEData && ResolveInfo::ThreadLocal != f_pEData->type()) { |
| f_pEData->setValue(f_pEData->value() + |
| edata->vaddr() + |
| edata->filesz()); |
| } |
| if (NULL != f_p_EData && ResolveInfo::ThreadLocal != f_p_EData->type()) { |
| f_p_EData->setValue(f_p_EData->value() + |
| edata->vaddr() + |
| edata->filesz()); |
| } |
| if (NULL != f_pBSSStart && ResolveInfo::ThreadLocal != f_pBSSStart->type()) { |
| f_pBSSStart->setValue(f_pBSSStart->value() + |
| edata->vaddr() + |
| edata->filesz()); |
| } |
| |
| if (NULL != f_pEnd && ResolveInfo::ThreadLocal != f_pEnd->type()) { |
| f_pEnd->setValue(f_pEnd->value() + |
| edata->vaddr() + |
| edata->memsz()); |
| } |
| if (NULL != f_p_End && ResolveInfo::ThreadLocal != f_p_End->type()) { |
| f_p_End->setValue(f_p_End->value() + |
| edata->vaddr() + |
| edata->memsz()); |
| } |
| } |
| else { |
| if (NULL != f_pEData) |
| f_pEData->setValue(0x0); |
| if (NULL != f_p_EData) |
| f_p_EData->setValue(0x0); |
| if (NULL != f_pBSSStart) |
| f_pBSSStart->setValue(0x0); |
| |
| if (NULL != f_pEnd) |
| f_pEnd->setValue(0x0); |
| if (NULL != f_p_End) |
| f_p_End->setValue(0x0); |
| } |
| } |
| |
| return true; |
| } |
| |
| GNUArchiveReader *GNULDBackend::getArchiveReader() |
| { |
| assert(NULL != m_pArchiveReader); |
| return m_pArchiveReader; |
| } |
| |
| const GNUArchiveReader *GNULDBackend::getArchiveReader() const |
| { |
| assert(NULL != m_pArchiveReader); |
| return m_pArchiveReader; |
| } |
| |
| ELFObjectReader *GNULDBackend::getObjectReader() |
| { |
| assert(NULL != m_pObjectReader); |
| return m_pObjectReader; |
| } |
| |
| const ELFObjectReader *GNULDBackend::getObjectReader() const |
| { |
| assert(NULL != m_pObjectReader); |
| return m_pObjectReader; |
| } |
| |
| ELFDynObjReader *GNULDBackend::getDynObjReader() |
| { |
| assert(NULL != m_pDynObjReader); |
| return m_pDynObjReader; |
| } |
| |
| const ELFDynObjReader *GNULDBackend::getDynObjReader() const |
| { |
| assert(NULL != m_pDynObjReader); |
| return m_pDynObjReader; |
| } |
| |
| ELFObjectWriter *GNULDBackend::getObjectWriter() |
| { |
| // TODO |
| return NULL; |
| } |
| |
| const ELFObjectWriter *GNULDBackend::getObjectWriter() const |
| { |
| // TODO |
| return NULL; |
| } |
| |
| ELFDynObjWriter *GNULDBackend::getDynObjWriter() |
| { |
| assert(NULL != m_pDynObjWriter); |
| return m_pDynObjWriter; |
| } |
| |
| const ELFDynObjWriter *GNULDBackend::getDynObjWriter() const |
| { |
| assert(NULL != m_pDynObjWriter); |
| return m_pDynObjWriter; |
| } |
| |
| ELFExecWriter *GNULDBackend::getExecWriter() |
| { |
| assert(NULL != m_pExecWriter); |
| return m_pExecWriter; |
| } |
| |
| const ELFExecWriter *GNULDBackend::getExecWriter() const |
| { |
| assert(NULL != m_pExecWriter); |
| return m_pExecWriter; |
| } |
| |
| ELFFileFormat* GNULDBackend::getOutputFormat(const Output& pOutput) |
| { |
| switch (pOutput.type()) { |
| case Output::DynObj: |
| return getDynObjFileFormat(); |
| case Output::Exec: |
| return getExecFileFormat(); |
| // FIXME: We do not support building .o now |
| case Output::Object: |
| default: |
| fatal(diag::unrecognized_output_file) << pOutput.type(); |
| return NULL; |
| } |
| } |
| |
| const ELFFileFormat* GNULDBackend::getOutputFormat(const Output& pOutput) const |
| { |
| switch (pOutput.type()) { |
| case Output::DynObj: |
| return getDynObjFileFormat(); |
| case Output::Exec: |
| return getExecFileFormat(); |
| // FIXME: We do not support building .o now |
| case Output::Object: |
| default: |
| fatal(diag::unrecognized_output_file) << pOutput.type(); |
| return NULL; |
| } |
| } |
| |
| ELFDynObjFileFormat* GNULDBackend::getDynObjFileFormat() |
| { |
| assert(NULL != m_pDynObjFileFormat); |
| return m_pDynObjFileFormat; |
| } |
| |
| const ELFDynObjFileFormat* GNULDBackend::getDynObjFileFormat() const |
| { |
| assert(NULL != m_pDynObjFileFormat); |
| return m_pDynObjFileFormat; |
| } |
| |
| ELFExecFileFormat* GNULDBackend::getExecFileFormat() |
| { |
| assert(NULL != m_pExecFileFormat); |
| return m_pExecFileFormat; |
| } |
| |
| const ELFExecFileFormat* GNULDBackend::getExecFileFormat() const |
| { |
| assert(NULL != 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 = getOutputFormat(pOutput); |
| |
| 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 = getOutputFormat(pOutput); |
| if (pOutput.type() == Output::Object) { |
| // 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 = getOutputFormat(pOutput); |
| |
| bool sym_exist = false; |
| HashTableType::entry_type* entry = 0; |
| |
| 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 |
| if (Output::DynObj == pOutput.type()) |
| 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; |
| } |
| } |
| } |
| |
| /// sizeInterp - compute the size of the .interp section |
| void GNULDBackend::sizeInterp(const Output& pOutput, const MCLDInfo& pLDInfo) |
| { |
| assert(pOutput.type() == Output::Exec); |
| |
| const char* dyld_name; |
| if (pLDInfo.options().hasDyld()) |
| dyld_name = pLDInfo.options().dyld().c_str(); |
| else |
| dyld_name = dyld(); |
| |
| LDSection& interp = getExecFileFormat()->getInterp(); |
| interp.setSize(std::strlen(dyld_name) + 1); |
| } |
| |
| /// emitInterp - emit the .interp |
| void GNULDBackend::emitInterp(Output& pOutput, const MCLDInfo& pLDInfo) |
| { |
| assert(pOutput.type() == Output::Exec && |
| getExecFileFormat()->hasInterp() && |
| pOutput.hasMemArea()); |
| |
| const LDSection& interp = getExecFileFormat()->getInterp(); |
| MemoryRegion *region = pOutput.memArea()->request( |
| interp.offset(), interp.size()); |
| const char* dyld_name; |
| if (pLDInfo.options().hasDyld()) |
| dyld_name = pLDInfo.options().dyld().c_str(); |
| else |
| dyld_name = dyld(); |
| |
| std::memcpy(region->start(), dyld_name, interp.size()); |
| } |
| |
| /// getSectionOrder |
| unsigned int GNULDBackend::getSectionOrder(const Output& pOutput, |
| const LDSection& pSectHdr, |
| const MCLDInfo& pInfo) 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; |
| const ELFFileFormat* file_format = getOutputFormat(pOutput); |
| |
| // 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 (pInfo.options().hasRelro()) { |
| 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() || |
| &pSectHdr == &file_format->getJCR() || |
| 0 == pSectHdr.name().compare(".data.rel.ro")) |
| return SHO_RELRO; |
| if (0 == pSectHdr.name().compare(".data.rel.ro.local")) |
| return SHO_RELRO_LOCAL; |
| } |
| 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, pInfo); |
| |
| // handle .interp |
| case LDFileFormat::Note: |
| return SHO_INTERP; |
| |
| case LDFileFormat::EhFrame: |
| case LDFileFormat::EhFrameHdr: |
| case LDFileFormat::GCCExceptTable: |
| return SHO_EXCEPTION; |
| |
| 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; |
| |
| 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 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() && "symbols must have fragment reference to get its index"); |
| 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(); |
| } |
| |
| /// allocateCommonSymbols - allocate common symbols in the corresponding |
| /// sections. |
| /// @refer Google gold linker: common.cc: 214 |
| bool |
| GNULDBackend::allocateCommonSymbols(const MCLDInfo& pInfo, MCLinker& pLinker) const |
| { |
| SymbolCategory& symbol_list = pLinker.getOutputSymbols(); |
| |
| if (symbol_list.emptyCommons() && symbol_list.emptyLocals()) |
| 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 or create corresponding BSS LDSection |
| LDSection* bss_sect = &pLinker.getOrCreateOutputSectHdr(".bss", |
| LDFileFormat::BSS, |
| llvm::ELF::SHT_NOBITS, |
| llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC); |
| |
| LDSection* tbss_sect = &pLinker.getOrCreateOutputSectHdr( |
| ".tbss", |
| LDFileFormat::BSS, |
| llvm::ELF::SHT_NOBITS, |
| llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC); |
| |
| assert(NULL != bss_sect && NULL !=tbss_sect); |
| |
| // get or create corresponding BSS SectionData |
| SectionData& bss_sect_data = pLinker.getOrCreateSectData(*bss_sect); |
| SectionData& tbss_sect_data = pLinker.getOrCreateSectData(*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()); |
| (*com_sym)->setFragmentRef(new FragmentRef(*frag, 0)); |
| |
| if (ResolveInfo::ThreadLocal == (*com_sym)->type()) { |
| // allocate TLS common symbol in tbss section |
| tbss_offset += pLinker.getLayout().appendFragment(*frag, |
| tbss_sect_data, |
| (*com_sym)->value()); |
| } |
| else { |
| bss_offset += pLinker.getLayout().appendFragment(*frag, |
| bss_sect_data, |
| (*com_sym)->value()); |
| } |
| } |
| } |
| |
| // 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()); |
| (*com_sym)->setFragmentRef(new FragmentRef(*frag, 0)); |
| |
| if (ResolveInfo::ThreadLocal == (*com_sym)->type()) { |
| // allocate TLS common symbol in tbss section |
| tbss_offset += pLinker.getLayout().appendFragment(*frag, |
| tbss_sect_data, |
| (*com_sym)->value()); |
| } |
| else { |
| bss_offset += pLinker.getLayout().appendFragment(*frag, |
| bss_sect_data, |
| (*com_sym)->value()); |
| } |
| } |
| |
| bss_sect->setSize(bss_offset); |
| tbss_sect->setSize(tbss_offset); |
| symbol_list.changeCommonsToGlobal(); |
| return true; |
| } |
| |
| |
| /// createProgramHdrs - base on output sections to create the program headers |
| void GNULDBackend::createProgramHdrs(Output& pOutput, const MCLDInfo& pInfo) |
| { |
| assert(pOutput.hasContext()); |
| ELFFileFormat *file_format = getOutputFormat(pOutput); |
| |
| // make PT_PHDR |
| m_ELFSegmentTable.produce(llvm::ELF::PT_PHDR); |
| |
| // make PT_INTERP |
| if (file_format->hasInterp()) { |
| ELFSegment* interp_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_INTERP); |
| interp_seg->addSection(&file_format->getInterp()); |
| } |
| |
| // FIXME: Should we consider -z relro here? |
| if (pInfo.options().hasRelro()) { |
| // if -z relro is given, we need to adjust sections' offset again, and let |
| // PT_GNU_RELRO end on a common page boundary |
| LDContext::SectionTable& sect_table = pOutput.context()->getSectionTable(); |
| |
| size_t idx; |
| for (idx = 0; idx < pOutput.context()->numOfSections(); ++idx) { |
| // find the first non-relro section |
| if (getSectionOrder(pOutput, *sect_table[idx], pInfo) > SHO_RELRO_LAST) { |
| break; |
| } |
| } |
| |
| // align the first non-relro section to page boundary |
| uint64_t offset = sect_table[idx]->offset(); |
| alignAddress(offset, commonPageSize(pInfo)); |
| sect_table[idx]->setOffset(offset); |
| |
| // set up remaining section's offset |
| for (++idx; idx < pOutput.context()->numOfSections(); ++idx) { |
| uint64_t offset; |
| size_t prev_idx = idx - 1; |
| if (LDFileFormat::BSS == sect_table[prev_idx]->kind()) |
| offset = sect_table[prev_idx]->offset(); |
| else |
| offset = sect_table[prev_idx]->offset() + sect_table[prev_idx]->size(); |
| |
| alignAddress(offset, sect_table[idx]->align()); |
| sect_table[idx]->setOffset(offset); |
| } |
| } // relro |
| |
| 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 = pOutput.context()->sectEnd(); |
| for (sect = pOutput.context()->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(abiPageSize(pInfo)); |
| |
| // check if this segment needs padding |
| padding = 0; |
| if (((*sect)->offset() & (abiPageSize(pInfo) - 1)) != 0) |
| padding = abiPageSize(pInfo); |
| } |
| |
| assert(NULL != load_seg); |
| load_seg->addSection((*sect)); |
| if (cur_seg_flag != prev_seg_flag) |
| load_seg->updateFlag(cur_seg_flag); |
| |
| if (LDFileFormat::Null != (*sect)->kind()) |
| (*sect)->setAddr(segmentStartAddr(pOutput, pInfo) + |
| (*sect)->offset() + |
| padding); |
| |
| prev_seg_flag = cur_seg_flag; |
| } |
| |
| // make PT_DYNAMIC |
| if (file_format->hasDynamic()) { |
| ELFSegment* dyn_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_DYNAMIC, |
| llvm::ELF::PF_R | |
| llvm::ELF::PF_W); |
| dyn_seg->addSection(&file_format->getDynamic()); |
| } |
| |
| if (pInfo.options().hasRelro()) { |
| // make PT_GNU_RELRO |
| ELFSegment* relro_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_GNU_RELRO); |
| for (LDContext::sect_iterator sect = pOutput.context()->sectBegin(); |
| sect != pOutput.context()->sectEnd(); ++sect) { |
| unsigned int order = getSectionOrder(pOutput, **sect, pInfo); |
| if (SHO_RELRO_LOCAL == order || |
| SHO_RELRO == order || |
| SHO_RELRO_LAST == order) { |
| relro_seg->addSection(*sect); |
| } |
| } |
| } |
| |
| // make PT_GNU_EH_FRAME |
| if (file_format->hasEhFrameHdr()) { |
| ELFSegment* eh_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_GNU_EH_FRAME); |
| eh_seg->addSection(&file_format->getEhFrameHdr()); |
| } |
| } |
| |
| /// setupProgramHdrs - set up the attributes of segments |
| void GNULDBackend:: setupProgramHdrs(const Output& pOutput, const MCLDInfo& pInfo) |
| { |
| // update segment info |
| 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(segmentStartAddr(pOutput, pInfo) + offset); |
| segment.setPaddr(segment.vaddr()); |
| segment.setFilesz(numOfSegments() * phdr_size); |
| segment.setMemsz(numOfSegments() * phdr_size); |
| segment.setAlign(bitclass() / 8); |
| continue; |
| } |
| |
| // bypass if there is no section in this segment (e.g., PT_GNU_STACK) |
| if (segment.numOfSections() == 0) |
| continue; |
| |
| segment.setOffset(segment.getFirstSection()->offset()); |
| if (llvm::ELF::PT_LOAD == segment.type() && |
| LDFileFormat::Null == segment.getFirstSection()->kind()) |
| segment.setVaddr(segmentStartAddr(pOutput, pInfo)); |
| else |
| segment.setVaddr(segment.getFirstSection()->addr()); |
| segment.setPaddr(segment.vaddr()); |
| |
| const LDSection* last_sect = segment.getLastSection(); |
| assert(NULL != last_sect); |
| uint64_t 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()); |
| } |
| } |
| |
| /// createGNUStackInfo - create an output GNU stack section or segment if needed |
| /// @ref gold linker: layout.cc:2608 |
| void GNULDBackend::createGNUStackInfo(const Output& pOutput, |
| const MCLDInfo& pInfo, |
| MCLinker& pLinker) |
| { |
| uint32_t flag = 0x0; |
| if (pInfo.options().hasStackSet()) { |
| // 1. check the command line option (-z execstack or -z noexecstack) |
| if (pInfo.options().hasExecStack()) |
| flag = llvm::ELF::SHF_EXECINSTR; |
| } else { |
| // 2. check the stack info from the input objects |
| size_t object_count = 0, stack_note_count = 0; |
| mcld::InputTree::const_bfs_iterator input, inEnd = pInfo.inputs().bfs_end(); |
| for (input=pInfo.inputs().bfs_begin(); input!=inEnd; ++input) { |
| if ((*input)->type() == Input::Object) { |
| ++object_count; |
| const LDSection* sect = (*input)->context()->getSection( |
| ".note.GNU-stack"); |
| if (NULL != sect) { |
| ++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 (isDefaultExecStack()) |
| flag = llvm::ELF::SHF_EXECINSTR; |
| } |
| |
| if (pOutput.type() != Output::Object) |
| m_ELFSegmentTable.produce(llvm::ELF::PT_GNU_STACK, |
| llvm::ELF::PF_R | |
| llvm::ELF::PF_W | |
| getSegmentFlag(flag)); |
| else |
| pLinker.getOrCreateOutputSectHdr(".note.GNU-stack", |
| LDFileFormat::Note, |
| llvm::ELF::SHT_PROGBITS, |
| flag); |
| } |
| |
| /// 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); |
| |
| if (pLDInfo.options().hasEhFrameHdr()) { |
| // init EhFrameHdr and size the output section |
| ELFFileFormat* format = getOutputFormat(pOutput); |
| assert(NULL != getEhFrame()); |
| m_pEhFrameHdr = new EhFrameHdr(*getEhFrame(), |
| format->getEhFrame(), |
| format->getEhFrameHdr()); |
| m_pEhFrameHdr->sizeOutput(); |
| } |
| } |
| |
| /// postLayout - Backend can do any needed modification after layout |
| void GNULDBackend::postLayout(const Output& pOutput, |
| const MCLDInfo& pInfo, |
| MCLinker& pLinker) |
| { |
| // 1. emit program headers |
| if (pOutput.type() != Output::Object) { |
| // 1.1 create program headers |
| createProgramHdrs(pLinker.getLDInfo().output(), pInfo); |
| } |
| |
| // 1.2 create special GNU Stack note section or segment |
| createGNUStackInfo(pOutput, pInfo, pLinker); |
| |
| if (pOutput.type() != Output::Object) { |
| // 1.3 set up the attributes of program headers |
| setupProgramHdrs(pOutput, pInfo); |
| } |
| |
| // 2. target specific post layout |
| doPostLayout(pOutput, pInfo, pLinker); |
| } |
| |
| void GNULDBackend::postProcessing(const Output& pOutput, |
| const MCLDInfo& pInfo, |
| MCLinker& pLinker) |
| { |
| if (pInfo.options().hasEhFrameHdr()) { |
| // emit eh_frame_hdr |
| if (bitclass() == 32) |
| m_pEhFrameHdr->emitOutput<32>(pLinker.getLDInfo().output(), |
| 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() || Output::Exec == pOutput.type()) |
| if (pSymbol.resolveInfo()->visibility() == ResolveInfo::Default || |
| pSymbol.resolveInfo()->visibility() == ResolveInfo::Protected) |
| return true; |
| return false; |
| } |
| |
| /// commonPageSize - the common page size of the target machine. |
| /// @ref gold linker: target.h:135 |
| uint64_t GNULDBackend::commonPageSize(const MCLDInfo& pInfo) const |
| { |
| if (pInfo.options().commPageSize() > 0) |
| return std::min(pInfo.options().commPageSize(), abiPageSize(pInfo)); |
| else |
| return std::min(static_cast<uint64_t>(0x1000), abiPageSize(pInfo)); |
| } |
| |
| /// abiPageSize - the abi page size of the target machine. |
| /// @ref gold linker: target.h:125 |
| uint64_t GNULDBackend::abiPageSize(const MCLDInfo& pInfo) const |
| { |
| if (pInfo.options().maxPageSize() > 0) |
| return pInfo.options().maxPageSize(); |
| else |
| return static_cast<uint64_t>(0x1000); |
| } |
| |
| /// isOutputPIC - return whether the output is position-independent |
| bool GNULDBackend::isOutputPIC(const Output& pOutput, |
| const MCLDInfo& pInfo) const |
| { |
| if (Output::DynObj == pOutput.type() || pInfo.options().isPIE()) |
| return true; |
| return false; |
| } |
| |
| /// isStaticLink - return whether we're doing static link |
| bool GNULDBackend::isStaticLink(const Output& pOutput, |
| const MCLDInfo& pInfo) const |
| { |
| InputTree::const_iterator it = pInfo.inputs().begin(); |
| if (!isOutputPIC(pOutput, pInfo) && (*it)->attribute()->isStatic()) |
| return true; |
| return false; |
| } |
| |
| /// isSymbolPreemtible - whether the symbol can be preemted by other |
| /// link unit |
| /// @ref Google gold linker, symtab.h:551 |
| bool GNULDBackend::isSymbolPreemptible(const ResolveInfo& pSym, |
| const MCLDInfo& pLDInfo, |
| const Output& pOutput) const |
| { |
| if (pSym.other() != ResolveInfo::Default) |
| return false; |
| |
| if (Output::DynObj != pOutput.type()) |
| return false; |
| |
| if (pLDInfo.options().Bsymbolic()) |
| return false; |
| |
| return true; |
| } |
| |
| /// symbolNeedsPLT - return whether the symbol needs a PLT entry |
| /// @ref Google gold linker, symtab.h:596 |
| bool GNULDBackend::symbolNeedsPLT(const ResolveInfo& pSym, |
| const MCLDInfo& pLDInfo, |
| const Output& pOutput) const |
| { |
| if (pSym.isUndef() && !pSym.isDyn() && pOutput.type() != Output::DynObj) |
| 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 (isStaticLink(pOutput, pLDInfo) || pLDInfo.options().isPIE()) |
| return false; |
| |
| return (pSym.isDyn() || |
| pSym.isUndef() || |
| isSymbolPreemptible(pSym, pLDInfo, pOutput)); |
| } |
| |
| /// symbolNeedsDynRel - return whether the symbol needs a dynamic relocation |
| /// @ref Google gold linker, symtab.h:645 |
| bool GNULDBackend::symbolNeedsDynRel(const ResolveInfo& pSym, |
| bool pSymHasPLT, |
| const MCLDInfo& pLDInfo, |
| const Output& pOutput, |
| 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() && (Output::Exec == pOutput.type())) |
| return false; |
| if (pSym.isAbsolute()) |
| return false; |
| if (isOutputPIC(pOutput, pLDInfo) && isAbsReloc) |
| return true; |
| if (pSymHasPLT && ResolveInfo::Function == pSym.type()) |
| return false; |
| if (!isOutputPIC(pOutput, pLDInfo) && pSymHasPLT) |
| return false; |
| if (pSym.isDyn() || pSym.isUndef() || |
| isSymbolPreemptible(pSym, pLDInfo, pOutput)) |
| return true; |
| |
| return false; |
| } |
| |
| /// symbolNeedsCopyReloc - return whether the symbol needs a copy relocation |
| bool GNULDBackend::symbolNeedsCopyReloc(const Layout& pLayout, |
| const Relocation& pReloc, |
| const ResolveInfo& pSym, |
| const MCLDInfo& pLDInfo, |
| const Output& pOutput) const |
| { |
| // only the reference from dynamic executable to non-function symbol in |
| // the dynamic objects may need copy relocation |
| if (isOutputPIC(pOutput, pLDInfo) || |
| !pSym.isDyn() || |
| pSym.type() == ResolveInfo::Function || |
| pSym.size() == 0) |
| return false; |
| |
| // check if the option -z nocopyreloc is given |
| if (pLDInfo.options().hasNoCopyReloc()) |
| return false; |
| |
| // TODO: Is this check necessary? |
| // if relocation target place is readonly, a copy relocation is needed |
| if ((pLayout.getOutputLDSection(*pReloc.targetRef().frag())->flag() & |
| llvm::ELF::SHF_WRITE) == 0) |
| return true; |
| |
| return false; |
| } |
| |