//===- IRBuilder.cpp ------------------------------------------------------===// // // The MCLinker Project // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "mcld/IRBuilder.h" #include "mcld/Fragment/FragmentRef.h" #include "mcld/LinkerScript.h" #include "mcld/LD/DebugString.h" #include "mcld/LD/EhFrame.h" #include "mcld/LD/ELFReader.h" #include "mcld/LD/LDContext.h" #include "mcld/LD/RelocData.h" #include "mcld/LD/SectionData.h" #include "mcld/Object/ObjectBuilder.h" #include "mcld/Support/ELF.h" #include "mcld/Support/MemoryArea.h" #include "mcld/Support/MsgHandling.h" #include namespace mcld { //===----------------------------------------------------------------------===// // Helper Functions //===----------------------------------------------------------------------===// LDFileFormat::Kind GetELFSectionKind(uint32_t pType, const char* pName, uint32_t pFlag) { if (pFlag & llvm::ELF::SHF_EXCLUDE) return LDFileFormat::Exclude; if (pFlag & llvm::ELF::SHF_MASKPROC) return LDFileFormat::Target; // name rules llvm::StringRef name(pName); if (name.startswith(".debug") || name.startswith(".zdebug") || name.startswith(".line") || name.startswith(".stab")) { if (name.startswith(".debug_str")) return LDFileFormat::DebugString; return LDFileFormat::Debug; } if (name.startswith(".comment")) return LDFileFormat::MetaData; if (name.startswith(".interp") || name.startswith(".dynamic")) return LDFileFormat::Note; if (name.startswith(".eh_frame")) return LDFileFormat::EhFrame; if (name.startswith(".eh_frame_hdr")) return LDFileFormat::EhFrameHdr; if (name.startswith(".gcc_except_table")) return LDFileFormat::GCCExceptTable; if (name.startswith(".note.GNU-stack")) return LDFileFormat::StackNote; if (name.startswith(".gnu.linkonce")) return LDFileFormat::LinkOnce; // type rules switch (pType) { case llvm::ELF::SHT_NULL: return LDFileFormat::Null; case llvm::ELF::SHT_INIT_ARRAY: case llvm::ELF::SHT_FINI_ARRAY: case llvm::ELF::SHT_PREINIT_ARRAY: case llvm::ELF::SHT_PROGBITS: { if ((pFlag & llvm::ELF::SHF_EXECINSTR) != 0) return LDFileFormat::TEXT; else return LDFileFormat::DATA; } case llvm::ELF::SHT_SYMTAB: case llvm::ELF::SHT_DYNSYM: case llvm::ELF::SHT_STRTAB: case llvm::ELF::SHT_HASH: case llvm::ELF::SHT_DYNAMIC: case llvm::ELF::SHT_SYMTAB_SHNDX: return LDFileFormat::NamePool; case llvm::ELF::SHT_RELA: case llvm::ELF::SHT_REL: return LDFileFormat::Relocation; case llvm::ELF::SHT_NOBITS: return LDFileFormat::BSS; case llvm::ELF::SHT_NOTE: return LDFileFormat::Note; case llvm::ELF::SHT_GROUP: return LDFileFormat::Group; case llvm::ELF::SHT_GNU_versym: case llvm::ELF::SHT_GNU_verdef: case llvm::ELF::SHT_GNU_verneed: return LDFileFormat::Version; case llvm::ELF::SHT_SHLIB: return LDFileFormat::Target; default: if ((pType >= llvm::ELF::SHT_LOPROC && pType <= llvm::ELF::SHT_HIPROC) || (pType >= llvm::ELF::SHT_LOOS && pType <= llvm::ELF::SHT_HIOS) || (pType >= llvm::ELF::SHT_LOUSER && pType <= llvm::ELF::SHT_HIUSER)) return LDFileFormat::Target; fatal(diag::err_unsupported_section) << pName << pType; } return LDFileFormat::MetaData; } //===----------------------------------------------------------------------===// // IRBuilder //===----------------------------------------------------------------------===// IRBuilder::IRBuilder(Module& pModule, const LinkerConfig& pConfig) : m_Module(pModule), m_Config(pConfig), m_InputBuilder(pConfig) { m_InputBuilder.setCurrentTree(m_Module.getInputTree()); // FIXME: where to set up Relocation? Relocation::SetUp(m_Config); } IRBuilder::~IRBuilder() { } /// CreateInput - To create an input file and append it to the input tree. Input* IRBuilder::CreateInput(const std::string& pName, const sys::fs::Path& pPath, Input::Type pType) { if (Input::Unknown == pType) return ReadInput(pName, pPath); m_InputBuilder.createNode(pName, pPath, pType); Input* input = *m_InputBuilder.getCurrentNode(); if (!input->hasContext()) m_InputBuilder.setContext(*input, false); return input; } /// ReadInput - To read an input file and append it to the input tree. Input* IRBuilder::ReadInput(const std::string& pName, const sys::fs::Path& pPath) { m_InputBuilder.createNode( pName, pPath, Input::Unknown); Input* input = *m_InputBuilder.getCurrentNode(); if (!input->hasContext()) m_InputBuilder.setContext(*input); if (!input->hasMemArea()) m_InputBuilder.setMemory(*input, FileHandle::OpenMode(FileHandle::ReadOnly), FileHandle::Permission(FileHandle::System)); return input; } /// ReadInput - To read an input file and append it to the input tree. Input* IRBuilder::ReadInput(const std::string& pNameSpec) { const sys::fs::Path* path = NULL; // find out the real path of the namespec. if (m_InputBuilder.getConstraint().isSharedSystem()) { // In the system with shared object support, we can find both archive // and shared object. if (m_InputBuilder.getAttributes().isStatic()) { // with --static, we must search an archive. path = m_Module.getScript().directories().find(pNameSpec, Input::Archive); } else { // otherwise, with --Bdynamic, we can find either an archive or a // shared object. path = m_Module.getScript().directories().find(pNameSpec, Input::DynObj); } } else { // In the system without shared object support, we only look for an archive path = m_Module.getScript().directories().find(pNameSpec, Input::Archive); } if (path == NULL) { fatal(diag::err_cannot_find_namespec) << pNameSpec; return NULL; } m_InputBuilder.createNode(pNameSpec, *path); Input* input = *m_InputBuilder.getCurrentNode(); if (!input->hasContext()) m_InputBuilder.setContext(*input); if (!input->hasMemArea()) m_InputBuilder.setMemory(*input, FileHandle::OpenMode(FileHandle::ReadOnly), FileHandle::Permission(FileHandle::System)); return input; } /// ReadInput - To read an input file and append it to the input tree. Input* IRBuilder::ReadInput(FileHandle& pFileHandle) { m_InputBuilder.createNode("file handler", pFileHandle.path()); Input* input = *m_InputBuilder.getCurrentNode(); if (pFileHandle.path().empty()) { m_InputBuilder.setContext(*input, false); } else { m_InputBuilder.setContext(*input, true); } m_InputBuilder.setMemory(*input, FileHandle::OpenMode(FileHandle::ReadOnly), FileHandle::Permission(FileHandle::System)); return input; } /// ReadInput - To read an input file and append it to the input tree. Input* IRBuilder::ReadInput(const std::string& pName, void* pRawMemory, size_t pSize) { m_InputBuilder.createNode(pName, sys::fs::Path("NAN")); Input* input = *m_InputBuilder.getCurrentNode(); m_InputBuilder.setContext(*input, false); m_InputBuilder.setMemory(*input, pRawMemory, pSize); return input; } bool IRBuilder::StartGroup() { if (m_InputBuilder.isInGroup()) { fatal(diag::fatal_forbid_nest_group); return false; } m_InputBuilder.enterGroup(); return true; } bool IRBuilder::EndGroup() { m_InputBuilder.exitGroup(); return true; } void IRBuilder::WholeArchive() { m_InputBuilder.getAttributes().setWholeArchive(); } void IRBuilder::NoWholeArchive() { m_InputBuilder.getAttributes().unsetWholeArchive(); } void IRBuilder::AsNeeded() { m_InputBuilder.getAttributes().setAsNeeded(); } void IRBuilder::NoAsNeeded() { m_InputBuilder.getAttributes().unsetAsNeeded(); } void IRBuilder::CopyDTNeeded() { m_InputBuilder.getAttributes().setAddNeeded(); } void IRBuilder::NoCopyDTNeeded() { m_InputBuilder.getAttributes().unsetAddNeeded(); } void IRBuilder::AgainstShared() { m_InputBuilder.getAttributes().setDynamic(); } void IRBuilder::AgainstStatic() { m_InputBuilder.getAttributes().setStatic(); } LDSection* IRBuilder::CreateELFHeader(Input& pInput, const std::string& pName, uint32_t pType, uint32_t pFlag, uint32_t pAlign) { // Create section header LDFileFormat::Kind kind = GetELFSectionKind(pType, pName.c_str(), pFlag); LDSection* header = LDSection::Create(pName, kind, pType, pFlag); header->setAlign(pAlign); // Append section header in input pInput.context()->appendSection(*header); return header; } /// CreateSectionData - To create a section data for given pSection. SectionData* IRBuilder::CreateSectionData(LDSection& pSection) { assert(!pSection.hasSectionData() && "pSection already has section data."); SectionData* sect_data = SectionData::Create(pSection); pSection.setSectionData(sect_data); return sect_data; } /// CreateRelocData - To create a relocation data for given pSection. RelocData* IRBuilder::CreateRelocData(LDSection& pSection) { assert(!pSection.hasRelocData() && "pSection already has relocation data."); RelocData* reloc_data = RelocData::Create(pSection); pSection.setRelocData(reloc_data); return reloc_data; } /// CreateEhFrame - To create a eh_frame for given pSection EhFrame* IRBuilder::CreateEhFrame(LDSection& pSection) { assert(!pSection.hasEhFrame() && "pSection already has eh_frame."); EhFrame* eh_frame = EhFrame::Create(pSection); pSection.setEhFrame(eh_frame); return eh_frame; } /// CreateDebugString - To create a DebugString for given pSection DebugString* IRBuilder::CreateDebugString(LDSection& pSection) { assert(!pSection.hasDebugString() && "pSection already has debug_str."); DebugString* debug_str = DebugString::Create(pSection); pSection.setDebugString(debug_str); return debug_str; } /// CreateBSS - To create a bss section for given pSection SectionData* IRBuilder::CreateBSS(LDSection& pSection) { assert(!pSection.hasSectionData() && "pSection already has section data."); assert((pSection.kind() == LDFileFormat::BSS) && "pSection is not a BSS section."); SectionData* sect_data = SectionData::Create(pSection); pSection.setSectionData(sect_data); /* value, valsize, size*/ FillFragment* frag = new FillFragment(0x0, 1, pSection.size()); ObjectBuilder::AppendFragment(*frag, *sect_data); return sect_data; } /// CreateRegion - To create a region fragment in the input file. Fragment* IRBuilder::CreateRegion(Input& pInput, size_t pOffset, size_t pLength) { if (!pInput.hasMemArea()) { fatal(diag::fatal_cannot_read_input) << pInput.path(); return NULL; } if (0 == pLength) return new FillFragment(0x0, 0, 0); llvm::StringRef region = pInput.memArea()->request(pOffset, pLength); return new RegionFragment(region); } /// CreateRegion - To create a region fragment wrapping the given memory Fragment* IRBuilder::CreateRegion(void* pMemory, size_t pLength) { if (0 == pLength) return new FillFragment(0x0, 0, 0); llvm::StringRef region(reinterpret_cast(pMemory), pLength); return new RegionFragment(region); } /// AppendFragment - To append pFrag to the given SectionData pSD uint64_t IRBuilder::AppendFragment(Fragment& pFrag, SectionData& pSD) { uint64_t size = ObjectBuilder::AppendFragment(pFrag, pSD, pSD.getSection().align()); pSD.getSection().setSize(pSD.getSection().size() + size); return size; } /// AppendRelocation - To append an relocation to the given RelocData pRD. void IRBuilder::AppendRelocation(Relocation& pRelocation, RelocData& pRD) { pRD.append(pRelocation); } /// AppendEhFrame - To append a fragment to EhFrame. uint64_t IRBuilder::AppendEhFrame(Fragment& pFrag, EhFrame& pEhFrame) { uint64_t size = ObjectBuilder::AppendFragment( pFrag, *pEhFrame.getSectionData(), pEhFrame.getSection().align()); pEhFrame.getSection().setSize(pEhFrame.getSection().size() + size); return size; } /// AppendEhFrame - To append a FDE to the given EhFrame pEhFram. uint64_t IRBuilder::AppendEhFrame(EhFrame::FDE& pFDE, EhFrame& pEhFrame) { pEhFrame.addFDE(pFDE); pEhFrame.getSection().setSize(pEhFrame.getSection().size() + pFDE.size()); return pFDE.size(); } /// AppendEhFrame - To append a CIE to the given EhFrame pEhFram. uint64_t IRBuilder::AppendEhFrame(EhFrame::CIE& pCIE, EhFrame& pEhFrame) { pEhFrame.addCIE(pCIE); pEhFrame.getSection().setSize(pEhFrame.getSection().size() + pCIE.size()); return pCIE.size(); } /// AddSymbol - To add a symbol in the input file and resolve the symbol /// immediately LDSymbol* IRBuilder::AddSymbol(Input& pInput, const std::string& pName, ResolveInfo::Type pType, ResolveInfo::Desc pDesc, ResolveInfo::Binding pBind, ResolveInfo::SizeType pSize, LDSymbol::ValueType pValue, LDSection* pSection, ResolveInfo::Visibility pVis) { // rename symbols std::string name = pName; if (!m_Module.getScript().renameMap().empty() && ResolveInfo::Undefined == pDesc) { // If the renameMap is not empty, some symbols should be renamed. // --wrap and --portable defines the symbol rename map. const LinkerScript& script = m_Module.getScript(); LinkerScript::SymbolRenameMap::const_iterator renameSym = script.renameMap().find(pName); if (script.renameMap().end() != renameSym) name = renameSym.getEntry()->value(); } // Fix up the visibility if object has no export set. if (pInput.noExport() && (pDesc != ResolveInfo::Undefined)) { if ((pVis == ResolveInfo::Default) || (pVis == ResolveInfo::Protected)) { pVis = ResolveInfo::Hidden; } } switch (pInput.type()) { case Input::Object: { FragmentRef* frag = NULL; if (pSection == NULL || ResolveInfo::Undefined == pDesc || ResolveInfo::Common == pDesc || ResolveInfo::Absolute == pBind || LDFileFormat::Ignore == pSection->kind() || LDFileFormat::Group == pSection->kind()) frag = FragmentRef::Null(); else frag = FragmentRef::Create(*pSection, pValue); LDSymbol* input_sym = addSymbolFromObject( name, pType, pDesc, pBind, pSize, pValue, frag, pVis); pInput.context()->addSymbol(input_sym); return input_sym; } case Input::DynObj: { return addSymbolFromDynObj( pInput, name, pType, pDesc, pBind, pSize, pValue, pVis); } default: { return NULL; break; } } return NULL; } LDSymbol* IRBuilder::addSymbolFromObject(const std::string& pName, ResolveInfo::Type pType, ResolveInfo::Desc pDesc, ResolveInfo::Binding pBinding, ResolveInfo::SizeType pSize, LDSymbol::ValueType pValue, FragmentRef* pFragmentRef, ResolveInfo::Visibility pVisibility) { // Step 1. calculate a Resolver::Result // resolved_result is a triple 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_Module.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_Module.getNamePool().insertSymbol(pName, false, pType, pDesc, pBinding, pSize, pValue, pVisibility, &old_info, resolved_result); } // the return ResolveInfo should not NULL assert(resolved_result.info != NULL); /// Step 2. create an input LDSymbol. // create a LDSymbol for the input file. LDSymbol* input_sym = LDSymbol::Create(*resolved_result.info); input_sym->setFragmentRef(pFragmentRef); input_sym->setValue(pValue); // Step 3. Set up corresponding output LDSymbol LDSymbol* output_sym = resolved_result.info->outSymbol(); bool has_output_sym = (output_sym != NULL); if (!resolved_result.existent || !has_output_sym) { // it is a new symbol, the output_sym should be NULL. assert(output_sym == NULL); if (pType == ResolveInfo::Section) { // if it is a section symbol, its output LDSymbol is the input LDSymbol. output_sym = input_sym; } else { // if it is a new symbol, create a LDSymbol for the output output_sym = LDSymbol::Create(*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); } return input_sym; } LDSymbol* IRBuilder::addSymbolFromDynObj(Input& pInput, const std::string& pName, ResolveInfo::Type pType, ResolveInfo::Desc pDesc, ResolveInfo::Binding pBinding, ResolveInfo::SizeType pSize, LDSymbol::ValueType pValue, ResolveInfo::Visibility pVisibility) { // We don't need sections of dynamic objects. So we ignore section symbols. 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 Resolver::Result resolved_result; m_Module.getNamePool().insertSymbol(pName, true, pType, pDesc, pBinding, pSize, pValue, pVisibility, NULL, resolved_result); // the return ResolveInfo should not NULL assert(resolved_result.info != NULL); if (resolved_result.overriden || !resolved_result.existent) pInput.setNeeded(); // create a LDSymbol for the input file. LDSymbol* input_sym = LDSymbol::Create(*resolved_result.info); input_sym->setFragmentRef(FragmentRef::Null()); input_sym->setValue(pValue); // this symbol is seen in a dynamic object, set the InDyn flag resolved_result.info->setInDyn(); if (!resolved_result.existent) { // we get a new symbol, leave it as NULL resolved_result.info->setSymPtr(NULL); } return input_sym; } /// AddRelocation - add a relocation entry /// /// All symbols should be read and resolved before calling this function. Relocation* IRBuilder::AddRelocation(LDSection& pSection, Relocation::Type pType, LDSymbol& pSym, uint32_t pOffset, Relocation::Address pAddend) { FragmentRef* frag_ref = FragmentRef::Create(*pSection.getLink(), pOffset); Relocation* relocation = Relocation::Create(pType, *frag_ref, pAddend); relocation->setSymInfo(pSym.resolveInfo()); pSection.getRelocData()->append(*relocation); return relocation; } ResolveInfo* IRBuilder::CreateLocalSymbol(FragmentRef& pFragRef) { // Create and add symbol to the name pool. ResolveInfo* resolveInfo = m_Module.getNamePool().createSymbol(/* pName */"", /* pIsDyn */false, ResolveInfo::Section, ResolveInfo::Define, ResolveInfo::Local, /* pSize */0, ResolveInfo::Hidden); if (resolveInfo == nullptr) { return nullptr; } // Create input symbol. LDSymbol* inputSym = LDSymbol::Create(*resolveInfo); if (inputSym == nullptr) { return nullptr; } inputSym->setFragmentRef(FragmentRef::Create(*pFragRef.frag(), pFragRef.offset())); inputSym->setValue(/* pValue */0); // The output symbol is simply an alias to the input symbol. resolveInfo->setSymPtr(inputSym); return resolveInfo; } /// AddSymbol - define an output symbol and override it immediately template <> LDSymbol* IRBuilder::AddSymbol( const llvm::StringRef& pName, ResolveInfo::Type pType, ResolveInfo::Desc pDesc, ResolveInfo::Binding pBinding, ResolveInfo::SizeType pSize, LDSymbol::ValueType pValue, FragmentRef* pFragmentRef, ResolveInfo::Visibility pVisibility) { ResolveInfo* info = m_Module.getNamePool().findInfo(pName); LDSymbol* output_sym = NULL; if (info == NULL) { // the symbol is not in the pool, create a new one. // create a ResolveInfo Resolver::Result result; m_Module.getNamePool().insertSymbol(pName, false, pType, pDesc, pBinding, pSize, pValue, pVisibility, NULL, result); assert(!result.existent); // create a output LDSymbol output_sym = LDSymbol::Create(*result.info); result.info->setSymPtr(output_sym); if (result.info->shouldForceLocal(m_Config)) m_Module.getSymbolTable().forceLocal(*output_sym); else m_Module.getSymbolTable().add(*output_sym); } else { // the symbol is already in the pool, override it ResolveInfo old_info; old_info.override(*info); info->setRegular(); info->setType(pType); info->setDesc(pDesc); info->setBinding(pBinding); info->setVisibility(pVisibility); info->setIsSymbol(true); info->setSize(pSize); output_sym = info->outSymbol(); if (output_sym != NULL) m_Module.getSymbolTable().arrange(*output_sym, old_info); else { // create a output LDSymbol output_sym = LDSymbol::Create(*info); info->setSymPtr(output_sym); m_Module.getSymbolTable().add(*output_sym); } } if (output_sym != NULL) { output_sym->setFragmentRef(pFragmentRef); output_sym->setValue(pValue); } return output_sym; } /// AddSymbol - define an output symbol and override it immediately template <> LDSymbol* IRBuilder::AddSymbol( const llvm::StringRef& pName, ResolveInfo::Type pType, ResolveInfo::Desc pDesc, ResolveInfo::Binding pBinding, ResolveInfo::SizeType pSize, LDSymbol::ValueType pValue, FragmentRef* pFragmentRef, ResolveInfo::Visibility pVisibility) { ResolveInfo* info = m_Module.getNamePool().findInfo(pName); if (info == NULL || !(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->setRegular(); info->setType(pType); info->setDesc(pDesc); info->setBinding(pBinding); info->setVisibility(pVisibility); info->setIsSymbol(true); info->setSize(pSize); LDSymbol* output_sym = info->outSymbol(); if (output_sym != NULL) { output_sym->setFragmentRef(pFragmentRef); output_sym->setValue(pValue); m_Module.getSymbolTable().arrange(*output_sym, old_info); } else { // create a output LDSymbol output_sym = LDSymbol::Create(*info); info->setSymPtr(output_sym); m_Module.getSymbolTable().add(*output_sym); } return output_sym; } /// AddSymbol - define an output symbol and resolve it /// immediately template <> LDSymbol* IRBuilder::AddSymbol( const llvm::StringRef& pName, ResolveInfo::Type pType, ResolveInfo::Desc pDesc, ResolveInfo::Binding pBinding, ResolveInfo::SizeType pSize, LDSymbol::ValueType pValue, FragmentRef* pFragmentRef, ResolveInfo::Visibility pVisibility) { // Result is Resolver::Result result; ResolveInfo old_info; m_Module.getNamePool().insertSymbol(pName, false, pType, pDesc, pBinding, pSize, pValue, pVisibility, &old_info, result); LDSymbol* output_sym = result.info->outSymbol(); bool has_output_sym = (output_sym != NULL); if (!result.existent || !has_output_sym) { output_sym = LDSymbol::Create(*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 (result.info->shouldForceLocal(m_Config)) m_Module.getSymbolTable().forceLocal(*output_sym); else if (has_output_sym) m_Module.getSymbolTable().arrange(*output_sym, old_info); else m_Module.getSymbolTable().add(*output_sym); return output_sym; } /// defineSymbol - define an output symbol and resolve it immediately. template <> LDSymbol* IRBuilder::AddSymbol( const llvm::StringRef& pName, ResolveInfo::Type pType, ResolveInfo::Desc pDesc, ResolveInfo::Binding pBinding, ResolveInfo::SizeType pSize, LDSymbol::ValueType pValue, FragmentRef* pFragmentRef, ResolveInfo::Visibility pVisibility) { ResolveInfo* info = m_Module.getNamePool().findInfo(pName); if (info == NULL || !(info->isUndef() || info->isDyn())) { // only undefined symbol and dynamic symbol can make a reference. return NULL; } return AddSymbol( pName, pType, pDesc, pBinding, pSize, pValue, pFragmentRef, pVisibility); } } // namespace mcld