| //===- MCLinker.cpp -------------------------------------------------------===// |
| // |
| // The MCLinker Project |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file implements the MCLinker class |
| // |
| //===----------------------------------------------------------------------===// |
| #include <mcld/MC/MCLinker.h> |
| |
| #include <llvm/Support/Host.h> |
| #include <llvm/Support/raw_ostream.h> |
| |
| #include <mcld/MC/MCLDInput.h> |
| #include <mcld/MC/MCLDInfo.h> |
| #include <mcld/LD/Resolver.h> |
| #include <mcld/LD/LDContext.h> |
| #include <mcld/LD/LDSymbol.h> |
| #include <mcld/LD/LDSectionFactory.h> |
| #include <mcld/LD/SectionMap.h> |
| #include <mcld/LD/RelocationFactory.h> |
| #include <mcld/LD/FillFragment.h> |
| #include <mcld/LD/RegionFragment.h> |
| #include <mcld/LD/EhFrame.h> |
| #include <mcld/LD/EhFrameHdr.h> |
| #include <mcld/Support/MemoryRegion.h> |
| #include <mcld/Support/MsgHandling.h> |
| #include <mcld/Target/TargetLDBackend.h> |
| |
| using namespace mcld; |
| |
| /// Constructor |
| MCLinker::MCLinker(TargetLDBackend& pBackend, |
| MCLDInfo& pInfo, |
| SectionMap& pSectionMap) |
| : m_Backend(pBackend), |
| m_LDInfo(pInfo), |
| m_SectionMap(pSectionMap), |
| m_LDSymbolFactory(128), |
| m_LDSectHdrFactory(10), // the average number of sections. (assuming 10.) |
| m_LDSectDataFactory(10), |
| m_pSectionMerger(NULL) |
| { |
| } |
| |
| /// Destructor |
| MCLinker::~MCLinker() |
| { |
| if (NULL != m_pSectionMerger) |
| delete m_pSectionMerger; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Symbol Operations |
| //===----------------------------------------------------------------------===// |
| /// addSymbolFromObject - add a symbol from object file and resolve it |
| /// immediately |
| LDSymbol* MCLinker::addSymbolFromObject(const llvm::StringRef& pName, |
| ResolveInfo::Type pType, |
| ResolveInfo::Desc pDesc, |
| ResolveInfo::Binding pBinding, |
| ResolveInfo::SizeType pSize, |
| LDSymbol::ValueType pValue, |
| FragmentRef* pFragmentRef, |
| ResolveInfo::Visibility pVisibility) |
| { |
| |
| // resolved_result is a triple <resolved_info, existent, override> |
| Resolver::Result resolved_result; |
| ResolveInfo old_info; // used for arrange output symbols |
| |
| if (pBinding == ResolveInfo::Local) { |
| // if the symbol is a local symbol, create a LDSymbol for input, but do not |
| // resolve them. |
| resolved_result.info = m_LDInfo.getNamePool().createSymbol(pName, |
| false, |
| pType, |
| pDesc, |
| pBinding, |
| pSize, |
| pVisibility); |
| |
| // No matter if there is a symbol with the same name, insert the symbol |
| // into output symbol table. So, we let the existent false. |
| resolved_result.existent = false; |
| resolved_result.overriden = true; |
| } |
| else { |
| // if the symbol is not local, insert and resolve it immediately |
| m_LDInfo.getNamePool().insertSymbol(pName, false, pType, pDesc, pBinding, |
| pSize, pVisibility, |
| &old_info, resolved_result); |
| } |
| |
| // the return ResolveInfo should not NULL |
| assert(NULL != resolved_result.info); |
| |
| // create a LDSymbol for the input file. |
| LDSymbol* input_sym = m_LDSymbolFactory.allocate(); |
| new (input_sym) LDSymbol(); |
| |
| // set the relation between input LDSymbol and its ResolveInfo |
| input_sym->setResolveInfo(*resolved_result.info); |
| |
| // set up input LDSymbol |
| input_sym->setFragmentRef(pFragmentRef); |
| input_sym->setValue(pValue); |
| |
| LDSymbol* output_sym = resolved_result.info->outSymbol(); |
| bool has_output_sym = (NULL != output_sym); |
| if (!resolved_result.existent || !has_output_sym) { |
| // it is a new symbol, the output_sym should be NULL. |
| assert(NULL == output_sym); |
| |
| // if it is a new symbol, create a LDSymbol for the output |
| output_sym = m_LDSymbolFactory.allocate(); |
| new (output_sym) LDSymbol(); |
| |
| // set up the relation between output LDSymbol and its ResolveInfo |
| output_sym->setResolveInfo(*resolved_result.info); |
| resolved_result.info->setSymPtr(output_sym); |
| } |
| |
| if (resolved_result.overriden || !has_output_sym) { |
| // symbol can be overriden only if it exists. |
| assert(output_sym != NULL); |
| |
| // should override output LDSymbol |
| output_sym->setFragmentRef(pFragmentRef); |
| output_sym->setValue(pValue); |
| } |
| |
| // After symbol resolution, visibility is changed to the most restrict one. |
| // we need to arrange its position in the output symbol . |
| if (pType != ResolveInfo::Section) { |
| if (!has_output_sym) { |
| // We merge sections when reading them. So we do not need to output symbols |
| // with section type |
| |
| // No matter the symbol is already in the output or not, add it if it |
| // should be forcefully set local. |
| if (shouldForceLocal(*resolved_result.info)) |
| m_OutputSymbols.forceLocal(*output_sym); |
| else { |
| // the symbol should not be forcefully local. |
| m_OutputSymbols.add(*output_sym); |
| } |
| } |
| else if (resolved_result.overriden) { |
| if (!shouldForceLocal(old_info) || |
| !shouldForceLocal(*resolved_result.info)) { |
| // If the old info and the new info are both forcefully local, then |
| // we should keep the output_sym in forcefully local category. Else, |
| // we should re-sort the output_sym |
| m_OutputSymbols.arrange(*output_sym, old_info); |
| } |
| } |
| } |
| |
| return input_sym; |
| } |
| |
| /// addSymbolFromDynObj - add a symbol from object file and resolve it |
| /// immediately |
| LDSymbol* MCLinker::addSymbolFromDynObj(const llvm::StringRef& pName, |
| ResolveInfo::Type pType, |
| ResolveInfo::Desc pDesc, |
| ResolveInfo::Binding pBinding, |
| ResolveInfo::SizeType pSize, |
| LDSymbol::ValueType pValue, |
| FragmentRef* pFragmentRef, |
| ResolveInfo::Visibility pVisibility) |
| { |
| // We merge sections when reading them. So we do not need symbols with |
| // section type |
| if (pType == ResolveInfo::Section) |
| return NULL; |
| |
| // ignore symbols with local binding or that have internal or hidden |
| // visibility |
| if (pBinding == ResolveInfo::Local || |
| pVisibility == ResolveInfo::Internal || |
| pVisibility == ResolveInfo::Hidden) |
| return NULL; |
| |
| // A protected symbol in a shared library must be treated as a |
| // normal symbol when viewed from outside the shared library. |
| if (pVisibility == ResolveInfo::Protected) |
| pVisibility = ResolveInfo::Default; |
| |
| // insert symbol and resolve it immediately |
| // resolved_result is a triple <resolved_info, existent, override> |
| Resolver::Result resolved_result; |
| m_LDInfo.getNamePool().insertSymbol(pName, true, pType, pDesc, |
| pBinding, pSize, pVisibility, |
| NULL, resolved_result); |
| |
| // the return ResolveInfo should not NULL |
| assert(NULL != resolved_result.info); |
| |
| // create a LDSymbol for the input file. |
| LDSymbol* input_sym = m_LDSymbolFactory.allocate(); |
| new (input_sym) LDSymbol(); |
| |
| // set up the relation between input LDSymbol and its ResolveInfo |
| input_sym->setResolveInfo(*resolved_result.info); |
| |
| // set up input LDSymbol |
| input_sym->setFragmentRef(pFragmentRef); |
| input_sym->setValue(pValue); |
| |
| LDSymbol* output_sym = NULL; |
| if (!resolved_result.existent) { |
| // we get a new symbol, leave it as NULL |
| resolved_result.info->setSymPtr(NULL); |
| } |
| else { |
| // we saw the symbol before, but the output_sym still may be NULL. |
| output_sym = resolved_result.info->outSymbol(); |
| } |
| |
| if (output_sym != NULL) { |
| // After symbol resolution, visibility is changed to the most restrict one. |
| // If we are not doing incremental linking, then any symbol with hidden |
| // or internal visibility is forcefully set as a local symbol. |
| if (shouldForceLocal(*resolved_result.info)) { |
| m_OutputSymbols.forceLocal(*output_sym); |
| } |
| } |
| |
| return input_sym; |
| } |
| |
| /// defineSymbolForcefully - define an output symbol and override it immediately |
| LDSymbol* MCLinker::defineSymbolForcefully(const llvm::StringRef& pName, |
| bool pIsDyn, |
| ResolveInfo::Type pType, |
| ResolveInfo::Desc pDesc, |
| ResolveInfo::Binding pBinding, |
| ResolveInfo::SizeType pSize, |
| LDSymbol::ValueType pValue, |
| FragmentRef* pFragmentRef, |
| ResolveInfo::Visibility pVisibility) |
| { |
| ResolveInfo* info = m_LDInfo.getNamePool().findInfo(pName); |
| LDSymbol* output_sym = NULL; |
| if (NULL == info) { |
| // the symbol is not in the pool, create a new one. |
| // create a ResolveInfo |
| Resolver::Result result; |
| m_LDInfo.getNamePool().insertSymbol(pName, pIsDyn, pType, pDesc, |
| pBinding, pSize, pVisibility, |
| NULL, result); |
| assert(!result.existent); |
| |
| // create a output LDSymbol |
| output_sym = m_LDSymbolFactory.allocate(); |
| new (output_sym) LDSymbol(); |
| |
| output_sym->setResolveInfo(*result.info); |
| result.info->setSymPtr(output_sym); |
| |
| if (shouldForceLocal(*result.info)) |
| m_OutputSymbols.forceLocal(*output_sym); |
| else |
| m_OutputSymbols.add(*output_sym); |
| } |
| else { |
| // the symbol is already in the pool, override it |
| ResolveInfo old_info; |
| old_info.override(*info); |
| |
| info->setSource(pIsDyn); |
| info->setType(pType); |
| info->setDesc(pDesc); |
| info->setBinding(pBinding); |
| info->setVisibility(pVisibility); |
| info->setIsSymbol(true); |
| info->setSize(pSize); |
| |
| output_sym = info->outSymbol(); |
| if (NULL != output_sym) |
| m_OutputSymbols.arrange(*output_sym, old_info); |
| else { |
| // create a output LDSymbol |
| output_sym = m_LDSymbolFactory.allocate(); |
| new (output_sym) LDSymbol(); |
| |
| output_sym->setResolveInfo(*info); |
| info->setSymPtr(output_sym); |
| |
| m_OutputSymbols.add(*output_sym); |
| } |
| } |
| |
| if (NULL != output_sym) { |
| output_sym->setFragmentRef(pFragmentRef); |
| output_sym->setValue(pValue); |
| } |
| |
| return output_sym; |
| } |
| |
| /// defineSymbolAsRefered - define an output symbol and override it immediately |
| LDSymbol* MCLinker::defineSymbolAsRefered(const llvm::StringRef& pName, |
| bool pIsDyn, |
| ResolveInfo::Type pType, |
| ResolveInfo::Desc pDesc, |
| ResolveInfo::Binding pBinding, |
| ResolveInfo::SizeType pSize, |
| LDSymbol::ValueType pValue, |
| FragmentRef* pFragmentRef, |
| ResolveInfo::Visibility pVisibility) |
| { |
| ResolveInfo* info = m_LDInfo.getNamePool().findInfo(pName); |
| |
| if (NULL == info || !(info->isUndef() || info->isDyn())) { |
| // only undefined symbol and dynamic symbol can make a reference. |
| return NULL; |
| } |
| |
| // the symbol is already in the pool, override it |
| ResolveInfo old_info; |
| old_info.override(*info); |
| |
| info->setSource(pIsDyn); |
| info->setType(pType); |
| info->setDesc(pDesc); |
| info->setBinding(pBinding); |
| info->setVisibility(pVisibility); |
| info->setIsSymbol(true); |
| info->setSize(pSize); |
| |
| LDSymbol* output_sym = info->outSymbol(); |
| if (NULL != output_sym) { |
| output_sym->setFragmentRef(pFragmentRef); |
| output_sym->setValue(pValue); |
| m_OutputSymbols.arrange(*output_sym, old_info); |
| } |
| else { |
| // create a output LDSymbol |
| output_sym = m_LDSymbolFactory.allocate(); |
| new (output_sym) LDSymbol(); |
| |
| output_sym->setResolveInfo(*info); |
| info->setSymPtr(output_sym); |
| |
| m_OutputSymbols.add(*output_sym); |
| } |
| |
| return output_sym; |
| } |
| |
| /// defineAndResolveSymbolForcefully - define an output symbol and resolve it |
| /// immediately |
| LDSymbol* MCLinker::defineAndResolveSymbolForcefully(const llvm::StringRef& pName, |
| bool pIsDyn, |
| ResolveInfo::Type pType, |
| ResolveInfo::Desc pDesc, |
| ResolveInfo::Binding pBinding, |
| ResolveInfo::SizeType pSize, |
| LDSymbol::ValueType pValue, |
| FragmentRef* pFragmentRef, |
| ResolveInfo::Visibility pVisibility) |
| { |
| // Result is <info, existent, override> |
| Resolver::Result result; |
| ResolveInfo old_info; |
| m_LDInfo.getNamePool().insertSymbol(pName, pIsDyn, pType, pDesc, pBinding, |
| pSize, pVisibility, |
| &old_info, result); |
| |
| LDSymbol* output_sym = result.info->outSymbol(); |
| bool has_output_sym = (NULL != output_sym); |
| |
| if (!result.existent || !has_output_sym) { |
| output_sym = m_LDSymbolFactory.allocate(); |
| new (output_sym) LDSymbol(); |
| output_sym->setResolveInfo(*result.info); |
| result.info->setSymPtr(output_sym); |
| } |
| |
| if (result.overriden || !has_output_sym) { |
| output_sym->setFragmentRef(pFragmentRef); |
| output_sym->setValue(pValue); |
| } |
| |
| // After symbol resolution, the visibility is changed to the most restrict. |
| // arrange the output position |
| if (shouldForceLocal(*result.info)) |
| m_OutputSymbols.forceLocal(*output_sym); |
| else if (has_output_sym) |
| m_OutputSymbols.arrange(*output_sym, old_info); |
| else |
| m_OutputSymbols.add(*output_sym); |
| |
| return output_sym; |
| } |
| |
| /// defineAndResolveSymbolAsRefered - define an output symbol and resolve it |
| /// immediately. |
| LDSymbol* MCLinker::defineAndResolveSymbolAsRefered(const llvm::StringRef& pName, |
| bool pIsDyn, |
| ResolveInfo::Type pType, |
| ResolveInfo::Desc pDesc, |
| ResolveInfo::Binding pBinding, |
| ResolveInfo::SizeType pSize, |
| LDSymbol::ValueType pValue, |
| FragmentRef* pFragmentRef, |
| ResolveInfo::Visibility pVisibility) |
| { |
| ResolveInfo* info = m_LDInfo.getNamePool().findInfo(pName); |
| |
| if (NULL == info || !(info->isUndef() || info->isDyn())) { |
| // only undefined symbol and dynamic symbol can make a reference. |
| return NULL; |
| } |
| |
| return defineAndResolveSymbolForcefully(pName, |
| pIsDyn, |
| pType, |
| pDesc, |
| pBinding, |
| pSize, |
| pValue, |
| pFragmentRef, |
| pVisibility); |
| } |
| |
| bool MCLinker::finalizeSymbols() |
| { |
| SymbolCategory::iterator symbol, symEnd = m_OutputSymbols.end(); |
| for (symbol = m_OutputSymbols.begin(); symbol != symEnd; ++symbol) { |
| |
| if ((*symbol)->resolveInfo()->isAbsolute() || |
| (*symbol)->resolveInfo()->type() == ResolveInfo::File) { |
| // absolute symbols or symbols with function type should have |
| // zero value |
| (*symbol)->setValue(0x0); |
| continue; |
| } |
| |
| if ((*symbol)->hasFragRef()) { |
| // set the virtual address of the symbol. If the output file is |
| // relocatable object file, the section's virtual address becomes zero. |
| // And the symbol's value become section relative offset. |
| uint64_t value = getLayout().getOutputOffset(*(*symbol)->fragRef()); |
| assert(NULL != (*symbol)->fragRef()->frag()); |
| uint64_t addr = getLayout().getOutputLDSection(*(*symbol)->fragRef()->frag())->addr(); |
| (*symbol)->setValue(value + addr); |
| continue; |
| } |
| } |
| |
| // finialize target-dependent symbols |
| return m_Backend.finalizeSymbols(*this, m_LDInfo.output()); |
| } |
| |
| bool MCLinker::shouldForceLocal(const ResolveInfo& pInfo) const |
| { |
| // forced local symbol matches all rules: |
| // 1. We are not doing incremental linking. |
| // 2. The symbol is with Hidden or Internal visibility. |
| // 3. The symbol should be global or weak. Otherwise, local symbol is local. |
| // 4. The symbol is defined or common |
| if (m_LDInfo.output().type() != Output::Object && |
| (pInfo.visibility() == ResolveInfo::Hidden || |
| pInfo.visibility() == ResolveInfo::Internal) && |
| (pInfo.isGlobal() || pInfo.isWeak()) && |
| (pInfo.isDefine() || pInfo.isCommon())) |
| return true; |
| return false; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Section Operations |
| //===----------------------------------------------------------------------===// |
| /// createSectHdr - create the input section header |
| LDSection& MCLinker::createSectHdr(const std::string& pName, |
| LDFileFormat::Kind pKind, |
| uint32_t pType, |
| uint32_t pFlag) |
| { |
| assert(m_LDInfo.output().hasContext()); |
| |
| // for user such as reader, standard/target fromat |
| LDSection* result = |
| m_LDSectHdrFactory.produce(pName, pKind, pType, pFlag); |
| |
| // check if we need to create a output section for output LDContext |
| std::string sect_name = m_SectionMap.getOutputSectName(pName); |
| LDSection* output_sect = m_LDInfo.output().context()->getSection(sect_name); |
| |
| if (NULL == output_sect) { |
| // create a output section and push it into output LDContext |
| output_sect = |
| m_LDSectHdrFactory.produce(sect_name, pKind, pType, pFlag); |
| m_LDInfo.output().context()->getSectionTable().push_back(output_sect); |
| m_pSectionMerger->addMapping(pName, output_sect); |
| } |
| return *result; |
| } |
| |
| /// getOrCreateOutputSectHdr - for reader and standard/target format to get |
| /// or create the output's section header |
| LDSection& MCLinker::getOrCreateOutputSectHdr(const std::string& pName, |
| LDFileFormat::Kind pKind, |
| uint32_t pType, |
| uint32_t pFlag, |
| uint32_t pAlign) |
| { |
| assert(m_LDInfo.output().hasContext()); |
| |
| // check if we need to create a output section for output LDContext |
| std::string sect_name = m_SectionMap.getOutputSectName(pName); |
| LDSection* output_sect = m_LDInfo.output().context()->getSection(sect_name); |
| |
| if (NULL == output_sect) { |
| // create a output section and push it into output LDContext |
| output_sect = |
| m_LDSectHdrFactory.produce(sect_name, pKind, pType, pFlag); |
| output_sect->setAlign(pAlign); |
| m_LDInfo.output().context()->getSectionTable().push_back(output_sect); |
| m_pSectionMerger->addMapping(pName, output_sect); |
| } |
| return *output_sect; |
| } |
| |
| /// getOrCreateSectData - get or create SectionData |
| /// pSection is input LDSection |
| SectionData& MCLinker::getOrCreateSectData(LDSection& pSection) |
| { |
| // if there is already a section data pointed by section, return it. |
| SectionData* sect_data = pSection.getSectionData(); |
| if (NULL != sect_data) { |
| m_Layout.addInputRange(*sect_data, pSection); |
| return *sect_data; |
| } |
| |
| // try to get one from output LDSection |
| LDSection* output_sect = |
| m_pSectionMerger->getOutputSectHdr(pSection.name()); |
| |
| assert(NULL != output_sect); |
| |
| sect_data = output_sect->getSectionData(); |
| |
| if (NULL != sect_data) { |
| pSection.setSectionData(sect_data); |
| m_Layout.addInputRange(*sect_data, pSection); |
| return *sect_data; |
| } |
| |
| // if the output LDSection also has no SectionData, then create one. |
| sect_data = m_LDSectDataFactory.allocate(); |
| new (sect_data) SectionData(*output_sect); |
| pSection.setSectionData(sect_data); |
| output_sect->setSectionData(sect_data); |
| m_Layout.addInputRange(*sect_data, pSection); |
| return *sect_data; |
| } |
| |
| void MCLinker::initSectionMap() |
| { |
| assert(m_LDInfo.output().hasContext()); |
| if (NULL == m_pSectionMerger) |
| m_pSectionMerger = new SectionMerger(m_SectionMap, *m_LDInfo.output().context()); |
| } |
| |
| bool MCLinker::layout() |
| { |
| return m_Layout.layout(m_LDInfo.output(), m_Backend, m_LDInfo); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Relocation Operations |
| //===----------------------------------------------------------------------===// |
| /// addRelocation - add a relocation entry in MCLinker (only for object file) |
| /// |
| /// All symbols should be read and resolved before calling this function. |
| Relocation* MCLinker::addRelocation(Relocation::Type pType, |
| const LDSymbol& pSym, |
| ResolveInfo& pResolveInfo, |
| FragmentRef& pFragmentRef, |
| const LDSection& pSection, |
| Relocation::Address pAddend) |
| { |
| // FIXME: we should dicard sections and symbols first instead |
| // if the symbol is in the discarded input section, then we also need to |
| // discard this relocation. |
| if (pSym.fragRef() == NULL && |
| pResolveInfo.type() == ResolveInfo::Section && |
| pResolveInfo.desc() == ResolveInfo::Undefined) |
| return NULL; |
| |
| Relocation* relocation = m_Backend.getRelocFactory()->produce(pType, |
| pFragmentRef, |
| pAddend); |
| |
| relocation->setSymInfo(&pResolveInfo); |
| |
| m_RelocationList.push_back(relocation); |
| |
| m_Backend.scanRelocation(*relocation, pSym, *this, m_LDInfo, |
| m_LDInfo.output(), pSection); |
| |
| if (pResolveInfo.isUndef() && !pResolveInfo.isDyn() && !pResolveInfo.isWeak()) |
| fatal(diag::undefined_reference) << pResolveInfo.name(); |
| return relocation; |
| } |
| |
| bool MCLinker::applyRelocations() |
| { |
| RelocationListType::iterator relocIter, relocEnd = m_RelocationList.end(); |
| |
| for (relocIter = m_RelocationList.begin(); relocIter != relocEnd; ++relocIter) { |
| Fragment* frag = (Fragment*)relocIter; |
| static_cast<Relocation*>(frag)->apply(*m_Backend.getRelocFactory(), m_LDInfo); |
| } |
| return true; |
| } |
| |
| void MCLinker::syncRelocationResult() |
| { |
| |
| MemoryRegion* region = m_LDInfo.output().memArea()->request(0, |
| m_LDInfo.output().memArea()->handler()->size()); |
| |
| uint8_t* data = region->getBuffer(); |
| |
| RelocationListType::iterator relocIter, relocEnd = m_RelocationList.end(); |
| for (relocIter = m_RelocationList.begin(); relocIter != relocEnd; ++relocIter) { |
| |
| Fragment* frag = (Fragment*)relocIter; |
| Relocation* reloc = static_cast<Relocation*>(frag); |
| |
| // get output file offset |
| size_t out_offset = m_Layout.getOutputLDSection(*reloc->targetRef().frag())->offset() + |
| m_Layout.getOutputOffset(reloc->targetRef()); |
| |
| uint8_t* target_addr = data + out_offset; |
| // byte swapping if target and host has different endian, and then write back |
| if(llvm::sys::isLittleEndianHost() != m_Backend.isLittleEndian()) { |
| uint64_t tmp_data = 0; |
| |
| switch(m_Backend.bitclass()) { |
| case 32u: |
| tmp_data = bswap32(reloc->target()); |
| std::memcpy(target_addr, &tmp_data, 4); |
| break; |
| |
| case 64u: |
| tmp_data = bswap64(reloc->target()); |
| std::memcpy(target_addr, &tmp_data, 8); |
| break; |
| |
| default: |
| break; |
| } |
| } |
| else { |
| std::memcpy(target_addr, &reloc->target(), m_Backend.bitclass()/8); |
| } |
| } // end of for |
| |
| m_LDInfo.output().memArea()->clear(); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Exception Handling Operations |
| //===----------------------------------------------------------------------===// |
| /// addEhFrame - add an exception handling section |
| /// @param pSection - the input section |
| /// @param pArea - the memory area which pSection is within. |
| uint64_t MCLinker::addEhFrame(const Input& pInput, |
| LDSection& pSection, |
| MemoryArea& pArea) |
| { |
| uint64_t size = 0; |
| |
| // get the SectionData of this eh_frame |
| SectionData& sect_data = getOrCreateSectData(pSection); |
| |
| // parse the eh_frame if the option --eh-frame-hdr is given |
| if (m_LDInfo.options().hasEhFrameHdr()) { |
| EhFrame* ehframe = m_Backend.getEhFrame(); |
| assert(NULL != ehframe); |
| if (ehframe->canRecognizeAllEhFrame()) { |
| size = ehframe->readEhFrame(m_Layout, m_Backend, sect_data, pInput, |
| pSection, pArea); |
| // zero size indicate that this is an empty section or we can't recognize |
| // this eh_frame, handle it as a regular section. |
| if (0 != size) |
| return size; |
| } |
| } |
| |
| // handle eh_frame as a regular section |
| MemoryRegion* region = pArea.request(pInput.fileOffset() + pSection.offset(), |
| pSection.size()); |
| |
| Fragment* frag = NULL; |
| if (NULL == region) { |
| // If the input section's size is zero, we got a NULL region. |
| // use a virtual fill fragment |
| frag = new FillFragment(0x0, 0, 0); |
| } |
| else |
| frag = new RegionFragment(*region); |
| |
| size = m_Layout.appendFragment(*frag, sect_data, pSection.align()); |
| return size; |
| } |
| |