| //===- 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 "mcld/IRBuilder.h" |
| #include "mcld/LinkerConfig.h" |
| #include "mcld/Fragment/FillFragment.h" |
| #include "mcld/Fragment/RegionFragment.h" |
| #include "mcld/LD/ELFFileFormat.h" |
| #include "mcld/Object/ObjectBuilder.h" |
| #include "mcld/Support/MsgHandling.h" |
| #include "mcld/Support/TargetRegistry.h" |
| |
| #include <llvm/ADT/StringRef.h> |
| #include <llvm/ADT/Triple.h> |
| #include <llvm/Support/Casting.h> |
| #include <llvm/Support/Dwarf.h> |
| |
| #include <cstring> |
| |
| 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) { |
| llvm::Triple::ArchType arch = pConfig.targets().triple().getArch(); |
| assert(arch == llvm::Triple::x86 || arch == llvm::Triple::x86_64); |
| if (arch == llvm::Triple::x86 || |
| pConfig.targets().triple().getEnvironment() == llvm::Triple::GNUX32) { |
| m_RelEntrySize = 8; |
| m_RelaEntrySize = 12; |
| if (arch == llvm::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; |
| } |
| |
| const Relocator* X86GNULDBackend::getRelocator() const { |
| assert(m_pRelocator != NULL); |
| return m_pRelocator; |
| } |
| |
| Relocator* X86GNULDBackend::getRelocator() { |
| assert(m_pRelocator != NULL); |
| return m_pRelocator; |
| } |
| |
| void X86GNULDBackend::doPreLayout(IRBuilder& pBuilder) { |
| // initialize .dynamic data |
| if (!config().isCodeStatic() && m_pDynamic == NULL) |
| 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(); |
| } |
| } |
| |
| if (config().options().genUnwindInfo()) |
| addEhFrameForPLT(pBuilder.getModule()); |
| } |
| |
| 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(m_pDynamic != NULL); |
| 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(m_pDynamic != NULL); |
| 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); |
| } |
| } |
| |
| 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 (FileFormat->hasPLT() && (&pSection == &(FileFormat->getPLT()))) { |
| unsigned char* buffer = pRegion.begin(); |
| |
| 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 (FileFormat->hasGOT() && (&pSection == &(FileFormat->getGOT()))) { |
| RegionSize += emitGOTSectionData(pRegion); |
| } else if (FileFormat->hasGOTPLT() && |
| (&pSection == &(FileFormat->getGOTPLT()))) { |
| RegionSize += emitGOTPLTSectionData(pRegion, FileFormat); |
| } else { |
| fatal(diag::unrecognized_output_sectoin) << pSection.name() |
| << "[email protected]"; |
| } |
| return RegionSize; |
| } |
| |
| X86PLT& X86GNULDBackend::getPLT() { |
| assert(m_pPLT != NULL && "PLT section not exist"); |
| return *m_pPLT; |
| } |
| |
| const X86PLT& X86GNULDBackend::getPLT() const { |
| assert(m_pPLT != NULL && "PLT section not exist"); |
| return *m_pPLT; |
| } |
| |
| OutputRelocSection& X86GNULDBackend::getRelDyn() { |
| assert(m_pRelDyn != NULL && ".rel.dyn/.rela.dyn section not exist"); |
| return *m_pRelDyn; |
| } |
| |
| const OutputRelocSection& X86GNULDBackend::getRelDyn() const { |
| assert(m_pRelDyn != NULL && ".rel.dyn/.rela.dyn section not exist"); |
| return *m_pRelDyn; |
| } |
| |
| OutputRelocSection& X86GNULDBackend::getRelPLT() { |
| assert(m_pRelPLT != NULL && ".rel.plt/.rela.plt section not exist"); |
| return *m_pRelPLT; |
| } |
| |
| const OutputRelocSection& X86GNULDBackend::getRelPLT() const { |
| assert(m_pRelPLT != NULL && ".rel.plt/.rela.plt section not exist"); |
| return *m_pRelPLT; |
| } |
| |
| unsigned int X86GNULDBackend::getTargetSectionOrder( |
| const LDSection& pSectHdr) const { |
| const ELFFileFormat* file_format = getOutputFormat(); |
| |
| if (file_format->hasGOT() && (&pSectHdr == &file_format->getGOT())) { |
| if (config().options().hasNow()) |
| return SHO_RELRO; |
| return SHO_RELRO_LAST; |
| } |
| |
| if (file_format->hasGOTPLT() && (&pSectHdr == &file_format->getGOTPLT())) { |
| if (config().options().hasNow()) |
| return SHO_RELRO; |
| return SHO_NON_RELRO_FIRST; |
| } |
| |
| if (file_format->hasPLT() && (&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); |
| } |
| } |
| |
| void X86GNULDBackend::addEhFrameForPLT(Module& pModule) { |
| LDSection* plt_sect = pModule.getSection(".plt"); |
| if (!plt_sect || plt_sect->size() == 0u) |
| return; |
| |
| LDSection* eh_sect = pModule.getSection(".eh_frame"); |
| if (!eh_sect || !eh_sect->hasEhFrame()) |
| return; |
| |
| EhFrame* eh_frame = eh_sect->getEhFrame(); |
| SectionData::FragmentListType& frag_list = |
| eh_frame->getSectionData()->getFragmentList(); |
| llvm::StringRef cie_region = createCIERegionForPLT(); |
| llvm::StringRef fde_region = createFDERegionForPLT(); |
| EhFrame::CIE* cie = new EhFrame::GeneratedCIE(cie_region); |
| EhFrame::FDE* fde = new EhFrame::GeneratedFDE(fde_region, *cie); |
| // Augmentation data only contains FDE encoding. |
| uint8_t aug_data = |
| (uint8_t)(llvm::dwarf::DW_EH_PE_pcrel | llvm::dwarf::DW_EH_PE_sdata4); |
| cie->setFDEEncode(aug_data); |
| cie->setAugmentationData(std::string(1, aug_data)); |
| |
| EhFrame::cie_iterator i = eh_frame->cie_begin(); |
| for (EhFrame::cie_iterator e = eh_frame->cie_end(); i != e; ++i) { |
| EhFrame::CIE& exist_cie = **i; |
| if (exist_cie == *cie) { |
| // Insert the FDE fragment |
| SectionData::iterator cur_iter(exist_cie); |
| frag_list.insertAfter(cur_iter, fde); |
| fde->setCIE(exist_cie); |
| |
| // Cleanup the CIE we created |
| cie->clearFDEs(); |
| delete cie; |
| break; |
| } |
| } |
| if (i == eh_frame->cie_end()) { |
| // Newly insert |
| eh_frame->addCIE(*cie); |
| eh_frame->addFDE(*fde); |
| } |
| } |
| |
| /// 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 (m_pRelocator == NULL) { |
| m_pRelocator = new X86_32Relocator(*this, config()); |
| } |
| return true; |
| } |
| |
| 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(); |
| plt.setAlign(16u); |
| 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(m_pGOT != NULL); |
| return *m_pGOT; |
| } |
| |
| const X86_32GOT& X86_32GNULDBackend::getGOT() const { |
| assert(m_pGOT != NULL); |
| return *m_pGOT; |
| } |
| |
| X86_32GOTPLT& X86_32GNULDBackend::getGOTPLT() { |
| assert(m_pGOTPLT != NULL); |
| return *m_pGOTPLT; |
| } |
| |
| const X86_32GOTPLT& X86_32GNULDBackend::getGOTPLT() const { |
| assert(m_pGOTPLT != NULL); |
| return *m_pGOTPLT; |
| } |
| |
| llvm::StringRef X86_32GNULDBackend::createCIERegionForPLT() { |
| static const uint8_t data[4 + 4 + 16] = { |
| 0x14, 0, 0, 0, // length |
| 0, 0, 0, 0, // ID |
| 1, // version |
| 'z', 'R', '\0', // augmentation string |
| 1, // code alignment factor |
| 0x7c, // data alignment factor |
| 8, // return address column |
| 1, // augmentation data size |
| llvm::dwarf::DW_EH_PE_pcrel |
| | llvm::dwarf::DW_EH_PE_sdata4, // FDE encoding |
| llvm::dwarf::DW_CFA_def_cfa, 4, 4, |
| llvm::dwarf::DW_CFA_offset + 8, 1, |
| llvm::dwarf::DW_CFA_nop, |
| llvm::dwarf::DW_CFA_nop |
| }; |
| return llvm::StringRef((const char*)data, 4 + 4 + 16); |
| } |
| |
| llvm::StringRef X86_32GNULDBackend::createFDERegionForPLT() { |
| static const uint8_t data[4 + 4 + 32] = { |
| 0x24, 0, 0, 0, // length |
| 0, 0, 0, 0, // offset to CIE |
| 0, 0, 0, 0, // offset to PLT |
| 0, 0, 0, 0, // size of PLT |
| 0, // augmentation data size |
| llvm::dwarf::DW_CFA_def_cfa_offset, 8, |
| llvm::dwarf::DW_CFA_advance_loc + 6, |
| llvm::dwarf::DW_CFA_def_cfa_offset, 12, |
| llvm::dwarf::DW_CFA_advance_loc + 10, |
| llvm::dwarf::DW_CFA_def_cfa_expression, |
| 11, |
| llvm::dwarf::DW_OP_breg4, 4, |
| llvm::dwarf::DW_OP_breg8, 0, |
| llvm::dwarf::DW_OP_lit15, |
| llvm::dwarf::DW_OP_and, |
| llvm::dwarf::DW_OP_lit11, |
| llvm::dwarf::DW_OP_ge, |
| llvm::dwarf::DW_OP_lit2, |
| llvm::dwarf::DW_OP_shl, |
| llvm::dwarf::DW_OP_plus, |
| llvm::dwarf::DW_CFA_nop, |
| llvm::dwarf::DW_CFA_nop, |
| llvm::dwarf::DW_CFA_nop, |
| llvm::dwarf::DW_CFA_nop |
| }; |
| return llvm::StringRef((const char*)data, 4 + 4 + 32); |
| } |
| |
| 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() || |
| m_pGOTSymbol != NULL) { |
| 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.begin()); |
| |
| 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.begin()); |
| |
| 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; |
| } |
| |
| 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 (m_pRelocator == NULL) { |
| m_pRelocator = new X86_64Relocator(*this, config()); |
| } |
| return true; |
| } |
| |
| X86_64GOT& X86_64GNULDBackend::getGOT() { |
| assert(m_pGOT != NULL); |
| return *m_pGOT; |
| } |
| |
| const X86_64GOT& X86_64GNULDBackend::getGOT() const { |
| assert(m_pGOT != NULL); |
| return *m_pGOT; |
| } |
| |
| X86_64GOTPLT& X86_64GNULDBackend::getGOTPLT() { |
| assert(m_pGOTPLT != NULL); |
| return *m_pGOTPLT; |
| } |
| |
| const X86_64GOTPLT& X86_64GNULDBackend::getGOTPLT() const { |
| assert(m_pGOTPLT != NULL); |
| return *m_pGOTPLT; |
| } |
| |
| llvm::StringRef X86_64GNULDBackend::createCIERegionForPLT() { |
| static const uint8_t data[4 + 4 + 16] = { |
| 0x14, 0, 0, 0, // length |
| 0, 0, 0, 0, // ID |
| 1, // CIE version |
| 'z', 'R', '\0', // augmentation string |
| 1, // code alignment factor |
| 0x78, // data alignment factor |
| 16, // return address column |
| 1, // augmentation data size |
| llvm::dwarf::DW_EH_PE_pcrel |
| | llvm::dwarf::DW_EH_PE_sdata4, // FDE encoding |
| llvm::dwarf::DW_CFA_def_cfa, 7, 8, |
| llvm::dwarf::DW_CFA_offset + 16, 1, |
| llvm::dwarf::DW_CFA_nop, |
| llvm::dwarf::DW_CFA_nop |
| }; |
| return llvm::StringRef((const char*)data, 4 + 4 + 16); |
| } |
| |
| llvm::StringRef X86_64GNULDBackend::createFDERegionForPLT() { |
| static const uint8_t data[4 + 4 + 32] = { |
| 0x24, 0, 0, 0, // length |
| 0, 0, 0, 0, // ID |
| 0, 0, 0, 0, // offset to PLT |
| 0, 0, 0, 0, // size of PLT |
| 0, // augmentation data size |
| llvm::dwarf::DW_CFA_def_cfa_offset, 16, |
| llvm::dwarf::DW_CFA_advance_loc + 6, |
| llvm::dwarf::DW_CFA_def_cfa_offset, 24, |
| llvm::dwarf::DW_CFA_advance_loc + 10, |
| llvm::dwarf::DW_CFA_def_cfa_expression, |
| 11, |
| llvm::dwarf::DW_OP_breg7, 8, |
| llvm::dwarf::DW_OP_breg16, 0, |
| llvm::dwarf::DW_OP_lit15, |
| llvm::dwarf::DW_OP_and, |
| llvm::dwarf::DW_OP_lit11, |
| llvm::dwarf::DW_OP_ge, |
| llvm::dwarf::DW_OP_lit3, |
| llvm::dwarf::DW_OP_shl, |
| llvm::dwarf::DW_OP_plus, |
| llvm::dwarf::DW_CFA_nop, |
| llvm::dwarf::DW_CFA_nop, |
| llvm::dwarf::DW_CFA_nop, |
| llvm::dwarf::DW_CFA_nop |
| }; |
| return llvm::StringRef((const char*)data, 4 + 4 + 32); |
| } |
| |
| 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::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(); |
| plt.setAlign(16u); |
| 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() || |
| m_pGOTSymbol != NULL) { |
| 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.begin()); |
| |
| 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.begin()); |
| |
| 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; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| /// createX86LDBackend - the help funtion to create corresponding X86LDBackend |
| /// |
| TargetLDBackend* createX86LDBackend(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); |
| **/ |
| } |
| llvm::Triple::ArchType arch = pConfig.targets().triple().getArch(); |
| if (arch == llvm::Triple::x86) |
| return new X86_32GNULDBackend( |
| pConfig, new X86_32GNUInfo(pConfig.targets().triple())); |
| assert(arch == llvm::Triple::x86_64); |
| return new X86_64GNULDBackend(pConfig, |
| new X86_64GNUInfo(pConfig.targets().triple())); |
| } |
| |
| } // namespace mcld |
| |
| //===----------------------------------------------------------------------===// |
| // Force static initialization. |
| //===----------------------------------------------------------------------===// |
| extern "C" void MCLDInitializeX86LDBackend() { |
| // Register the linker backend |
| mcld::TargetRegistry::RegisterTargetLDBackend(mcld::TheX86_32Target, |
| mcld::createX86LDBackend); |
| mcld::TargetRegistry::RegisterTargetLDBackend(mcld::TheX86_64Target, |
| mcld::createX86LDBackend); |
| } |