| //===- X86LDBackend.cpp ---------------------------------------------------===// |
| // |
| // The MCLinker Project |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| #include "X86.h" |
| #include "X86ELFDynamic.h" |
| #include "X86LDBackend.h" |
| #include "X86Relocator.h" |
| #include "X86GNUInfo.h" |
| |
| #include <llvm/ADT/Triple.h> |
| #include <llvm/Support/Casting.h> |
| |
| #include <mcld/LinkerConfig.h> |
| #include <mcld/IRBuilder.h> |
| #include <mcld/Fragment/FillFragment.h> |
| #include <mcld/Fragment/RegionFragment.h> |
| #include <mcld/Fragment/FragmentLinker.h> |
| #include <mcld/Support/MemoryRegion.h> |
| #include <mcld/Support/MsgHandling.h> |
| #include <mcld/Support/TargetRegistry.h> |
| #include <mcld/Object/ObjectBuilder.h> |
| |
| #include <cstring> |
| |
| using namespace mcld; |
| |
| //===----------------------------------------------------------------------===// |
| // X86GNULDBackend |
| //===----------------------------------------------------------------------===// |
| X86GNULDBackend::X86GNULDBackend(const LinkerConfig& pConfig, |
| GNUInfo* pInfo, |
| Relocation::Type pCopyRel) |
| : GNULDBackend(pConfig, pInfo), |
| m_pRelocator(NULL), |
| m_pPLT(NULL), |
| m_pRelDyn(NULL), |
| m_pRelPLT(NULL), |
| m_pDynamic(NULL), |
| m_pGOTSymbol(NULL), |
| m_CopyRel(pCopyRel) |
| { |
| Triple::ArchType arch = pConfig.targets().triple().getArch(); |
| assert (arch == Triple::x86 || arch == Triple::x86_64); |
| if (arch == Triple::x86 || |
| pConfig.targets().triple().getEnvironment() == Triple::GNUX32) { |
| m_RelEntrySize = 8; |
| m_RelaEntrySize = 12; |
| if (arch == Triple::x86) |
| m_PointerRel = llvm::ELF::R_386_32; |
| else |
| m_PointerRel = llvm::ELF::R_X86_64_32; |
| } |
| else { |
| m_RelEntrySize = 16; |
| m_RelaEntrySize = 24; |
| m_PointerRel = llvm::ELF::R_X86_64_64; |
| } |
| } |
| |
| X86GNULDBackend::~X86GNULDBackend() |
| { |
| delete m_pRelocator; |
| delete m_pPLT; |
| delete m_pRelDyn; |
| delete m_pRelPLT; |
| delete m_pDynamic; |
| } |
| |
| Relocator* X86GNULDBackend::getRelocator() |
| { |
| assert(NULL != m_pRelocator); |
| return m_pRelocator; |
| } |
| |
| void X86GNULDBackend::doPreLayout(IRBuilder& pBuilder) |
| { |
| // initialize .dynamic data |
| if (!config().isCodeStatic() && NULL == m_pDynamic) |
| m_pDynamic = new X86ELFDynamic(*this, config()); |
| |
| // set .got.plt and .got sizes |
| // when building shared object, the .got section is must |
| if (LinkerConfig::Object != config().codeGenType()) { |
| setGOTSectionSize(pBuilder); |
| |
| // set .plt size |
| if (m_pPLT->hasPLT1()) |
| m_pPLT->finalizeSectionSize(); |
| |
| // set .rel.dyn/.rela.dyn size |
| if (!m_pRelDyn->empty()) { |
| assert(!config().isCodeStatic() && |
| "static linkage should not result in a dynamic relocation section"); |
| setRelDynSize(); |
| } |
| // set .rel.plt/.rela.plt size |
| if (!m_pRelPLT->empty()) { |
| assert(!config().isCodeStatic() && |
| "static linkage should not result in a dynamic relocation section"); |
| setRelPLTSize(); |
| } |
| } |
| } |
| |
| void X86GNULDBackend::doPostLayout(Module& pModule, |
| IRBuilder& pBuilder) |
| { |
| } |
| |
| /// dynamic - the dynamic section of the target machine. |
| /// Use co-variant return type to return its own dynamic section. |
| X86ELFDynamic& X86GNULDBackend::dynamic() |
| { |
| assert(NULL != m_pDynamic); |
| return *m_pDynamic; |
| } |
| |
| /// dynamic - the dynamic section of the target machine. |
| /// Use co-variant return type to return its own dynamic section. |
| const X86ELFDynamic& X86GNULDBackend::dynamic() const |
| { |
| assert(NULL != m_pDynamic); |
| return *m_pDynamic; |
| } |
| |
| void X86GNULDBackend::defineGOTSymbol(IRBuilder& pBuilder, |
| Fragment& pFrag) |
| { |
| // define symbol _GLOBAL_OFFSET_TABLE_ |
| if (m_pGOTSymbol != NULL) { |
| pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>( |
| "_GLOBAL_OFFSET_TABLE_", |
| ResolveInfo::Object, |
| ResolveInfo::Define, |
| ResolveInfo::Local, |
| 0x0, // size |
| 0x0, // value |
| FragmentRef::Create(pFrag, 0x0), |
| ResolveInfo::Hidden); |
| } |
| else { |
| m_pGOTSymbol = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>( |
| "_GLOBAL_OFFSET_TABLE_", |
| ResolveInfo::Object, |
| ResolveInfo::Define, |
| ResolveInfo::Local, |
| 0x0, // size |
| 0x0, // value |
| FragmentRef::Create(pFrag, 0x0), |
| ResolveInfo::Hidden); |
| } |
| } |
| |
| void X86GNULDBackend::addCopyReloc(ResolveInfo& pSym) |
| { |
| Relocation& rel_entry = *m_pRelDyn->consumeEntry(); |
| rel_entry.setType(m_CopyRel); |
| assert(pSym.outSymbol()->hasFragRef()); |
| rel_entry.targetRef().assign(*pSym.outSymbol()->fragRef()); |
| rel_entry.setSymInfo(&pSym); |
| } |
| |
| /// defineSymbolforCopyReloc |
| /// For a symbol needing copy relocation, define a copy symbol in the BSS |
| /// section and all other reference to this symbol should refer to this |
| /// copy. |
| /// @note This is executed at `scan relocation' stage. |
| LDSymbol& X86GNULDBackend::defineSymbolforCopyReloc(IRBuilder& pBuilder, |
| const ResolveInfo& pSym) |
| { |
| // get or create corresponding BSS LDSection |
| LDSection* bss_sect_hdr = NULL; |
| ELFFileFormat* file_format = getOutputFormat(); |
| if (ResolveInfo::ThreadLocal == pSym.type()) |
| bss_sect_hdr = &file_format->getTBSS(); |
| else |
| bss_sect_hdr = &file_format->getBSS(); |
| |
| // get or create corresponding BSS SectionData |
| assert(NULL != bss_sect_hdr); |
| SectionData* bss_section = NULL; |
| if (bss_sect_hdr->hasSectionData()) |
| bss_section = bss_sect_hdr->getSectionData(); |
| else |
| bss_section = IRBuilder::CreateSectionData(*bss_sect_hdr); |
| |
| // Determine the alignment by the symbol value |
| // FIXME: here we use the largest alignment |
| uint32_t addralign = config().targets().bitclass() / 8; |
| |
| // allocate space in BSS for the copy symbol |
| Fragment* frag = new FillFragment(0x0, 1, pSym.size()); |
| uint64_t size = ObjectBuilder::AppendFragment(*frag, |
| *bss_section, |
| addralign); |
| bss_sect_hdr->setSize(bss_sect_hdr->size() + size); |
| |
| // change symbol binding to Global if it's a weak symbol |
| ResolveInfo::Binding binding = (ResolveInfo::Binding)pSym.binding(); |
| if (binding == ResolveInfo::Weak) |
| binding = ResolveInfo::Global; |
| |
| // Define the copy symbol in the bss section and resolve it |
| LDSymbol* cpy_sym = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>( |
| pSym.name(), |
| (ResolveInfo::Type)pSym.type(), |
| ResolveInfo::Define, |
| binding, |
| pSym.size(), // size |
| 0x0, // value |
| FragmentRef::Create(*frag, 0x0), |
| (ResolveInfo::Visibility)pSym.other()); |
| |
| return *cpy_sym; |
| } |
| |
| void X86GNULDBackend::scanRelocation(Relocation& pReloc, |
| IRBuilder& pLinker, |
| Module& pModule, |
| LDSection& pSection) |
| { |
| if (LinkerConfig::Object == config().codeGenType()) |
| return; |
| // rsym - The relocation target symbol |
| ResolveInfo* rsym = pReloc.symInfo(); |
| assert(NULL != rsym && |
| "ResolveInfo of relocation not set while scanRelocation"); |
| |
| pReloc.updateAddend(); |
| assert(NULL != pSection.getLink()); |
| if (0 == (pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC)) |
| return; |
| |
| // Scan relocation type to determine if the GOT/PLT/Dynamic Relocation |
| // entries should be created. |
| if (rsym->isLocal()) // rsym is local |
| scanLocalReloc(pReloc, pLinker, pModule, pSection); |
| else // rsym is external |
| scanGlobalReloc(pReloc, pLinker, pModule, pSection); |
| |
| // check if we should issue undefined reference for the relocation target |
| // symbol |
| if (rsym->isUndef() && !rsym->isDyn() && !rsym->isWeak() && !rsym->isNull()) |
| fatal(diag::undefined_reference) << rsym->name(); |
| } |
| |
| uint64_t X86GNULDBackend::emitSectionData(const LDSection& pSection, |
| MemoryRegion& pRegion) const |
| { |
| assert(pRegion.size() && "Size of MemoryRegion is zero!"); |
| |
| const ELFFileFormat* FileFormat = getOutputFormat(); |
| assert(FileFormat && |
| "ELFFileFormat is NULL in X86GNULDBackend::emitSectionData!"); |
| |
| unsigned int EntrySize = 0; |
| uint64_t RegionSize = 0; |
| |
| if (&pSection == &(FileFormat->getPLT())) { |
| assert(m_pPLT && "emitSectionData failed, m_pPLT is NULL!"); |
| |
| unsigned char* buffer = pRegion.getBuffer(); |
| |
| m_pPLT->applyPLT0(); |
| m_pPLT->applyPLT1(); |
| X86PLT::iterator it = m_pPLT->begin(); |
| unsigned int plt0_size = llvm::cast<PLTEntryBase>((*it)).size(); |
| |
| memcpy(buffer, llvm::cast<PLTEntryBase>((*it)).getValue(), plt0_size); |
| RegionSize += plt0_size; |
| ++it; |
| |
| PLTEntryBase* plt1 = 0; |
| X86PLT::iterator ie = m_pPLT->end(); |
| while (it != ie) { |
| plt1 = &(llvm::cast<PLTEntryBase>(*it)); |
| EntrySize = plt1->size(); |
| memcpy(buffer + RegionSize, plt1->getValue(), EntrySize); |
| RegionSize += EntrySize; |
| ++it; |
| } |
| } |
| |
| else if (&pSection == &(FileFormat->getGOT())) { |
| RegionSize += emitGOTSectionData(pRegion); |
| } |
| |
| else if (&pSection == &(FileFormat->getGOTPLT())) { |
| RegionSize += emitGOTPLTSectionData(pRegion, FileFormat); |
| } |
| |
| else { |
| fatal(diag::unrecognized_output_sectoin) |
| << pSection.name() |
| << "[email protected]"; |
| } |
| return RegionSize; |
| } |
| |
| X86PLT& X86GNULDBackend::getPLT() |
| { |
| assert(NULL != m_pPLT && "PLT section not exist"); |
| return *m_pPLT; |
| } |
| |
| const X86PLT& X86GNULDBackend::getPLT() const |
| { |
| assert(NULL != m_pPLT && "PLT section not exist"); |
| return *m_pPLT; |
| } |
| |
| OutputRelocSection& X86GNULDBackend::getRelDyn() |
| { |
| assert(NULL != m_pRelDyn && ".rel.dyn/.rela.dyn section not exist"); |
| return *m_pRelDyn; |
| } |
| |
| const OutputRelocSection& X86GNULDBackend::getRelDyn() const |
| { |
| assert(NULL != m_pRelDyn && ".rel.dyn/.rela.dyn section not exist"); |
| return *m_pRelDyn; |
| } |
| |
| OutputRelocSection& X86GNULDBackend::getRelPLT() |
| { |
| assert(NULL != m_pRelPLT && ".rel.plt/.rela.plt section not exist"); |
| return *m_pRelPLT; |
| } |
| |
| const OutputRelocSection& X86GNULDBackend::getRelPLT() const |
| { |
| assert(NULL != m_pRelPLT && ".rel.plt/.rela.plt section not exist"); |
| return *m_pRelPLT; |
| } |
| |
| unsigned int |
| X86GNULDBackend::getTargetSectionOrder(const LDSection& pSectHdr) const |
| { |
| const ELFFileFormat* file_format = getOutputFormat(); |
| |
| if (&pSectHdr == &file_format->getGOT()) { |
| if (config().options().hasNow()) |
| return SHO_RELRO; |
| return SHO_RELRO_LAST; |
| } |
| |
| if (&pSectHdr == &file_format->getGOTPLT()) { |
| if (config().options().hasNow()) |
| return SHO_RELRO; |
| return SHO_NON_RELRO_FIRST; |
| } |
| |
| if (&pSectHdr == &file_format->getPLT()) |
| return SHO_PLT; |
| |
| return SHO_UNDEFINED; |
| } |
| |
| void X86GNULDBackend::initTargetSymbols(IRBuilder& pBuilder, Module& pModule) |
| { |
| if (LinkerConfig::Object != config().codeGenType()) { |
| // Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the |
| // same name in input |
| m_pGOTSymbol = |
| pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>( |
| "_GLOBAL_OFFSET_TABLE_", |
| ResolveInfo::Object, |
| ResolveInfo::Define, |
| ResolveInfo::Local, |
| 0x0, // size |
| 0x0, // value |
| FragmentRef::Null(), // FragRef |
| ResolveInfo::Hidden); |
| } |
| } |
| |
| /// finalizeSymbol - finalize the symbol value |
| bool X86GNULDBackend::finalizeTargetSymbols() |
| { |
| return true; |
| } |
| |
| /// doCreateProgramHdrs - backend can implement this function to create the |
| /// target-dependent segments |
| void X86GNULDBackend::doCreateProgramHdrs(Module& pModule) |
| { |
| // TODO |
| } |
| |
| X86_32GNULDBackend::X86_32GNULDBackend(const LinkerConfig& pConfig, |
| GNUInfo* pInfo) |
| : X86GNULDBackend(pConfig, pInfo, llvm::ELF::R_386_COPY), |
| m_pGOT (NULL), |
| m_pGOTPLT (NULL) { |
| } |
| |
| X86_32GNULDBackend::~X86_32GNULDBackend() |
| { |
| delete m_pGOT; |
| delete m_pGOTPLT; |
| } |
| |
| bool X86_32GNULDBackend::initRelocator() |
| { |
| if (NULL == m_pRelocator) { |
| m_pRelocator = new X86_32Relocator(*this); |
| } |
| return true; |
| } |
| |
| void X86_32GNULDBackend::scanLocalReloc(Relocation& pReloc, |
| IRBuilder& pBuilder, |
| Module& pModule, |
| LDSection& pSection) |
| { |
| // rsym - The relocation target symbol |
| ResolveInfo* rsym = pReloc.symInfo(); |
| |
| switch(pReloc.type()){ |
| |
| case llvm::ELF::R_386_32: |
| case llvm::ELF::R_386_16: |
| case llvm::ELF::R_386_8: |
| // If buiding PIC object (shared library or PIC executable), |
| // a dynamic relocations with RELATIVE type to this location is needed. |
| // Reserve an entry in .rel.dyn |
| if (config().isCodeIndep()) { |
| m_pRelDyn->reserveEntry(); |
| // set Rel bit |
| rsym->setReserved(rsym->reserved() | ReserveRel); |
| checkAndSetHasTextRel(*pSection.getLink()); |
| } |
| return; |
| |
| case llvm::ELF::R_386_GOTOFF: |
| case llvm::ELF::R_386_GOTPC: |
| // FIXME: A GOT section is needed |
| return; |
| |
| case llvm::ELF::R_386_GOT32: |
| // Symbol needs GOT entry, reserve entry in .got |
| // return if we already create GOT for this symbol |
| if (rsym->reserved() & (ReserveGOT | GOTRel)) |
| return; |
| // FIXME: check STT_GNU_IFUNC symbol |
| m_pGOT->reserve(); |
| |
| // If the GOT is used in statically linked binaries, |
| // the GOT entry is enough and no relocation is needed. |
| if (config().isCodeStatic()) { |
| rsym->setReserved(rsym->reserved() | ReserveGOT); |
| return; |
| } |
| // If building shared object or the symbol is undefined, a dynamic |
| // relocation is needed to relocate this GOT entry. Reserve an |
| // entry in .rel.dyn |
| if (LinkerConfig::DynObj == |
| config().codeGenType() || rsym->isUndef() || rsym->isDyn()) { |
| m_pRelDyn->reserveEntry(); |
| // set GOTRel bit |
| rsym->setReserved(rsym->reserved() | GOTRel); |
| return; |
| } |
| // set GOT bit |
| rsym->setReserved(rsym->reserved() | ReserveGOT); |
| return; |
| |
| case llvm::ELF::R_386_PC32: |
| case llvm::ELF::R_386_PC16: |
| case llvm::ELF::R_386_PC8: |
| return; |
| |
| case llvm::ELF::R_386_TLS_GD: { |
| // FIXME: no linker optimization for TLS relocation |
| if (rsym->reserved() & GOTRel) |
| return; |
| m_pGOT->reserve(2); |
| // reserve an rel entry |
| m_pRelDyn->reserveEntry(); |
| // set GOTRel bit |
| rsym->setReserved(rsym->reserved() | GOTRel); |
| // define the section symbol for .tdata or .tbss |
| // the target symbol of the created dynamic relocation should be the |
| // section symbol of the section which this symbol defined. so we |
| // need to define that section symbol here |
| ELFFileFormat* file_format = getOutputFormat(); |
| const LDSection* sym_sect = |
| &rsym->outSymbol()->fragRef()->frag()->getParent()->getSection(); |
| if (&file_format->getTData() == sym_sect) { |
| if (NULL == f_pTDATA) |
| f_pTDATA = pModule.getSectionSymbolSet().get(*sym_sect); |
| } |
| else if (&file_format->getTBSS() == sym_sect || rsym->isCommon()) { |
| if (NULL == f_pTBSS) |
| f_pTBSS = pModule.getSectionSymbolSet().get(*sym_sect); |
| } |
| else |
| error(diag::invalid_tls) << rsym->name() << sym_sect->name(); |
| return; |
| } |
| |
| case llvm::ELF::R_386_TLS_LDM: |
| getTLSModuleID(); |
| return; |
| |
| case llvm::ELF::R_386_TLS_LDO_32: |
| return; |
| |
| case llvm::ELF::R_386_TLS_IE: |
| setHasStaticTLS(); |
| // if buildint shared object, a RELATIVE dynamic relocation is needed |
| if (LinkerConfig::DynObj == config().codeGenType()) { |
| m_pRelDyn->reserveEntry(); |
| rsym->setReserved(rsym->reserved() | ReserveRel); |
| checkAndSetHasTextRel(*pSection.getLink()); |
| } else { |
| // for local sym, we can convert ie to le if not building shared object |
| convertTLSIEtoLE(pReloc, pSection); |
| return; |
| } |
| if (rsym->reserved() & GOTRel) |
| return; |
| // reserve got and dyn relocation entries for tp-relative offset |
| m_pGOT->reserve(); |
| m_pRelDyn->reserveEntry(); |
| // set GOTRel bit |
| rsym->setReserved(rsym->reserved() | GOTRel); |
| m_pRelDyn->addSymbolToDynSym(*rsym->outSymbol()); |
| return; |
| |
| case llvm::ELF::R_386_TLS_GOTIE: |
| setHasStaticTLS(); |
| if (rsym->reserved() & GOTRel) |
| return; |
| // reserve got and dyn relocation entries for tp-relative offset |
| m_pGOT->reserve(); |
| m_pRelDyn->reserveEntry(); |
| // set GOTRel bit |
| rsym->setReserved(rsym->reserved() | GOTRel); |
| m_pRelDyn->addSymbolToDynSym(*rsym->outSymbol()); |
| return; |
| |
| case llvm::ELF::R_386_TLS_LE: |
| case llvm::ELF::R_386_TLS_LE_32: |
| setHasStaticTLS(); |
| // if buildint shared object, a dynamic relocation is needed |
| if (LinkerConfig::DynObj == config().codeGenType()) { |
| m_pRelDyn->reserveEntry(); |
| rsym->setReserved(rsym->reserved() | ReserveRel); |
| checkAndSetHasTextRel(*pSection.getLink()); |
| // the target symbol of the dynamic relocation is rsym, so we need to |
| // emit it into .dynsym |
| assert(NULL != rsym->outSymbol()); |
| m_pRelDyn->addSymbolToDynSym(*rsym->outSymbol()); |
| } |
| return; |
| |
| default: |
| fatal(diag::unsupported_relocation) << (int)pReloc.type() |
| << "[email protected]"; |
| break; |
| } // end switch |
| } |
| |
| void X86_32GNULDBackend::scanGlobalReloc(Relocation& pReloc, |
| IRBuilder& pBuilder, |
| Module& pModule, |
| LDSection& pSection) |
| { |
| // rsym - The relocation target symbol |
| ResolveInfo* rsym = pReloc.symInfo(); |
| |
| switch(pReloc.type()) { |
| case llvm::ELF::R_386_32: |
| case llvm::ELF::R_386_16: |
| case llvm::ELF::R_386_8: |
| // Absolute relocation type, symbol may needs PLT entry or |
| // dynamic relocation entry |
| if (symbolNeedsPLT(*rsym)) { |
| // create plt for this symbol if it does not have one |
| if (!(rsym->reserved() & ReservePLT)){ |
| // Symbol needs PLT entry, we need to reserve a PLT entry |
| // and the corresponding GOT and dynamic relocation entry |
| // in .got and .rel.plt. (GOT entry will be reserved simultaneously |
| // when calling X86PLT->reserveEntry()) |
| m_pPLT->reserveEntry(); |
| m_pGOTPLT->reserve(); |
| m_pRelPLT->reserveEntry(); |
| // set PLT bit |
| rsym->setReserved(rsym->reserved() | ReservePLT); |
| } |
| } |
| |
| if (symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT), true)) { |
| // symbol needs dynamic relocation entry, reserve an entry in .rel.dyn |
| m_pRelDyn->reserveEntry(); |
| if (symbolNeedsCopyReloc(pReloc, *rsym)) { |
| LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym); |
| addCopyReloc(*cpy_sym.resolveInfo()); |
| } |
| else { |
| // set Rel bit |
| rsym->setReserved(rsym->reserved() | ReserveRel); |
| checkAndSetHasTextRel(pSection); |
| } |
| } |
| return; |
| |
| case llvm::ELF::R_386_GOTOFF: |
| case llvm::ELF::R_386_GOTPC: { |
| // FIXME: A GOT section is needed |
| return; |
| } |
| |
| case llvm::ELF::R_386_PLT32: |
| // A PLT entry is needed when building shared library |
| |
| // return if we already create plt for this symbol |
| if (rsym->reserved() & ReservePLT) |
| return; |
| |
| // if the symbol's value can be decided at link time, then no need plt |
| if (symbolFinalValueIsKnown(*rsym)) |
| return; |
| |
| // if symbol is defined in the ouput file and it's not |
| // preemptible, no need plt |
| if (rsym->isDefine() && !rsym->isDyn() && |
| !isSymbolPreemptible(*rsym)) { |
| return; |
| } |
| |
| // Symbol needs PLT entry, we need to reserve a PLT entry |
| // and the corresponding GOT and dynamic relocation entry |
| // in .got and .rel.plt. (GOT entry will be reserved simultaneously |
| // when calling X86PLT->reserveEntry()) |
| m_pPLT->reserveEntry(); |
| m_pGOTPLT->reserve(); |
| m_pRelPLT->reserveEntry(); |
| // set PLT bit |
| rsym->setReserved(rsym->reserved() | ReservePLT); |
| return; |
| |
| case llvm::ELF::R_386_GOT32: |
| // Symbol needs GOT entry, reserve entry in .got |
| // return if we already create GOT for this symbol |
| if (rsym->reserved() & (ReserveGOT | GOTRel)) |
| return; |
| m_pGOT->reserve(); |
| |
| // If the GOT is used in statically linked binaries, |
| // the GOT entry is enough and no relocation is needed. |
| if (config().isCodeStatic()) { |
| rsym->setReserved(rsym->reserved() | ReserveGOT); |
| return; |
| } |
| // If building shared object or the symbol is undefined, a dynamic |
| // relocation is needed to relocate this GOT entry. Reserve an |
| // entry in .rel.dyn |
| if (LinkerConfig::DynObj == |
| config().codeGenType() || rsym->isUndef() || rsym->isDyn()) { |
| m_pRelDyn->reserveEntry(); |
| // set GOTRel bit |
| rsym->setReserved(rsym->reserved() | GOTRel); |
| return; |
| } |
| // set GOT bit |
| rsym->setReserved(rsym->reserved() | ReserveGOT); |
| return; |
| |
| case llvm::ELF::R_386_PC32: |
| case llvm::ELF::R_386_PC16: |
| case llvm::ELF::R_386_PC8: |
| |
| if (symbolNeedsPLT(*rsym) && |
| LinkerConfig::DynObj != config().codeGenType()) { |
| // create plt for this symbol if it does not have one |
| if (!(rsym->reserved() & ReservePLT)){ |
| // Symbol needs PLT entry, we need to reserve a PLT entry |
| // and the corresponding GOT and dynamic relocation entry |
| // in .got and .rel.plt. (GOT entry will be reserved simultaneously |
| // when calling X86PLT->reserveEntry()) |
| m_pPLT->reserveEntry(); |
| m_pGOTPLT->reserve(); |
| m_pRelPLT->reserveEntry(); |
| // set PLT bit |
| rsym->setReserved(rsym->reserved() | ReservePLT); |
| } |
| } |
| |
| if (symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT), false)) { |
| // symbol needs dynamic relocation entry, reserve an entry in .rel.dyn |
| m_pRelDyn->reserveEntry(); |
| if (symbolNeedsCopyReloc(pReloc, *rsym)) { |
| LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym); |
| addCopyReloc(*cpy_sym.resolveInfo()); |
| } |
| else { |
| // set Rel bit |
| rsym->setReserved(rsym->reserved() | ReserveRel); |
| checkAndSetHasTextRel(pSection); |
| } |
| } |
| return; |
| |
| case llvm::ELF::R_386_TLS_GD: { |
| // FIXME: no linker optimization for TLS relocation |
| if (rsym->reserved() & GOTRel) |
| return; |
| // reserve two pairs of got entry and dynamic relocation |
| m_pGOT->reserve(2); |
| m_pRelDyn->reserveEntry(2); |
| // set GOTRel bit |
| rsym->setReserved(rsym->reserved() | GOTRel); |
| return; |
| } |
| |
| case llvm::ELF::R_386_TLS_LDM: |
| getTLSModuleID(); |
| return; |
| |
| case llvm::ELF::R_386_TLS_LDO_32: |
| return; |
| |
| case llvm::ELF::R_386_TLS_IE: |
| setHasStaticTLS(); |
| // if buildint shared object, a RELATIVE dynamic relocation is needed |
| if (LinkerConfig::DynObj == config().codeGenType()) { |
| m_pRelDyn->reserveEntry(); |
| rsym->setReserved(rsym->reserved() | ReserveRel); |
| checkAndSetHasTextRel(*pSection.getLink()); |
| } else { |
| // for global sym, we can convert ie to le if its final value is known |
| if (symbolFinalValueIsKnown(*rsym)) { |
| convertTLSIEtoLE(pReloc, pSection); |
| return; |
| } |
| } |
| if (rsym->reserved() & GOTRel) |
| return; |
| // reserve got and dyn relocation entries for tp-relative offset |
| m_pGOT->reserve(); |
| m_pRelDyn->reserveEntry(); |
| // set GOTRel bit |
| rsym->setReserved(rsym->reserved() | GOTRel); |
| return; |
| |
| case llvm::ELF::R_386_TLS_GOTIE: |
| setHasStaticTLS(); |
| if (rsym->reserved() & GOTRel) |
| return; |
| // reserve got and dyn relocation entries for tp-relative offset |
| m_pGOT->reserve(); |
| m_pRelDyn->reserveEntry(); |
| // set GOTRel bit |
| rsym->setReserved(rsym->reserved() | GOTRel); |
| return; |
| |
| case llvm::ELF::R_386_TLS_LE: |
| case llvm::ELF::R_386_TLS_LE_32: |
| setHasStaticTLS(); |
| // if buildint shared object, a dynamic relocation is needed |
| if (LinkerConfig::DynObj == config().codeGenType()) { |
| m_pRelDyn->reserveEntry(); |
| rsym->setReserved(rsym->reserved() | ReserveRel); |
| checkAndSetHasTextRel(*pSection.getLink()); |
| } |
| return; |
| |
| default: { |
| fatal(diag::unsupported_relocation) << (int)pReloc.type() |
| << "[email protected]"; |
| break; |
| } |
| } // end switch |
| } |
| |
| void X86_32GNULDBackend::initTargetSections(Module& pModule, |
| ObjectBuilder& pBuilder) |
| { |
| if (LinkerConfig::Object != config().codeGenType()) { |
| ELFFileFormat* file_format = getOutputFormat(); |
| // initialize .got |
| LDSection& got = file_format->getGOT(); |
| m_pGOT = new X86_32GOT(got); |
| |
| // initialize .got.plt |
| LDSection& gotplt = file_format->getGOTPLT(); |
| m_pGOTPLT = new X86_32GOTPLT(gotplt); |
| |
| // initialize .plt |
| LDSection& plt = file_format->getPLT(); |
| m_pPLT = new X86_32PLT(plt, |
| *m_pGOTPLT, |
| config()); |
| |
| // initialize .rel.plt |
| LDSection& relplt = file_format->getRelPlt(); |
| relplt.setLink(&plt); |
| m_pRelPLT = new OutputRelocSection(pModule, relplt); |
| |
| // initialize .rel.dyn |
| LDSection& reldyn = file_format->getRelDyn(); |
| m_pRelDyn = new OutputRelocSection(pModule, reldyn); |
| |
| } |
| } |
| |
| X86_32GOT& X86_32GNULDBackend::getGOT() |
| { |
| assert(NULL != m_pGOT); |
| return *m_pGOT; |
| } |
| |
| const X86_32GOT& X86_32GNULDBackend::getGOT() const |
| { |
| assert(NULL != m_pGOT); |
| return *m_pGOT; |
| } |
| |
| X86_32GOTPLT& X86_32GNULDBackend::getGOTPLT() |
| { |
| assert(NULL != m_pGOTPLT); |
| return *m_pGOTPLT; |
| } |
| |
| const X86_32GOTPLT& X86_32GNULDBackend::getGOTPLT() const |
| { |
| assert(NULL != m_pGOTPLT); |
| return *m_pGOTPLT; |
| } |
| |
| void X86_32GNULDBackend::setRelDynSize() |
| { |
| ELFFileFormat* file_format = getOutputFormat(); |
| file_format->getRelDyn().setSize |
| (m_pRelDyn->numOfRelocs() * getRelEntrySize()); |
| } |
| |
| void X86_32GNULDBackend::setRelPLTSize() |
| { |
| ELFFileFormat* file_format = getOutputFormat(); |
| file_format->getRelPlt().setSize |
| (m_pRelPLT->numOfRelocs() * getRelEntrySize()); |
| } |
| |
| void X86_32GNULDBackend::setGOTSectionSize(IRBuilder& pBuilder) |
| { |
| // set .got.plt size |
| if (LinkerConfig::DynObj == config().codeGenType() || |
| m_pGOTPLT->hasGOT1() || |
| NULL != m_pGOTSymbol) { |
| m_pGOTPLT->finalizeSectionSize(); |
| defineGOTSymbol(pBuilder, *(m_pGOTPLT->begin())); |
| } |
| |
| // set .got size |
| if (!m_pGOT->empty()) |
| m_pGOT->finalizeSectionSize(); |
| } |
| |
| uint64_t X86_32GNULDBackend::emitGOTSectionData(MemoryRegion& pRegion) const |
| { |
| assert(m_pGOT && "emitGOTSectionData failed, m_pGOT is NULL!"); |
| |
| uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer()); |
| |
| X86_32GOTEntry* got = 0; |
| unsigned int EntrySize = X86_32GOTEntry::EntrySize; |
| uint64_t RegionSize = 0; |
| |
| for (X86_32GOT::iterator it = m_pGOT->begin(), |
| ie = m_pGOT->end(); it != ie; ++it, ++buffer) { |
| got = &(llvm::cast<X86_32GOTEntry>((*it))); |
| *buffer = static_cast<uint32_t>(got->getValue()); |
| RegionSize += EntrySize; |
| } |
| |
| return RegionSize; |
| } |
| |
| uint64_t X86_32GNULDBackend::emitGOTPLTSectionData(MemoryRegion& pRegion, |
| const ELFFileFormat* FileFormat) const |
| { |
| assert(m_pGOTPLT && "emitGOTPLTSectionData failed, m_pGOTPLT is NULL!"); |
| m_pGOTPLT->applyGOT0(FileFormat->getDynamic().addr()); |
| m_pGOTPLT->applyAllGOTPLT(*m_pPLT); |
| |
| uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.getBuffer()); |
| |
| X86_32GOTEntry* got = 0; |
| unsigned int EntrySize = X86_32GOTEntry::EntrySize; |
| uint64_t RegionSize = 0; |
| |
| for (X86_32GOTPLT::iterator it = m_pGOTPLT->begin(), |
| ie = m_pGOTPLT->end(); it != ie; ++it, ++buffer) { |
| got = &(llvm::cast<X86_32GOTEntry>((*it))); |
| *buffer = static_cast<uint32_t>(got->getValue()); |
| RegionSize += EntrySize; |
| } |
| |
| return RegionSize; |
| } |
| |
| /// convert R_386_TLS_IE to R_386_TLS_LE |
| void X86_32GNULDBackend::convertTLSIEtoLE(Relocation& pReloc, |
| LDSection& pSection) |
| { |
| assert(pReloc.type() == llvm::ELF::R_386_TLS_IE); |
| assert(NULL != pReloc.targetRef().frag()); |
| |
| // 1. create the fragment references and new relocs |
| uint64_t off = pReloc.targetRef().offset(); |
| if (off >= 4) |
| off -= 4; |
| else |
| off = 0; |
| |
| FragmentRef* fragref = FragmentRef::Create(*pReloc.targetRef().frag(), off); |
| // TODO: add symbols for R_386_TLS_OPT relocs |
| Relocation* reloc = Relocation::Create(X86_32Relocator::R_386_TLS_OPT, |
| *fragref, |
| 0x0); |
| |
| // 2. modify the opcodes to the appropriate ones |
| uint8_t* op = (reinterpret_cast<uint8_t*>(&reloc->target())); |
| off = pReloc.targetRef().offset() - reloc->targetRef().offset() - 1; |
| if (op[off] == 0xa1) { |
| op[off] = 0xb8; |
| } else { |
| switch (op[off - 1]) { |
| case 0x8b: |
| assert((op[off] & 0xc7) == 0x05); |
| op[off - 1] = 0xc7; |
| op[off] = 0xc0 | ((op[off] >> 3) & 7); |
| break; |
| case 0x03: |
| assert((op[off] & 0xc7) == 0x05); |
| op[off - 1] = 0x81; |
| op[off] = 0xc0 | ((op[off] >> 3) & 7); |
| break; |
| default: |
| assert(0); |
| break; |
| } |
| } |
| |
| // 3. insert the new relocs "BEFORE" the original reloc. |
| pSection.getRelocData()->getRelocationList().insert( |
| RelocData::iterator(pReloc), reloc); |
| |
| // 4. change the type of the original reloc |
| pReloc.setType(llvm::ELF::R_386_TLS_LE); |
| } |
| |
| // Create a GOT entry for the TLS module index |
| X86_32GOTEntry& X86_32GNULDBackend::getTLSModuleID() |
| { |
| static X86_32GOTEntry* got_entry = NULL; |
| if (NULL != got_entry) |
| return *got_entry; |
| |
| // Allocate 2 got entries and 1 dynamic reloc for R_386_TLS_LDM |
| m_pGOT->reserve(2); |
| got_entry = m_pGOT->consume(); |
| m_pGOT->consume()->setValue(0x0); |
| |
| m_pRelDyn->reserveEntry(); |
| Relocation* rel_entry = m_pRelDyn->consumeEntry(); |
| rel_entry->setType(llvm::ELF::R_386_TLS_DTPMOD32); |
| rel_entry->targetRef().assign(*got_entry, 0x0); |
| rel_entry->setSymInfo(NULL); |
| |
| return *got_entry; |
| } |
| |
| X86_64GNULDBackend::X86_64GNULDBackend(const LinkerConfig& pConfig, |
| GNUInfo* pInfo) |
| : X86GNULDBackend(pConfig, pInfo, llvm::ELF::R_X86_64_COPY), |
| m_pGOT (NULL), |
| m_pGOTPLT (NULL) { |
| } |
| |
| X86_64GNULDBackend::~X86_64GNULDBackend() |
| { |
| delete m_pGOT; |
| delete m_pGOTPLT; |
| } |
| |
| bool X86_64GNULDBackend::initRelocator() |
| { |
| if (NULL == m_pRelocator) { |
| m_pRelocator = new X86_64Relocator(*this); |
| } |
| return true; |
| } |
| |
| X86_64GOT& X86_64GNULDBackend::getGOT() |
| { |
| assert(NULL != m_pGOT); |
| return *m_pGOT; |
| } |
| |
| const X86_64GOT& X86_64GNULDBackend::getGOT() const |
| { |
| assert(NULL != m_pGOT); |
| return *m_pGOT; |
| } |
| |
| X86_64GOTPLT& X86_64GNULDBackend::getGOTPLT() |
| { |
| assert(NULL != m_pGOTPLT); |
| return *m_pGOTPLT; |
| } |
| |
| const X86_64GOTPLT& X86_64GNULDBackend::getGOTPLT() const |
| { |
| assert(NULL != m_pGOTPLT); |
| return *m_pGOTPLT; |
| } |
| |
| void X86_64GNULDBackend::setRelDynSize() |
| { |
| ELFFileFormat* file_format = getOutputFormat(); |
| file_format->getRelaDyn().setSize |
| (m_pRelDyn->numOfRelocs() * getRelaEntrySize()); |
| } |
| |
| void X86_64GNULDBackend::setRelPLTSize() |
| { |
| ELFFileFormat* file_format = getOutputFormat(); |
| file_format->getRelaPlt().setSize |
| (m_pRelPLT->numOfRelocs() * getRelaEntrySize()); |
| } |
| |
| void X86_64GNULDBackend::scanLocalReloc(Relocation& pReloc, |
| IRBuilder& pBuilder, |
| Module& pModule, |
| LDSection& pSection) |
| { |
| // rsym - The relocation target symbol |
| ResolveInfo* rsym = pReloc.symInfo(); |
| |
| switch(pReloc.type()){ |
| case llvm::ELF::R_X86_64_64: |
| case llvm::ELF::R_X86_64_32: |
| case llvm::ELF::R_X86_64_16: |
| case llvm::ELF::R_X86_64_8: |
| case llvm::ELF::R_X86_64_32S: |
| // If buiding PIC object (shared library or PIC executable), |
| // a dynamic relocations with RELATIVE type to this location is needed. |
| // Reserve an entry in .rela.dyn |
| if (config().isCodeIndep()) { |
| m_pRelDyn->reserveEntry(); |
| // set Rel bit |
| rsym->setReserved(rsym->reserved() | ReserveRel); |
| checkAndSetHasTextRel(*pSection.getLink()); |
| } |
| return; |
| |
| case llvm::ELF::R_X86_64_PC32: |
| case llvm::ELF::R_X86_64_PC16: |
| case llvm::ELF::R_X86_64_PC8: |
| return; |
| |
| case llvm::ELF::R_X86_64_GOTPCREL: |
| // Symbol needs GOT entry, reserve entry in .got |
| // return if we already create GOT for this symbol |
| if (rsym->reserved() & (ReserveGOT | GOTRel)) |
| return; |
| m_pGOT->reserve(); |
| |
| // If the GOT is used in statically linked binaries, |
| // the GOT entry is enough and no relocation is needed. |
| if (config().isCodeStatic()) { |
| rsym->setReserved(rsym->reserved() | ReserveGOT); |
| return; |
| } |
| // If building shared object or the symbol is undefined, a dynamic |
| // relocation is needed to relocate this GOT entry. Reserve an |
| // entry in .rela.dyn |
| if (LinkerConfig::DynObj == |
| config().codeGenType() || rsym->isUndef() || rsym->isDyn()) { |
| m_pRelDyn->reserveEntry(); |
| // set GOTRel bit |
| rsym->setReserved(rsym->reserved() | GOTRel); |
| return; |
| } |
| // set GOT bit |
| rsym->setReserved(rsym->reserved() | ReserveGOT); |
| return; |
| |
| default: |
| fatal(diag::unsupported_relocation) << (int)pReloc.type() |
| << "[email protected]"; |
| break; |
| } // end switch |
| } |
| |
| void X86_64GNULDBackend::scanGlobalReloc(Relocation& pReloc, |
| IRBuilder& pBuilder, |
| Module& pModule, |
| LDSection& pSection) |
| { |
| // rsym - The relocation target symbol |
| ResolveInfo* rsym = pReloc.symInfo(); |
| |
| switch(pReloc.type()) { |
| case llvm::ELF::R_X86_64_64: |
| case llvm::ELF::R_X86_64_32: |
| case llvm::ELF::R_X86_64_16: |
| case llvm::ELF::R_X86_64_8: |
| case llvm::ELF::R_X86_64_32S: |
| // Absolute relocation type, symbol may needs PLT entry or |
| // dynamic relocation entry |
| if (symbolNeedsPLT(*rsym)) { |
| // create plt for this symbol if it does not have one |
| if (!(rsym->reserved() & ReservePLT)){ |
| // Symbol needs PLT entry, we need to reserve a PLT entry |
| // and the corresponding GOT and dynamic relocation entry |
| // in .got and .rela.plt. (GOT entry will be reserved simultaneously |
| // when calling X86PLT->reserveEntry()) |
| m_pPLT->reserveEntry(); |
| m_pGOTPLT->reserve(); |
| m_pRelPLT->reserveEntry(); |
| // set PLT bit |
| rsym->setReserved(rsym->reserved() | ReservePLT); |
| } |
| } |
| |
| if (symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT), true)) { |
| // symbol needs dynamic relocation entry, reserve an entry in .rela.dyn |
| m_pRelDyn->reserveEntry(); |
| if (symbolNeedsCopyReloc(pReloc, *rsym)) { |
| LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym); |
| addCopyReloc(*cpy_sym.resolveInfo()); |
| } |
| else { |
| // set Rel bit |
| rsym->setReserved(rsym->reserved() | ReserveRel); |
| checkAndSetHasTextRel(*pSection.getLink()); |
| } |
| } |
| return; |
| |
| case llvm::ELF::R_X86_64_GOTPCREL: |
| // Symbol needs GOT entry, reserve entry in .got |
| // return if we already create GOT for this symbol |
| if (rsym->reserved() & (ReserveGOT | GOTRel)) |
| return; |
| m_pGOT->reserve(); |
| |
| // If the GOT is used in statically linked binaries, |
| // the GOT entry is enough and no relocation is needed. |
| if (config().isCodeStatic()) { |
| rsym->setReserved(rsym->reserved() | ReserveGOT); |
| return; |
| } |
| // If building shared object or the symbol is undefined, a dynamic |
| // relocation is needed to relocate this GOT entry. Reserve an |
| // entry in .rela.dyn |
| if (LinkerConfig::DynObj == |
| config().codeGenType() || rsym->isUndef() || rsym->isDyn()) { |
| m_pRelDyn->reserveEntry(); |
| // set GOTRel bit |
| rsym->setReserved(rsym->reserved() | GOTRel); |
| return; |
| } |
| // set GOT bit |
| rsym->setReserved(rsym->reserved() | ReserveGOT); |
| return; |
| |
| case llvm::ELF::R_X86_64_PLT32: |
| // A PLT entry is needed when building shared library |
| |
| // return if we already create plt for this symbol |
| if (rsym->reserved() & ReservePLT) |
| return; |
| |
| // if the symbol's value can be decided at link time, then no need plt |
| if (symbolFinalValueIsKnown(*rsym)) |
| return; |
| |
| // if symbol is defined in the ouput file and it's not |
| // preemptible, no need plt |
| if (rsym->isDefine() && !rsym->isDyn() && |
| !isSymbolPreemptible(*rsym)) { |
| return; |
| } |
| |
| // Symbol needs PLT entry, we need to reserve a PLT entry |
| // and the corresponding GOT and dynamic relocation entry |
| // in .got and .rel.plt. (GOT entry will be reserved simultaneously |
| // when calling X86PLT->reserveEntry()) |
| m_pPLT->reserveEntry(); |
| m_pGOTPLT->reserve(); |
| m_pRelPLT->reserveEntry(); |
| // set PLT bit |
| rsym->setReserved(rsym->reserved() | ReservePLT); |
| return; |
| |
| case llvm::ELF::R_X86_64_PC32: |
| case llvm::ELF::R_X86_64_PC16: |
| case llvm::ELF::R_X86_64_PC8: |
| if (symbolNeedsPLT(*rsym) && |
| LinkerConfig::DynObj != config().codeGenType()) { |
| // create plt for this symbol if it does not have one |
| if (!(rsym->reserved() & ReservePLT)){ |
| // Symbol needs PLT entry, we need to reserve a PLT entry |
| // and the corresponding GOT and dynamic relocation entry |
| // in .got and .rel.plt. (GOT entry will be reserved simultaneously |
| // when calling X86PLT->reserveEntry()) |
| m_pPLT->reserveEntry(); |
| m_pGOTPLT->reserve(); |
| m_pRelPLT->reserveEntry(); |
| // set PLT bit |
| rsym->setReserved(rsym->reserved() | ReservePLT); |
| } |
| } |
| |
| // Only PC relative relocation against dynamic symbol needs a |
| // dynamic relocation. Only dynamic copy relocation is allowed |
| // and PC relative relocation will be resolved to the local copy. |
| // All other dynamic relocations may lead to run-time relocation |
| // overflow. |
| if (isDynamicSymbol(*rsym) && |
| symbolNeedsDynRel(*rsym, (rsym->reserved() & ReservePLT), false) && |
| symbolNeedsCopyReloc(pReloc, *rsym)) { |
| m_pRelDyn->reserveEntry(); |
| LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym); |
| addCopyReloc(*cpy_sym.resolveInfo()); |
| } |
| return; |
| |
| default: |
| fatal(diag::unsupported_relocation) << (int)pReloc.type() |
| << "[email protected]"; |
| break; |
| } // end switch |
| } |
| |
| void X86_64GNULDBackend::initTargetSections(Module& pModule, |
| ObjectBuilder& pBuilder) |
| { |
| if (LinkerConfig::Object != config().codeGenType()) { |
| ELFFileFormat* file_format = getOutputFormat(); |
| // initialize .got |
| LDSection& got = file_format->getGOT(); |
| m_pGOT = new X86_64GOT(got); |
| |
| // initialize .got.plt |
| LDSection& gotplt = file_format->getGOTPLT(); |
| m_pGOTPLT = new X86_64GOTPLT(gotplt); |
| |
| // initialize .plt |
| LDSection& plt = file_format->getPLT(); |
| m_pPLT = new X86_64PLT(plt, |
| *m_pGOTPLT, |
| config()); |
| |
| // initialize .rela.plt |
| LDSection& relplt = file_format->getRelaPlt(); |
| relplt.setLink(&plt); |
| m_pRelPLT = new OutputRelocSection(pModule, relplt); |
| |
| // initialize .rela.dyn |
| LDSection& reldyn = file_format->getRelaDyn(); |
| m_pRelDyn = new OutputRelocSection(pModule, reldyn); |
| |
| } |
| } |
| |
| void X86_64GNULDBackend::setGOTSectionSize(IRBuilder& pBuilder) |
| { |
| // set .got.plt size |
| if (LinkerConfig::DynObj == config().codeGenType() || |
| m_pGOTPLT->hasGOT1() || |
| NULL != m_pGOTSymbol) { |
| m_pGOTPLT->finalizeSectionSize(); |
| defineGOTSymbol(pBuilder, *(m_pGOTPLT->begin())); |
| } |
| |
| // set .got size |
| if (!m_pGOT->empty()) |
| m_pGOT->finalizeSectionSize(); |
| } |
| |
| uint64_t X86_64GNULDBackend::emitGOTSectionData(MemoryRegion& pRegion) const |
| { |
| assert(m_pGOT && "emitGOTSectionData failed, m_pGOT is NULL!"); |
| |
| uint64_t* buffer = reinterpret_cast<uint64_t*>(pRegion.getBuffer()); |
| |
| X86_64GOTEntry* got = 0; |
| unsigned int EntrySize = X86_64GOTEntry::EntrySize; |
| uint64_t RegionSize = 0; |
| |
| for (X86_64GOT::iterator it = m_pGOT->begin(), |
| ie = m_pGOT->end(); it != ie; ++it, ++buffer) { |
| got = &(llvm::cast<X86_64GOTEntry>((*it))); |
| *buffer = static_cast<uint64_t>(got->getValue()); |
| RegionSize += EntrySize; |
| } |
| |
| return RegionSize; |
| } |
| |
| uint64_t X86_64GNULDBackend::emitGOTPLTSectionData(MemoryRegion& pRegion, |
| const ELFFileFormat* FileFormat) const |
| { |
| assert(m_pGOTPLT && "emitGOTPLTSectionData failed, m_pGOTPLT is NULL!"); |
| m_pGOTPLT->applyGOT0(FileFormat->getDynamic().addr()); |
| m_pGOTPLT->applyAllGOTPLT(*m_pPLT); |
| |
| uint64_t* buffer = reinterpret_cast<uint64_t*>(pRegion.getBuffer()); |
| |
| X86_64GOTEntry* got = 0; |
| unsigned int EntrySize = X86_64GOTEntry::EntrySize; |
| uint64_t RegionSize = 0; |
| |
| for (X86_64GOTPLT::iterator it = m_pGOTPLT->begin(), |
| ie = m_pGOTPLT->end(); it != ie; ++it, ++buffer) { |
| got = &(llvm::cast<X86_64GOTEntry>((*it))); |
| *buffer = static_cast<uint64_t>(got->getValue()); |
| RegionSize += EntrySize; |
| } |
| |
| return RegionSize; |
| } |
| |
| namespace mcld { |
| |
| //===----------------------------------------------------------------------===// |
| /// createX86LDBackend - the help funtion to create corresponding X86LDBackend |
| /// |
| TargetLDBackend* createX86LDBackend(const llvm::Target& pTarget, |
| const LinkerConfig& pConfig) |
| { |
| if (pConfig.targets().triple().isOSDarwin()) { |
| assert(0 && "MachO linker is not supported yet"); |
| /** |
| return new X86MachOLDBackend(createX86MachOArchiveReader, |
| createX86MachOObjectReader, |
| createX86MachOObjectWriter); |
| **/ |
| } |
| if (pConfig.targets().triple().isOSWindows()) { |
| assert(0 && "COFF linker is not supported yet"); |
| /** |
| return new X86COFFLDBackend(createX86COFFArchiveReader, |
| createX86COFFObjectReader, |
| createX86COFFObjectWriter); |
| **/ |
| } |
| Triple::ArchType arch = pConfig.targets().triple().getArch(); |
| if (arch == Triple::x86) |
| return new X86_32GNULDBackend(pConfig, |
| new X86_32GNUInfo(pConfig.targets().triple())); |
| assert (arch == Triple::x86_64); |
| return new X86_64GNULDBackend(pConfig, |
| new X86_64GNUInfo(pConfig.targets().triple())); |
| } |
| |
| } // namespace of mcld |
| |
| //===----------------------------------------------------------------------===// |
| // Force static initialization. |
| //===----------------------------------------------------------------------===// |
| extern "C" void MCLDInitializeX86LDBackend() { |
| // Register the linker backend |
| mcld::TargetRegistry::RegisterTargetLDBackend(TheX86_32Target, createX86LDBackend); |
| mcld::TargetRegistry::RegisterTargetLDBackend(TheX86_64Target, createX86LDBackend); |
| } |