blob: 6dcde18a81c839760740ed1dc08f02003fe929cb [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
20namespace std {
21 template<>
22 struct hash<llvm::StringRef> {
23 public:
24 size_t operator()(const llvm::StringRef &s) const {
25 using llvm::hash_value;
26 return hash_value(s);
27 }
28 };
29}
30
Michael J. Spencera5d22812012-11-13 19:58:58 +000031namespace lld {
32/// \brief The FileArchive class represents an Archive Library file
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +000033class FileArchive : public ArchiveLibraryFile {
34public:
35
36 virtual ~FileArchive() { }
37
Michael J. Spencera5d22812012-11-13 19:58:58 +000038 /// \brief Check if any member of the archive contains an Atom with the
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +000039 /// specified name and return the File object for that member, or nullptr.
40 virtual const File *find(StringRef name, bool dataSymbolOnly) const {
Michael J. Spencerad5f00e2013-01-10 01:27:45 +000041 auto member = _symbolMemberMap.find(name);
42 if (member == _symbolMemberMap.end())
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +000043 return nullptr;
Michael J. Spencerad5f00e2013-01-10 01:27:45 +000044
45 error_code ec;
46 llvm::object::Archive::child_iterator ci = member->second;
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +000047
48 if (dataSymbolOnly && (ec = isDataSymbol(ci->getBuffer(), name)))
49 return nullptr;
50
51 std::vector<std::unique_ptr<File>> result;
52
Michael J. Spencer64afcb42013-01-23 01:18:43 +000053 LinkerInput li(std::unique_ptr<MemoryBuffer>(ci->getBuffer()));
54 if ((ec = _getReader(li)->parseFile(li.takeBuffer(), result)))
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +000055 return nullptr;
56
57 assert(result.size() == 1);
58
Nick Kledzik36293f62013-01-23 22:32:56 +000059 // TO DO: set ordinal of child just loaded
60
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +000061 // give up the pointer so that this object no longer manages it
Shankar Easwaran85bb0452012-11-13 20:34:55 +000062 return result[0].release();
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +000063 }
64
Nick Kledzik36293f62013-01-23 22:32:56 +000065 virtual void setOrdinalAndIncrement(uint64_t &ordinal) const {
66 _ordinal = ordinal++;
67 // Leave space in ordinal range for all children
68 for (auto mf = _archive->begin_children(),
69 me = _archive->end_children(); mf != me; ++mf) {
70 ordinal++;
71 }
72 }
73
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +000074 virtual const atom_collection<DefinedAtom> &defined() const {
75 return _definedAtoms;
76 }
77
78 virtual const atom_collection<UndefinedAtom> &undefined() const {
79 return _undefinedAtoms;
80 }
81
82 virtual const atom_collection<SharedLibraryAtom> &sharedLibrary() const {
83 return _sharedLibraryAtoms;
84 }
85
86 virtual const atom_collection<AbsoluteAtom> &absolute() const {
87 return _absoluteAtoms;
88 }
89
90protected:
Michael J. Spencera5d22812012-11-13 19:58:58 +000091 error_code isDataSymbol(MemoryBuffer *mb, StringRef symbol) const {
Shankar Easwaran85bb0452012-11-13 20:34:55 +000092 std::unique_ptr<llvm::object::ObjectFile>
93 obj(llvm::object::ObjectFile::createObjectFile(mb));
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +000094 error_code ec;
95 llvm::object::SymbolRef::Type symtype;
96 uint32_t symflags;
97 llvm::object::symbol_iterator ibegin = obj->begin_symbols();
98 llvm::object::symbol_iterator iend = obj->end_symbols();
99 StringRef symbolname;
100
101 for (llvm::object::symbol_iterator i = ibegin; i != iend; i.increment(ec)) {
102 if (ec) return ec;
103
104 // Get symbol name
105 if ((ec = (i->getName(symbolname)))) return ec;
106
107 if (symbolname != symbol)
108 continue;
109
110 // Get symbol flags
111 if ((ec = (i->getFlags(symflags)))) return ec;
112
113 if (symflags <= llvm::object::SymbolRef::SF_Undefined)
114 continue;
115
116 // Get Symbol Type
117 if ((ec = (i->getType(symtype)))) return ec;
118
119 if (symtype == llvm::object::SymbolRef::ST_Data) {
120 return error_code::success();
121 }
122 }
123 return llvm::object::object_error::parse_failed;
124 }
125
126private:
Michael J. Spencer64afcb42013-01-23 01:18:43 +0000127 std::function<ErrorOr<Reader&> (const LinkerInput &)> _getReader;
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000128 std::unique_ptr<llvm::object::Archive> _archive;
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000129 atom_collection_vector<DefinedAtom> _definedAtoms;
130 atom_collection_vector<UndefinedAtom> _undefinedAtoms;
131 atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
132 atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
133
134public:
135 /// only subclasses of ArchiveLibraryFile can be instantiated
Michael J. Spencer64afcb42013-01-23 01:18:43 +0000136 FileArchive(const TargetInfo &ti,
137 std::function<ErrorOr<Reader&> (const LinkerInput &)> getReader,
138 std::unique_ptr<llvm::MemoryBuffer> mb,
139 error_code &ec)
140 : ArchiveLibraryFile(mb->getBufferIdentifier()), _getReader(getReader) {
Michael J. Spencera5d22812012-11-13 19:58:58 +0000141 std::unique_ptr<llvm::object::Archive> archive_obj(
Michael J. Spencer64afcb42013-01-23 01:18:43 +0000142 new llvm::object::Archive(mb.release(), ec));
Michael J. Spencera5d22812012-11-13 19:58:58 +0000143 if (ec)
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000144 return;
Michael J. Spencera5d22812012-11-13 19:58:58 +0000145 _archive.swap(archive_obj);
Michael J. Spencerad5f00e2013-01-10 01:27:45 +0000146
147 // Cache symbols.
148 for (auto i = _archive->begin_symbols(), e = _archive->end_symbols();
149 i != e; ++i) {
150 StringRef name;
151 llvm::object::Archive::child_iterator member;
152 if ((ec = i->getName(name)))
153 return;
154 if ((ec = i->getMember(member)))
155 return;
156 _symbolMemberMap[name] = member;
157 }
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000158 }
Michael J. Spencerad5f00e2013-01-10 01:27:45 +0000159
160 std::unordered_map<StringRef, llvm::object::Archive::child_iterator> _symbolMemberMap;
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000161}; // class FileArchive
162
163// Returns a vector of Files that are contained in the archive file
164// pointed to by the MemoryBuffer
165error_code ReaderArchive::parseFile(std::unique_ptr<llvm::MemoryBuffer> mb,
Michael J. Spencer64afcb42013-01-23 01:18:43 +0000166 std::vector<std::unique_ptr<File>> &result){
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000167 error_code ec;
168
Michael J. Spencer64afcb42013-01-23 01:18:43 +0000169 if (_options._forceLoadArchives) {
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000170 _archive.reset(new llvm::object::Archive(mb.release(), ec));
171 if (ec)
172 return ec;
173
174 for (auto mf = _archive->begin_children(),
Michael J. Spencera5d22812012-11-13 19:58:58 +0000175 me = _archive->end_children(); mf != me; ++mf) {
Michael J. Spencer64afcb42013-01-23 01:18:43 +0000176 LinkerInput li(std::unique_ptr<MemoryBuffer>(mf->getBuffer()));
177 if ((ec = _getReader(li)->parseFile(li.takeBuffer(), result)))
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000178 return ec;
179 }
180 } else {
181 std::unique_ptr<File> f;
Michael J. Spencer64afcb42013-01-23 01:18:43 +0000182 f.reset(new FileArchive(_targetInfo, _getReader, std::move(mb), ec));
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000183 if (ec)
184 return ec;
185
186 result.push_back(std::move(f));
187 }
188 return llvm::error_code::success();
189}
Michael J. Spencer64afcb42013-01-23 01:18:43 +0000190} // end namespace lld