//===----------------------------------------------------------------------===// // 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; } }
/// configure the output filename bool OutputFormatOptions::parseOutput(Module& pModule, LinkerConfig& pConfig) { if (true == m_Shared || true == m_PIE) { // -shared or -pie m_FileType = mcld::LinkerConfig::DynObj; } else if (true == m_Relocatable) { // partial linking m_FileType = mcld::LinkerConfig::Object; } else if (mcld::LinkerConfig::Binary == m_OFormat) { // binary output m_FileType = mcld::LinkerConfig::Binary; } pConfig.setCodeGenType(m_FileType); std::string output_filename(m_OutputFilename.native()); if (m_OutputFilename.empty()) { if (llvm::Triple::Win32 == pConfig.targets().triple().getOS()) { output_filename.assign("_out"); switch (m_FileType) { case mcld::LinkerConfig::Object: { output_filename += ".obj"; break; } case mcld::LinkerConfig::DynObj: { output_filename += ".dll"; break; } case mcld::LinkerConfig::Exec: { output_filename += ".exe"; break; } case mcld::LinkerConfig::External: break; default: { return false; break; } } // switch } else { if (mcld::LinkerConfig::Object == m_FileType || mcld::LinkerConfig::DynObj == m_FileType || mcld::LinkerConfig::Exec == m_FileType || mcld::LinkerConfig::External == m_FileType) { output_filename.assign("a.out"); } else { return false; } } } // end of if empty m_OutputFilename pModule.setName(output_filename); return true; }
// FIXME: LinkerConfig& pConfig should be constant bool MCLDEmulateELF(LinkerScript& pScript, LinkerConfig& pConfig) { // set up section map if (pConfig.options().getScriptList().empty() && pConfig.codeGenType() != LinkerConfig::Object) { const unsigned int map_size = (sizeof(map) / sizeof(map[0])); for (unsigned int i = 0; i < map_size; ++i) { std::pair<SectionMap::mapping, bool> res = pScript.sectionMap().insert(map[i].from, map[i].to, map[i].policy); if (!res.second) return false; } } else { // FIXME: this is the hack to help assignment processing in current // implementation. pScript.sectionMap().insert("", ""); } if (!pConfig.options().nostdlib()) { // TODO: check if user sets the default search path instead via -Y option // set up default search path switch (pConfig.targets().triple().getOS()) { case llvm::Triple::NetBSD: pScript.directories().insert("=/usr/lib"); break; case llvm::Triple::Win32: pScript.directories().insert("=/mingw/lib"); break; default: pScript.directories().insert("=/lib"); pScript.directories().insert("=/usr/lib"); break; } } return true; }
static bool MCLDEmulateX86ELF(LinkerScript& pScript, LinkerConfig& pConfig) { if (!MCLDEmulateELF(pScript, pConfig)) return false; // set up bitclass and endian pConfig.targets().setEndian(TargetOptions::Little); unsigned int bitclass; 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) { bitclass = 32; } else { bitclass = 64; } pConfig.targets().setBitClass(bitclass); // set up target-dependent constraints of attributes pConfig.attribute().constraint().enableWholeArchive(); pConfig.attribute().constraint().enableAsNeeded(); pConfig.attribute().constraint().setSharedSystem(); // set up the predefined attributes pConfig.attribute().predefined().unsetWholeArchive(); pConfig.attribute().predefined().unsetAsNeeded(); pConfig.attribute().predefined().setDynamic(); return true; }
static bool MCLDEmulateARMELF(LinkerScript& pScript, LinkerConfig& pConfig) { if (!MCLDEmulateELF(pScript, pConfig)) return false; // set up bitclass and endian pConfig.targets().setEndian(TargetOptions::Little); pConfig.targets().setBitClass(32); // set up target-dependent constraints of attributes pConfig.attribute().constraint().enableWholeArchive(); pConfig.attribute().constraint().enableAsNeeded(); pConfig.attribute().constraint().setSharedSystem(); // set up the predefined attributes pConfig.attribute().predefined().unsetWholeArchive(); pConfig.attribute().predefined().unsetAsNeeded(); pConfig.attribute().predefined().setDynamic(); // set up section map if (pConfig.options().getScriptList().empty() && pConfig.codeGenType() != LinkerConfig::Object) { pScript.sectionMap().insert(".ARM.exidx*", ".ARM.exidx"); pScript.sectionMap().insert(".ARM.extab*", ".ARM.extab"); pScript.sectionMap().insert(".ARM.attributes*", ".ARM.attributes"); } return true; }
bool SearchPathOptions::parse(LinkerConfig& pConfig, LinkerScript& pScript) { // set --sysroot if (!m_SysRoot.empty()) { if (exists(m_SysRoot) && is_directory(m_SysRoot)) pScript.setSysroot(m_SysRoot); } // set -L[path] llvm::cl::list<std::string>::iterator sd; llvm::cl::list<std::string>::iterator sdEnd = m_SearchDirList.end(); for (sd = m_SearchDirList.begin(); sd != sdEnd; ++sd) { if (!pScript.directories().insert(*sd)) { // FIXME: need a warning function errs() << "WARNING: can not open search directory `-L" << *sd << "'.\n"; } } // set -no-stdlib pConfig.options().setNoStdlib(m_NoStdlib); // set --rpath [path] llvm::cl::list<std::string>::iterator rp; llvm::cl::list<std::string>::iterator rpEnd = m_RuntimePath.end(); for (rp = m_RuntimePath.begin(); rp != rpEnd; ++rp) { pConfig.options().getRpathList().push_back(*rp); } return true; }
void ELFObjectWriter::writeELFHeader(const LinkerConfig& pConfig, const Module& pModule, MemoryArea& pOutput) const { typedef typename ELFSizeTraits<SIZE>::Ehdr ElfXX_Ehdr; typedef typename ELFSizeTraits<SIZE>::Shdr ElfXX_Shdr; typedef typename ELFSizeTraits<SIZE>::Phdr ElfXX_Phdr; // ELF header must start from 0x0 MemoryRegion *region = pOutput.request(0, sizeof(ElfXX_Ehdr)); ElfXX_Ehdr* header = (ElfXX_Ehdr*)region->start(); memcpy(header->e_ident, ElfMagic, EI_MAG3+1); header->e_ident[EI_CLASS] = (SIZE == 32) ? ELFCLASS32 : ELFCLASS64; header->e_ident[EI_DATA] = pConfig.targets().isLittleEndian()? ELFDATA2LSB : ELFDATA2MSB; header->e_ident[EI_VERSION] = target().getInfo().ELFVersion(); header->e_ident[EI_OSABI] = target().getInfo().OSABI(); header->e_ident[EI_ABIVERSION] = target().getInfo().ABIVersion(); // FIXME: add processor-specific and core file types. switch(pConfig.codeGenType()) { case LinkerConfig::Object: header->e_type = ET_REL; break; case LinkerConfig::DynObj: header->e_type = ET_DYN; break; case LinkerConfig::Exec: header->e_type = ET_EXEC; break; default: llvm::errs() << "unspported output file type: " << pConfig.codeGenType() << ".\n"; header->e_type = ET_NONE; } header->e_machine = target().getInfo().machine(); header->e_version = header->e_ident[EI_VERSION]; header->e_entry = getEntryPoint(pConfig, pModule); if (LinkerConfig::Object != pConfig.codeGenType()) header->e_phoff = sizeof(ElfXX_Ehdr); else header->e_phoff = 0x0; header->e_shoff = getLastStartOffset<SIZE>(pModule); header->e_flags = target().getInfo().flags(); header->e_ehsize = sizeof(ElfXX_Ehdr); header->e_phentsize = sizeof(ElfXX_Phdr); header->e_phnum = target().elfSegmentTable().size(); header->e_shentsize = sizeof(ElfXX_Shdr); header->e_shnum = pModule.size(); header->e_shstrndx = pModule.getSection(".shstrtab")->index(); }
//===----------------------------------------------------------------------===// // ELFDynObjReader //===----------------------------------------------------------------------===// ELFDynObjReader::ELFDynObjReader(GNULDBackend& pBackend, IRBuilder& pBuilder, const LinkerConfig& pConfig) : DynObjReader(), m_pELFReader(0), m_Builder(pBuilder) { if (pConfig.targets().is32Bits() && pConfig.targets().isLittleEndian()) m_pELFReader = new ELFReader<32, true>(pBackend); else if (pConfig.targets().is64Bits() && pConfig.targets().isLittleEndian()) m_pELFReader = new ELFReader<64, true>(pBackend); }
//===----------------------------------------------------------------------===// // emulateX86LD - the help function to emulate X86 ld //===----------------------------------------------------------------------===// bool emulateX86LD(LinkerScript& pScript, LinkerConfig& pConfig) { if (pConfig.targets().triple().isOSDarwin()) { assert(0 && "MachO linker has not supported yet"); return false; } if (pConfig.targets().triple().isOSWindows()) { assert(0 && "COFF linker has not supported yet"); return false; } return MCLDEmulateX86ELF(pScript, pConfig); }
bool TargetControlOptions::parse(LinkerConfig& pConfig) { // set -G [size] pConfig.options().setGPSize(m_GPSize); // set --warn-shared-textrel pConfig.options().setWarnSharedTextrel(m_WarnSharedTextrel); // set --fix-cortex-a8 if (m_FIXCA8) mcld::warning(mcld::diag::warn_unsupported_option) << m_FIXCA8.ArgStr; return true; }
/// emitRelocation void ELFObjectWriter::emitRelocation(const LinkerConfig& pConfig, const LDSection& pSection, MemoryRegion& pRegion) const { const RelocData* sect_data = pSection.getRelocData(); assert(NULL != sect_data && "SectionData is NULL in emitRelocation!"); if (pSection.type() == SHT_REL) { if (pConfig.targets().is32Bits()) emitRel<32>(pConfig, *sect_data, pRegion); else if (pConfig.targets().is64Bits()) emitRel<64>(pConfig, *sect_data, pRegion); else { fatal(diag::unsupported_bitclass) << pConfig.targets().triple().str() << pConfig.targets().bitclass(); } } else if (pSection.type() == SHT_RELA) { if (pConfig.targets().is32Bits()) emitRela<32>(pConfig, *sect_data, pRegion); else if (pConfig.targets().is64Bits()) emitRela<64>(pConfig, *sect_data, pRegion); else { fatal(diag::unsupported_bitclass) << pConfig.targets().triple().str() << pConfig.targets().bitclass(); } } else llvm::report_fatal_error("unsupported relocation section type!"); }
enum Linker::ErrorCode Linker::extractFiles(const LinkerConfig& pConfig) { mLDConfig = pConfig.getLDConfig(); if (mLDConfig == NULL) { return kDelegateLDInfo; } return kSuccess; }
bool DynamicSectionOptions::parse(LinkerConfig& pConfig, LinkerScript& pScript) { // set up entry point from -e pScript.setEntry(m_Entry); // --Bsymbolic pConfig.options().setBsymbolic(m_Bsymbolic); // --Bgroup pConfig.options().setBgroup(m_Bgroup); // set --soname [soname] pConfig.options().setSOName(m_SOName); // set -z options llvm::cl::list<ZOption>::iterator zOpt; llvm::cl::list<ZOption>::iterator zOptEnd = m_ZOptionList.end(); for (zOpt = m_ZOptionList.begin(); zOpt != zOptEnd; ++zOpt) { pConfig.options().addZOption(*zOpt); } // set --no-undefined if (llvm::cl::BOU_UNSET != m_NoUndefined) pConfig.options().setNoUndefined(llvm::cl::BOU_TRUE == m_NoUndefined); // set --allow-multiple-definition if (llvm::cl::BOU_UNSET != m_AllowMulDefs) pConfig.options().setMulDefs(llvm::cl::BOU_TRUE == m_AllowMulDefs); // set --dynamic-linker [dyld] pConfig.options().setDyld(m_Dyld); // set --enable-new-dtags pConfig.options().setNewDTags(m_EnableNewDTags); // set --auxiliary, -f llvm::cl::list<std::string>::iterator aux; llvm::cl::list<std::string>::iterator auxEnd = m_Auxiliary.end(); for (aux = m_Auxiliary.begin(); aux != auxEnd; ++aux) pConfig.options().getAuxiliaryList().push_back(*aux); // set --filter, -F pConfig.options().setFilter(m_Filter); return true; }
//===----------------------------------------------------------------------===// // Testcases //===----------------------------------------------------------------------===// TEST_F(ELFBinaryReaderTest, is_myformat) { LinkerScript script; Module module("test", script); LinkerConfig config; IRBuilder builder(module, config); ELFBinaryReader* reader = new ELFBinaryReader(builder, config); Input input("test.bin"); bool doContinue = false; config.options().setBinaryInput(); ASSERT_TRUE(reader->isMyFormat(input, doContinue)); config.options().setBinaryInput(false); ASSERT_FALSE(reader->isMyFormat(input, doContinue)); delete reader; }
//===----------------------------------------------------------------------===// // ELFObjectReader //===----------------------------------------------------------------------===// /// constructor ELFObjectReader::ELFObjectReader(GNULDBackend& pBackend, IRBuilder& pBuilder, const LinkerConfig& pConfig) : ObjectReader(), m_pELFReader(NULL), m_pEhFrameReader(NULL), m_Builder(pBuilder), m_ReadFlag(ParseEhFrame), m_Backend(pBackend), m_Config(pConfig) { if (pConfig.targets().is32Bits() && pConfig.targets().isLittleEndian()) { m_pELFReader = new ELFReader<32, true>(pBackend); } else if (pConfig.targets().is64Bits() && pConfig.targets().isLittleEndian()) { m_pELFReader = new ELFReader<64, true>(pBackend); } m_pEhFrameReader = new EhFrameReader(); }
/// getEntryPoint uint64_t ELFObjectWriter::getEntryPoint(const LinkerConfig& pConfig, const Module& pModule) const { llvm::StringRef entry_name; if (pConfig.options().hasEntry()) entry_name = pConfig.options().entry(); else entry_name = target().getInfo().entry(); uint64_t result = 0x0; bool issue_warning = (pConfig.options().hasEntry() && LinkerConfig::Object != pConfig.codeGenType() && LinkerConfig::DynObj != pConfig.codeGenType()); const LDSymbol* entry_symbol = pModule.getNamePool().findSymbol(entry_name); // found the symbol if (NULL != entry_symbol) { if (entry_symbol->desc() != ResolveInfo::Define && issue_warning) { llvm::errs() << "WARNING: entry symbol '" << entry_symbol->name() << "' exists but is not defined.\n"; } result = entry_symbol->value(); } // not in the symbol pool else { // We should parse entry as a number. // @ref GNU ld manual, Options -e. e.g., -e 0x1000. char* endptr; result = strtoull(entry_name.data(), &endptr, 0); if (*endptr != '\0') { if (issue_warning) { llvm::errs() << "cannot find entry symbol '" << entry_name.data() << "'.\n"; } result = 0x0; } } return result; }
void ELFObjectWriter::emitRela(const LinkerConfig& pConfig, const RelocData& pRelocData, MemoryRegion& pRegion) const { typedef typename ELFSizeTraits<SIZE>::Rela ElfXX_Rela; typedef typename ELFSizeTraits<SIZE>::Addr ElfXX_Addr; typedef typename ELFSizeTraits<SIZE>::Word ElfXX_Word; ElfXX_Rela* rel = reinterpret_cast<ElfXX_Rela*>(pRegion.start()); const Relocation* relocation = 0; const FragmentRef* frag_ref = 0; for (RelocData::const_iterator it = pRelocData.begin(), ie = pRelocData.end(); it != ie; ++it, ++rel) { ElfXX_Addr r_offset = 0; ElfXX_Word r_sym = 0; relocation = &(llvm::cast<Relocation>(*it)); frag_ref = &(relocation->targetRef()); if(LinkerConfig::DynObj == pConfig.codeGenType() || LinkerConfig::Exec == pConfig.codeGenType()) { r_offset = static_cast<ElfXX_Addr>( frag_ref->frag()->getParent()->getSection().addr() + frag_ref->getOutputOffset()); } else { r_offset = static_cast<ElfXX_Addr>(frag_ref->getOutputOffset()); } if( relocation->symInfo() == NULL ) r_sym = 0; else r_sym = static_cast<ElfXX_Word>( target().getSymbolIdx(relocation->symInfo()->outSymbol())); target().emitRelocation(*rel, relocation->type(), r_sym, r_offset, relocation->addend()); } }
bool OptimizationOptions::parse(LinkerConfig& pConfig) { // set --gc-sections if (m_GCSections) pConfig.options().setGCSections(); // set --ld-generated-unwind-info (or not) pConfig.options().setGenUnwindInfo(m_GenUnwindInfo); // set --icf [mode] switch (m_ICF) { case ICF_None: break; case ICF_All: case ICF_Safe: default: warning(mcld::diag::warn_unsupported_option) << m_ICF.ArgStr; break; } return true; }
Linker::Linker(const LinkerConfig& pConfig) : mLDConfig(NULL), mModule(NULL), mLinker(NULL), mBuilder(NULL), mOutputHandler(-1) { const std::string &triple = pConfig.getTriple(); enum ErrorCode err = config(pConfig); if (kSuccess != err) { ALOGE("%s (%s)", GetErrorString(err), triple.c_str()); return; } return; }
static bool MCLDEmulateHexagonELF(LinkerConfig& pConfig) { if (!MCLDEmulateELF(pConfig)) return false; // set up bitclass and endian pConfig.targets().setEndian(TargetOptions::Little); pConfig.targets().setBitClass(32); // set up target-dependent constraints of attributes pConfig.attribute().constraint().enableWholeArchive(); pConfig.attribute().constraint().enableAsNeeded(); pConfig.attribute().constraint().setSharedSystem(); // set up the predefined attributes pConfig.attribute().predefined().unsetWholeArchive(); pConfig.attribute().predefined().unsetAsNeeded(); pConfig.attribute().predefined().setDynamic(); return true; }
/// getSectLink - compute ElfXX_Shdr::sh_link uint64_t ELFObjectWriter::getSectLink(const LDSection& pSection, const LinkerConfig& pConfig) const { if (llvm::ELF::SHT_SYMTAB == pSection.type()) return target().getOutputFormat()->getStrTab().index(); if (llvm::ELF::SHT_DYNSYM == pSection.type()) return target().getOutputFormat()->getDynStrTab().index(); if (llvm::ELF::SHT_DYNAMIC == pSection.type()) return target().getOutputFormat()->getDynStrTab().index(); if (llvm::ELF::SHT_HASH == pSection.type() || llvm::ELF::SHT_GNU_HASH == pSection.type()) return target().getOutputFormat()->getDynSymTab().index(); if (llvm::ELF::SHT_REL == pSection.type() || llvm::ELF::SHT_RELA == pSection.type()) { if (LinkerConfig::Object == pConfig.codeGenType()) return target().getOutputFormat()->getSymTab().index(); else return target().getOutputFormat()->getDynSymTab().index(); } // FIXME: currently we link ARM_EXIDX section to output text section here if (llvm::ELF::SHT_ARM_EXIDX == pSection.type()) return target().getOutputFormat()->getText().index(); return llvm::ELF::SHN_UNDEF; }
bool OutputFormatOptions::parse(mcld::Module& pModule, LinkerConfig& pConfig) { if (!parseOutput(pModule, pConfig)) { mcld::unreachable(mcld::diag::unrecognized_output_file) << pModule.name(); return false; } if (mcld::Input::Binary == m_Format) pConfig.options().setBinaryInput(); pConfig.options().setStripDebug(m_StripDebug || m_StripAll); if (m_StripAll) pConfig.options().setStripSymbols(mcld::GeneralOptions::StripAllSymbols); else if (m_DiscardAll) pConfig.options().setStripSymbols(mcld::GeneralOptions::StripLocals); else if (m_DiscardLocals) pConfig.options().setStripSymbols(mcld::GeneralOptions::StripTemporaries); else pConfig.options().setStripSymbols(mcld::GeneralOptions::KeepAllSymbols); pConfig.options().setEhFrameHdr(m_EhFrameHdr); pConfig.options().setPIE(m_PIE); pConfig.options().setNMagic(m_NMagic); pConfig.options().setOMagic(m_OMagic); pConfig.options().setHashStyle(m_HashStyle); pConfig.options().setExportDynamic(m_ExportDynamic); if (m_NoWarnMismatch) pConfig.options().setWarnMismatch(false); else pConfig.options().setWarnMismatch(true); // build-id // exclude-libs return true; }
/// includeMember - include the object member in the given file offset, and /// return the size of the object /// @param pConfig - LinkerConfig /// @param pArchiveRoot - the archive root /// @param pFileOffset - file offset of the member header in the archive size_t GNUArchiveReader::includeMember(const LinkerConfig& pConfig, Archive& pArchive, uint32_t pFileOffset) { Input* cur_archive = &(pArchive.getARFile()); Input* member = NULL; uint32_t file_offset = pFileOffset; size_t size = 0; do { uint32_t nested_offset = 0; // use the file offset in current archive to find out the member we // want to include member = readMemberHeader(pArchive, *cur_archive, file_offset, nested_offset, size); assert(member != NULL); // bypass if we get an archive that is already in the map if (Input::Archive == member->type()) { cur_archive = member; file_offset = nested_offset; continue; } // insert a node into the subtree of current archive. Archive::ArchiveMember* parent = pArchive.getArchiveMember(cur_archive->name()); assert(NULL != parent); pArchive.inputs().insert(parent->lastPos, *(parent->move), *member); // move the iterator to new created node, and also adjust the // direction to Afterward for next insertion in this subtree parent->move->move(parent->lastPos); parent->move = &InputTree::Afterward; bool doContinue = false; if (m_ELFObjectReader.isMyFormat(*member, doContinue)) { member->setType(Input::Object); pArchive.addObjectMember(pFileOffset, parent->lastPos); m_ELFObjectReader.readHeader(*member); m_ELFObjectReader.readSections(*member); m_ELFObjectReader.readSymbols(*member); m_Module.getObjectList().push_back(member); } else if (doContinue && isMyFormat(*member, doContinue)) { member->setType(Input::Archive); // when adding a new archive node, set the iterator to archive // itself, and set the direction to Downward pArchive.addArchiveMember(member->name(), parent->lastPos, &InputTree::Downward); cur_archive = member; file_offset = nested_offset; } else { warning(diag::warn_unrecognized_input_file) << member->path() << pConfig.targets().triple().str(); } } while (Input::Object != member->type()); return size; }
bool GroupReader::readGroup(Module::input_iterator pRoot, InputBuilder& pBuilder, const LinkerConfig& pConfig) { // record the number of total objects included in this sub-tree size_t cur_obj_cnt = 0; size_t last_obj_cnt = 0; size_t non_ar_obj_cnt = 0; // record the archive files in this sub-tree typedef std::vector<ArchiveListEntry*> ArchiveListType; ArchiveListType ar_list; Module::input_iterator input = --pRoot; // Since the end of a sub-tree is the same node to the end of whole tree, we // take the end of the whole input tree for conventience. Module::input_iterator input_end = m_Module.input_end(); // first time read the sub-tree while (input != input_end) { // already got type - for example, bitcode or external OIR (object // intermediate representation) if ((*input)->type() == Input::Script || (*input)->type() == Input::Object || (*input)->type() == Input::DynObj || (*input)->type() == Input::Archive || (*input)->type() == Input::External) { ++input; continue; } // is an archive if (m_ArchiveReader.isMyFormat(**input)) { (*input)->setType(Input::Archive); // record the Archive used by each archive node Archive* ar = new Archive(**input, pBuilder); ArchiveListEntry* entry = new ArchiveListEntry(*ar, input); ar_list.push_back(entry); // read archive m_ArchiveReader.readArchive(*ar); cur_obj_cnt += ar->numOfObjectMember(); } // is a relocatable object file else if (m_ObjectReader.isMyFormat(**input)) { (*input)->setType(Input::Object); m_ObjectReader.readHeader(**input); m_ObjectReader.readSections(**input); m_ObjectReader.readSymbols(**input); m_Module.getObjectList().push_back(*input); ++cur_obj_cnt; ++non_ar_obj_cnt; } // is a shared object file else if (m_DynObjReader.isMyFormat(**input)) { (*input)->setType(Input::DynObj); m_DynObjReader.readHeader(**input); m_DynObjReader.readSymbols(**input); m_Module.getLibraryList().push_back(*input); } else { fatal(diag::err_unrecognized_input_file) << (*input)->path() << pConfig.targets().triple().str(); } ++input; } // after read in all the archives, traverse the archive list in a loop until // there is no unresolved symbols added ArchiveListType::iterator it = ar_list.begin(); ArchiveListType::iterator end = ar_list.end(); while (cur_obj_cnt != last_obj_cnt) { last_obj_cnt = cur_obj_cnt; cur_obj_cnt = non_ar_obj_cnt; for (it = ar_list.begin(); it != end; ++it) { Archive& ar = (*it)->archive; // if --whole-archive is given to this archive, no need to read it again if ( ar.getARFile().attribute()->isWholeArchive()) continue; m_ArchiveReader.readArchive(ar); cur_obj_cnt += ar.numOfObjectMember(); } } // after all needed member included, merge the archive sub-tree to main // InputTree for (it = ar_list.begin(); it != end; ++it) { Archive& ar = (*it)->archive; if (ar.numOfObjectMember() > 0) { m_Module.getInputTree().merge<InputTree::Inclusive>((*it)->input, ar.inputs()); } } // cleanup ar_list for (it = ar_list.begin(); it != end; ++it) { delete &((*it)->archive); delete (*it); } ar_list.clear(); return true; }