1 //===- lib/ReaderWriter/FileArchive.cpp -----------------------------------===//
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "lld/Core/ArchiveLibraryFile.h"
11 #include "lld/Core/LLVM.h"
12 #include "lld/Core/LinkingContext.h"
13 #include "lld/Core/Parallel.h"
14 #include "llvm/ADT/Hashing.h"
15 #include "llvm/ADT/StringRef.h"
16 #include "llvm/Object/Archive.h"
17 #include "llvm/Object/ObjectFile.h"
18 #include "llvm/Support/Debug.h"
19 #include "llvm/Support/Format.h"
20 #include "llvm/Support/MemoryBuffer.h"
24 #include <unordered_map>
26 using llvm::object::Archive;
27 using llvm::object::ObjectFile;
28 using llvm::object::SymbolRef;
29 using llvm::object::symbol_iterator;
30 using llvm::object::object_error;
36 /// \brief The FileArchive class represents an Archive Library file
37 class FileArchive : public lld::ArchiveLibraryFile {
39 FileArchive(std::unique_ptr<MemoryBuffer> mb, const Registry ®,
40 StringRef path, bool logLoading)
41 : ArchiveLibraryFile(path), _mb(std::shared_ptr<MemoryBuffer>(mb.release())),
42 _registry(reg), _logLoading(logLoading) {}
44 /// \brief Check if any member of the archive contains an Atom with the
45 /// specified name and return the File object for that member, or nullptr.
46 File *find(StringRef name, bool dataSymbolOnly) override {
47 auto member = _symbolMemberMap.find(name);
48 if (member == _symbolMemberMap.end())
50 Archive::child_iterator ci = member->second;
52 // Don't return a member already returned
53 const char *memberStart = ci->getBuffer().data();
54 if (_membersInstantiated.count(memberStart))
56 if (dataSymbolOnly && !isDataSymbol(ci, name))
59 _membersInstantiated.insert(memberStart);
61 // Check if a file is preloaded.
63 std::lock_guard<std::mutex> lock(_mutex);
64 auto it = _preloaded.find(memberStart);
65 if (it != _preloaded.end()) {
66 std::unique_ptr<Future<File *>> &p = it->second;
67 Future<File *> *future = p.get();
72 std::unique_ptr<File> result;
73 if (instantiateMember(ci, result))
76 // give up the pointer so that this object no longer manages it
77 return result.release();
80 // Instantiate a member file containing a given symbol name.
81 void preload(TaskGroup &group, StringRef name) override {
82 auto member = _symbolMemberMap.find(name);
83 if (member == _symbolMemberMap.end())
85 Archive::child_iterator ci = member->second;
87 // Do nothing if a member is already instantiated.
88 const char *memberStart = ci->getBuffer().data();
89 if (_membersInstantiated.count(memberStart))
92 std::lock_guard<std::mutex> lock(_mutex);
93 if (_preloaded.find(memberStart) != _preloaded.end())
96 // Instantiate the member
97 auto *future = new Future<File *>();
98 _preloaded[memberStart] = std::unique_ptr<Future<File *>>(future);
101 std::unique_ptr<File> result;
102 std::error_code ec = instantiateMember(ci, result);
103 future->set(ec ? nullptr : result.release());
107 /// \brief parse each member
109 parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
110 if (std::error_code ec = parse())
112 for (auto mf = _archive->child_begin(), me = _archive->child_end();
114 std::unique_ptr<File> file;
115 if (std::error_code ec = instantiateMember(mf, file))
117 result.push_back(std::move(file));
119 return std::error_code();
122 const atom_collection<DefinedAtom> &defined() const override {
123 return _definedAtoms;
126 const atom_collection<UndefinedAtom> &undefined() const override {
127 return _undefinedAtoms;
130 const atom_collection<SharedLibraryAtom> &sharedLibrary() const override {
131 return _sharedLibraryAtoms;
134 const atom_collection<AbsoluteAtom> &absolute() const override {
135 return _absoluteAtoms;
138 /// Returns a set of all defined symbols in the archive.
139 std::set<StringRef> getDefinedSymbols() override {
141 std::set<StringRef> ret;
142 for (const auto &e : _symbolMemberMap)
148 std::error_code doParse() override {
149 // Make Archive object which will be owned by FileArchive object.
151 _archive.reset(new Archive(_mb->getMemBufferRef(), ec));
154 if ((ec = buildTableOfContents()))
156 return std::error_code();
161 instantiateMember(Archive::child_iterator member,
162 std::unique_ptr<File> &result) const {
163 ErrorOr<llvm::MemoryBufferRef> mbOrErr = member->getMemoryBufferRef();
164 if (std::error_code ec = mbOrErr.getError())
166 llvm::MemoryBufferRef mb = mbOrErr.get();
167 std::string memberPath = (_archive->getFileName() + "("
168 + mb.getBufferIdentifier() + ")").str();
171 llvm::errs() << memberPath << "\n";
173 std::unique_ptr<MemoryBuffer> memberMB(MemoryBuffer::getMemBuffer(
174 mb.getBuffer(), mb.getBufferIdentifier(), false));
176 std::vector<std::unique_ptr<File>> files;
177 if (std::error_code ec = _registry.loadFile(std::move(memberMB), files))
179 assert(files.size() == 1);
180 result = std::move(files[0]);
181 if (std::error_code ec = result->parse())
183 result->setArchivePath(_archive->getFileName());
185 // The memory buffer is co-owned by the archive file and the children,
186 // so that the bufffer is deallocated when all the members are destructed.
187 result->setSharedMemoryBuffer(_mb);
188 return std::error_code();
191 // Parses the given memory buffer as an object file, and returns true
192 // code if the given symbol is a data symbol. If the symbol is not a data
193 // symbol or does not exist, returns false.
194 bool isDataSymbol(Archive::child_iterator member, StringRef symbol) const {
195 ErrorOr<llvm::MemoryBufferRef> buf = member->getMemoryBufferRef();
198 std::unique_ptr<MemoryBuffer> mb(MemoryBuffer::getMemBuffer(
199 buf.get().getBuffer(), buf.get().getBufferIdentifier(), false));
201 auto objOrErr(ObjectFile::createObjectFile(mb->getMemBufferRef()));
202 if (objOrErr.getError())
204 std::unique_ptr<ObjectFile> obj = std::move(objOrErr.get());
206 for (SymbolRef sym : obj->symbols()) {
207 // Skip until we find the symbol.
209 if (sym.getName(name))
213 uint32_t flags = sym.getFlags();
214 if (flags <= SymbolRef::SF_Undefined)
217 // Returns true if it's a data symbol.
218 SymbolRef::Type type;
219 if (sym.getType(type))
221 if (type == SymbolRef::ST_Data)
227 std::error_code buildTableOfContents() {
228 DEBUG_WITH_TYPE("FileArchive", llvm::dbgs()
229 << "Table of contents for archive '"
230 << _archive->getFileName() << "':\n");
231 for (const Archive::Symbol &sym : _archive->symbols()) {
232 StringRef name = sym.getName();
233 ErrorOr<Archive::child_iterator> memberOrErr = sym.getMember();
234 if (std::error_code ec = memberOrErr.getError())
236 Archive::child_iterator member = memberOrErr.get();
239 llvm::dbgs() << llvm::format("0x%08llX ", member->getBuffer().data())
240 << "'" << name << "'\n");
241 _symbolMemberMap[name] = member;
243 return std::error_code();
246 typedef std::unordered_map<StringRef, Archive::child_iterator> MemberMap;
247 typedef std::set<const char *> InstantiatedSet;
249 std::shared_ptr<MemoryBuffer> _mb;
250 const Registry &_registry;
251 std::unique_ptr<Archive> _archive;
252 MemberMap _symbolMemberMap;
253 InstantiatedSet _membersInstantiated;
254 atom_collection_vector<DefinedAtom> _definedAtoms;
255 atom_collection_vector<UndefinedAtom> _undefinedAtoms;
256 atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
257 atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
259 std::vector<std::unique_ptr<MemoryBuffer>> _memberBuffers;
260 std::map<const char *, std::unique_ptr<Future<File *>>> _preloaded;
264 class ArchiveReader : public Reader {
266 ArchiveReader(bool logLoading) : _logLoading(logLoading) {}
268 bool canParse(file_magic magic, StringRef,
269 const MemoryBuffer &) const override {
270 return (magic == llvm::sys::fs::file_magic::archive);
274 loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry ®,
275 std::vector<std::unique_ptr<File>> &result) const override {
276 StringRef path = mb->getBufferIdentifier();
277 std::unique_ptr<FileArchive> file(
278 new FileArchive(std::move(mb), reg, path, _logLoading));
279 result.push_back(std::move(file));
280 return std::error_code();
287 } // anonymous namespace
289 void Registry::addSupportArchives(bool logLoading) {
290 add(std::unique_ptr<Reader>(new ArchiveReader(logLoading)));
293 } // end namespace lld