blob: c31b955a6b7690c9e33703e641ef0eb2e7308ad0 [file] [log] [blame]
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +00001//===- lib/ReaderWriter/ReaderArchive.cpp - Archive Library Reader--------===//
2//
3// The LLVM Linker
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===---------------------------------------------------------------------===//
Michael J. Spencera5d22812012-11-13 19:58:58 +00009
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +000010#include "lld/ReaderWriter/ReaderArchive.h"
11
Michael J. Spencer64afcb42013-01-23 01:18:43 +000012#include "lld/Core/ArchiveLibraryFile.h"
13#include "lld/Core/LinkerOptions.h"
14
Michael J. Spencerad5f00e2013-01-10 01:27:45 +000015#include "llvm/ADT/Hashing.h"
Michael J. Spencer64afcb42013-01-23 01:18:43 +000016#include "llvm/Object/ObjectFile.h"
Michael J. Spencerad5f00e2013-01-10 01:27:45 +000017
18#include <unordered_map>
19
Michael J. Spencera5d22812012-11-13 19:58:58 +000020namespace lld {
21/// \brief The FileArchive class represents an Archive Library file
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +000022class FileArchive : public ArchiveLibraryFile {
23public:
24
25 virtual ~FileArchive() { }
26
Michael J. Spencera5d22812012-11-13 19:58:58 +000027 /// \brief Check if any member of the archive contains an Atom with the
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +000028 /// specified name and return the File object for that member, or nullptr.
29 virtual const File *find(StringRef name, bool dataSymbolOnly) const {
Michael J. Spencerad5f00e2013-01-10 01:27:45 +000030 auto member = _symbolMemberMap.find(name);
31 if (member == _symbolMemberMap.end())
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +000032 return nullptr;
Michael J. Spencerad5f00e2013-01-10 01:27:45 +000033
Michael J. Spencerad5f00e2013-01-10 01:27:45 +000034 llvm::object::Archive::child_iterator ci = member->second;
Shankar Easwaran8962feb2013-03-14 16:09:49 +000035
Michael J. Spencer4673da22013-02-03 10:49:26 +000036 if (dataSymbolOnly) {
37 OwningPtr<MemoryBuffer> buff;
38 if (ci->getMemoryBuffer(buff, true))
39 return nullptr;
40 if (isDataSymbol(buff.take(), name))
41 return nullptr;
42 }
Shankar Easwaran8962feb2013-03-14 16:09:49 +000043
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +000044 std::vector<std::unique_ptr<File>> result;
45
Michael J. Spencer4673da22013-02-03 10:49:26 +000046 OwningPtr<MemoryBuffer> buff;
47 if (ci->getMemoryBuffer(buff, true))
48 return nullptr;
49 LinkerInput li(std::unique_ptr<MemoryBuffer>(buff.take()));
50 if (_getReader(li)->parseFile(li.takeBuffer(), result))
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +000051 return nullptr;
52
53 assert(result.size() == 1);
54
Nick Kledzik36293f62013-01-23 22:32:56 +000055 // TO DO: set ordinal of child just loaded
Shankar Easwaran8962feb2013-03-14 16:09:49 +000056
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +000057 // give up the pointer so that this object no longer manages it
Shankar Easwaran85bb0452012-11-13 20:34:55 +000058 return result[0].release();
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +000059 }
60
Nick Kledzik36293f62013-01-23 22:32:56 +000061 virtual void setOrdinalAndIncrement(uint64_t &ordinal) const {
62 _ordinal = ordinal++;
63 // Leave space in ordinal range for all children
Shankar Easwaran8962feb2013-03-14 16:09:49 +000064 for (auto mf = _archive->begin_children(),
Nick Kledzik36293f62013-01-23 22:32:56 +000065 me = _archive->end_children(); mf != me; ++mf) {
66 ordinal++;
67 }
68 }
69
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +000070 virtual const atom_collection<DefinedAtom> &defined() const {
71 return _definedAtoms;
72 }
73
74 virtual const atom_collection<UndefinedAtom> &undefined() const {
75 return _undefinedAtoms;
76 }
77
78 virtual const atom_collection<SharedLibraryAtom> &sharedLibrary() const {
79 return _sharedLibraryAtoms;
80 }
81
82 virtual const atom_collection<AbsoluteAtom> &absolute() const {
83 return _absoluteAtoms;
84 }
85
86protected:
Michael J. Spencera5d22812012-11-13 19:58:58 +000087 error_code isDataSymbol(MemoryBuffer *mb, StringRef symbol) const {
Shankar Easwaran8962feb2013-03-14 16:09:49 +000088 std::unique_ptr<llvm::object::ObjectFile>
Shankar Easwaran85bb0452012-11-13 20:34:55 +000089 obj(llvm::object::ObjectFile::createObjectFile(mb));
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +000090 error_code ec;
91 llvm::object::SymbolRef::Type symtype;
92 uint32_t symflags;
93 llvm::object::symbol_iterator ibegin = obj->begin_symbols();
94 llvm::object::symbol_iterator iend = obj->end_symbols();
95 StringRef symbolname;
96
97 for (llvm::object::symbol_iterator i = ibegin; i != iend; i.increment(ec)) {
98 if (ec) return ec;
Shankar Easwaran8962feb2013-03-14 16:09:49 +000099
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000100 // Get symbol name
101 if ((ec = (i->getName(symbolname)))) return ec;
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000102
103 if (symbolname != symbol)
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000104 continue;
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000105
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000106 // Get symbol flags
107 if ((ec = (i->getFlags(symflags)))) return ec;
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000108
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000109 if (symflags <= llvm::object::SymbolRef::SF_Undefined)
110 continue;
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000111
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000112 // Get Symbol Type
113 if ((ec = (i->getType(symtype)))) return ec;
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000114
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000115 if (symtype == llvm::object::SymbolRef::ST_Data) {
116 return error_code::success();
117 }
118 }
119 return llvm::object::object_error::parse_failed;
120 }
121
122private:
Michael J. Spencer64afcb42013-01-23 01:18:43 +0000123 std::function<ErrorOr<Reader&> (const LinkerInput &)> _getReader;
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000124 std::unique_ptr<llvm::object::Archive> _archive;
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000125 atom_collection_vector<DefinedAtom> _definedAtoms;
126 atom_collection_vector<UndefinedAtom> _undefinedAtoms;
127 atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
128 atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
129
130public:
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000131 /// only subclasses of ArchiveLibraryFile can be instantiated
Michael J. Spencer64afcb42013-01-23 01:18:43 +0000132 FileArchive(const TargetInfo &ti,
Shankar Easwaran3256d4f2013-01-25 07:39:18 +0000133 std::function<ErrorOr<Reader &>(const LinkerInput &)> getReader,
134 std::unique_ptr<llvm::MemoryBuffer> mb, error_code &ec)
135 : ArchiveLibraryFile(ti, mb->getBufferIdentifier()),
136 _getReader(getReader) {
Michael J. Spencera5d22812012-11-13 19:58:58 +0000137 std::unique_ptr<llvm::object::Archive> archive_obj(
Michael J. Spencer64afcb42013-01-23 01:18:43 +0000138 new llvm::object::Archive(mb.release(), ec));
Michael J. Spencera5d22812012-11-13 19:58:58 +0000139 if (ec)
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000140 return;
Michael J. Spencera5d22812012-11-13 19:58:58 +0000141 _archive.swap(archive_obj);
Michael J. Spencerad5f00e2013-01-10 01:27:45 +0000142
143 // Cache symbols.
144 for (auto i = _archive->begin_symbols(), e = _archive->end_symbols();
145 i != e; ++i) {
146 StringRef name;
147 llvm::object::Archive::child_iterator member;
148 if ((ec = i->getName(name)))
149 return;
150 if ((ec = i->getMember(member)))
151 return;
152 _symbolMemberMap[name] = member;
153 }
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000154 }
Michael J. Spencerad5f00e2013-01-10 01:27:45 +0000155
156 std::unordered_map<StringRef, llvm::object::Archive::child_iterator> _symbolMemberMap;
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000157}; // class FileArchive
158
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000159// Returns a vector of Files that are contained in the archive file
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000160// pointed to by the MemoryBuffer
161error_code ReaderArchive::parseFile(std::unique_ptr<llvm::MemoryBuffer> mb,
Michael J. Spencer64afcb42013-01-23 01:18:43 +0000162 std::vector<std::unique_ptr<File>> &result){
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000163 error_code ec;
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000164
Michael J. Spencer64afcb42013-01-23 01:18:43 +0000165 if (_options._forceLoadArchives) {
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000166 _archive.reset(new llvm::object::Archive(mb.release(), ec));
167 if (ec)
168 return ec;
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000169
170 for (auto mf = _archive->begin_children(),
Michael J. Spencera5d22812012-11-13 19:58:58 +0000171 me = _archive->end_children(); mf != me; ++mf) {
Michael J. Spencer4673da22013-02-03 10:49:26 +0000172 OwningPtr<MemoryBuffer> buff;
173 if ((ec = mf->getMemoryBuffer(buff, true)))
174 return ec;
175 LinkerInput li(std::unique_ptr<MemoryBuffer>(buff.take()));
Michael J. Spencer64afcb42013-01-23 01:18:43 +0000176 if ((ec = _getReader(li)->parseFile(li.takeBuffer(), result)))
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000177 return ec;
178 }
179 } else {
180 std::unique_ptr<File> f;
Michael J. Spencer64afcb42013-01-23 01:18:43 +0000181 f.reset(new FileArchive(_targetInfo, _getReader, std::move(mb), ec));
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000182 if (ec)
183 return ec;
184
185 result.push_back(std::move(f));
186 }
187 return llvm::error_code::success();
188}
Michael J. Spencer64afcb42013-01-23 01:18:43 +0000189} // end namespace lld