bool GNUArchiveReader::readArchive(const LinkerConfig& pConfig, Archive& pArchive) { // bypass the empty archive if (Archive::MAGIC_LEN == pArchive.getARFile().memArea()->handler()->size()) return true; if (pArchive.getARFile().attribute()->isWholeArchive()) return includeAllMembers(pConfig, pArchive); // if this is the first time read this archive, setup symtab and strtab if (pArchive.getSymbolTable().empty()) { // read the symtab of the archive readSymbolTable(pArchive); // read the strtab of the archive readStringTable(pArchive); // add root archive to ArchiveMemberMap pArchive.addArchiveMember(pArchive.getARFile().name(), pArchive.inputs().root(), &InputTree::Downward); } // include the needed members in the archive and build up the input tree bool willSymResolved; do { willSymResolved = false; for (size_t idx = 0; idx < pArchive.numOfSymbols(); ++idx) { // bypass if we already decided to include this symbol or not if (Archive::Symbol::Unknown != pArchive.getSymbolStatus(idx)) continue; // bypass if another symbol with the same object file offset is included if (pArchive.hasObjectMember(pArchive.getObjFileOffset(idx))) { pArchive.setSymbolStatus(idx, Archive::Symbol::Include); continue; } // check if we should include this defined symbol Archive::Symbol::Status status = shouldIncludeSymbol(pArchive.getSymbolName(idx)); if (Archive::Symbol::Unknown != status) pArchive.setSymbolStatus(idx, status); if (Archive::Symbol::Include == status) { // include the object member from the given offset includeMember(pConfig, pArchive, pArchive.getObjFileOffset(idx)); willSymResolved = true; } // end of if } // end of for } while (willSymResolved); return true; }
/// includeAllMembers - include all object members. This is called if /// --whole-archive is the attribute for this archive file. bool GNUArchiveReader::includeAllMembers(const LinkerConfig& pConfig, Archive& pArchive) { // read the symtab of the archive readSymbolTable(pArchive); // read the strtab of the archive readStringTable(pArchive); // add root archive to ArchiveMemberMap pArchive.addArchiveMember(pArchive.getARFile().name(), pArchive.inputs().root(), &InputTree::Downward); bool isThinAR = isThinArchive(pArchive.getARFile()); uint32_t begin_offset = pArchive.getARFile().fileOffset() + Archive::MAGIC_LEN + sizeof(Archive::MemberHeader) + pArchive.getSymTabSize(); if (pArchive.hasStrTable()) { if (0x0 != (begin_offset & 1)) ++begin_offset; begin_offset += sizeof(Archive::MemberHeader) + pArchive.getStrTable().size(); } uint32_t end_offset = pArchive.getARFile().memArea()->handler()->size(); for (uint32_t offset = begin_offset; offset < end_offset; offset += sizeof(Archive::MemberHeader)) { size_t size = includeMember(pConfig, pArchive, offset); if (!isThinAR) { offset += size; } if (0x0 != (offset & 1)) ++offset; } 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; }