2012-11-14 02:39:10 +08:00
|
|
|
//===- lib/ReaderWriter/ReaderArchive.cpp - Archive Library Reader--------===//
|
|
|
|
//
|
|
|
|
// The LLVM Linker
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===---------------------------------------------------------------------===//
|
2012-11-14 03:58:58 +08:00
|
|
|
|
2012-11-14 02:39:10 +08:00
|
|
|
#include "lld/ReaderWriter/ReaderArchive.h"
|
|
|
|
|
2013-01-23 09:18:43 +08:00
|
|
|
#include "lld/Core/ArchiveLibraryFile.h"
|
|
|
|
#include "lld/Core/LinkerOptions.h"
|
|
|
|
|
2013-01-10 09:27:45 +08:00
|
|
|
#include "llvm/ADT/Hashing.h"
|
2013-01-23 09:18:43 +08:00
|
|
|
#include "llvm/Object/ObjectFile.h"
|
2013-01-10 09:27:45 +08:00
|
|
|
|
|
|
|
#include <unordered_map>
|
|
|
|
|
|
|
|
namespace std {
|
|
|
|
template<>
|
|
|
|
struct hash<llvm::StringRef> {
|
|
|
|
public:
|
|
|
|
size_t operator()(const llvm::StringRef &s) const {
|
|
|
|
using llvm::hash_value;
|
|
|
|
return hash_value(s);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2012-11-14 03:58:58 +08:00
|
|
|
namespace lld {
|
|
|
|
/// \brief The FileArchive class represents an Archive Library file
|
2012-11-14 02:39:10 +08:00
|
|
|
class FileArchive : public ArchiveLibraryFile {
|
|
|
|
public:
|
|
|
|
|
|
|
|
virtual ~FileArchive() { }
|
|
|
|
|
2012-11-14 03:58:58 +08:00
|
|
|
/// \brief Check if any member of the archive contains an Atom with the
|
2012-11-14 02:39:10 +08:00
|
|
|
/// specified name and return the File object for that member, or nullptr.
|
|
|
|
virtual const File *find(StringRef name, bool dataSymbolOnly) const {
|
2013-01-10 09:27:45 +08:00
|
|
|
auto member = _symbolMemberMap.find(name);
|
|
|
|
if (member == _symbolMemberMap.end())
|
2012-11-14 02:39:10 +08:00
|
|
|
return nullptr;
|
2013-01-10 09:27:45 +08:00
|
|
|
|
|
|
|
error_code ec;
|
|
|
|
llvm::object::Archive::child_iterator ci = member->second;
|
2012-11-14 02:39:10 +08:00
|
|
|
|
|
|
|
if (dataSymbolOnly && (ec = isDataSymbol(ci->getBuffer(), name)))
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
std::vector<std::unique_ptr<File>> result;
|
|
|
|
|
2013-01-23 09:18:43 +08:00
|
|
|
LinkerInput li(std::unique_ptr<MemoryBuffer>(ci->getBuffer()));
|
|
|
|
if ((ec = _getReader(li)->parseFile(li.takeBuffer(), result)))
|
2012-11-14 02:39:10 +08:00
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
assert(result.size() == 1);
|
|
|
|
|
2013-01-24 06:32:56 +08:00
|
|
|
// TO DO: set ordinal of child just loaded
|
|
|
|
|
2012-11-14 02:39:10 +08:00
|
|
|
// give up the pointer so that this object no longer manages it
|
2012-11-14 04:34:55 +08:00
|
|
|
return result[0].release();
|
2012-11-14 02:39:10 +08:00
|
|
|
}
|
|
|
|
|
2013-01-24 06:32:56 +08:00
|
|
|
virtual void setOrdinalAndIncrement(uint64_t &ordinal) const {
|
|
|
|
_ordinal = ordinal++;
|
|
|
|
// Leave space in ordinal range for all children
|
|
|
|
for (auto mf = _archive->begin_children(),
|
|
|
|
me = _archive->end_children(); mf != me; ++mf) {
|
|
|
|
ordinal++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-14 02:39:10 +08:00
|
|
|
virtual const atom_collection<DefinedAtom> &defined() const {
|
|
|
|
return _definedAtoms;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual const atom_collection<UndefinedAtom> &undefined() const {
|
|
|
|
return _undefinedAtoms;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual const atom_collection<SharedLibraryAtom> &sharedLibrary() const {
|
|
|
|
return _sharedLibraryAtoms;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual const atom_collection<AbsoluteAtom> &absolute() const {
|
|
|
|
return _absoluteAtoms;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
2012-11-14 03:58:58 +08:00
|
|
|
error_code isDataSymbol(MemoryBuffer *mb, StringRef symbol) const {
|
2012-11-14 04:34:55 +08:00
|
|
|
std::unique_ptr<llvm::object::ObjectFile>
|
|
|
|
obj(llvm::object::ObjectFile::createObjectFile(mb));
|
2012-11-14 02:39:10 +08:00
|
|
|
error_code ec;
|
|
|
|
llvm::object::SymbolRef::Type symtype;
|
|
|
|
uint32_t symflags;
|
|
|
|
llvm::object::symbol_iterator ibegin = obj->begin_symbols();
|
|
|
|
llvm::object::symbol_iterator iend = obj->end_symbols();
|
|
|
|
StringRef symbolname;
|
|
|
|
|
|
|
|
for (llvm::object::symbol_iterator i = ibegin; i != iend; i.increment(ec)) {
|
|
|
|
if (ec) return ec;
|
|
|
|
|
|
|
|
// Get symbol name
|
|
|
|
if ((ec = (i->getName(symbolname)))) return ec;
|
|
|
|
|
|
|
|
if (symbolname != symbol)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Get symbol flags
|
|
|
|
if ((ec = (i->getFlags(symflags)))) return ec;
|
|
|
|
|
|
|
|
if (symflags <= llvm::object::SymbolRef::SF_Undefined)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Get Symbol Type
|
|
|
|
if ((ec = (i->getType(symtype)))) return ec;
|
|
|
|
|
|
|
|
if (symtype == llvm::object::SymbolRef::ST_Data) {
|
|
|
|
return error_code::success();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return llvm::object::object_error::parse_failed;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2013-01-23 09:18:43 +08:00
|
|
|
std::function<ErrorOr<Reader&> (const LinkerInput &)> _getReader;
|
2012-11-14 02:39:10 +08:00
|
|
|
std::unique_ptr<llvm::object::Archive> _archive;
|
|
|
|
atom_collection_vector<DefinedAtom> _definedAtoms;
|
|
|
|
atom_collection_vector<UndefinedAtom> _undefinedAtoms;
|
|
|
|
atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
|
|
|
|
atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
|
|
|
|
|
|
|
|
public:
|
|
|
|
/// only subclasses of ArchiveLibraryFile can be instantiated
|
2013-01-23 09:18:43 +08:00
|
|
|
FileArchive(const TargetInfo &ti,
|
|
|
|
std::function<ErrorOr<Reader&> (const LinkerInput &)> getReader,
|
|
|
|
std::unique_ptr<llvm::MemoryBuffer> mb,
|
|
|
|
error_code &ec)
|
|
|
|
: ArchiveLibraryFile(mb->getBufferIdentifier()), _getReader(getReader) {
|
2012-11-14 03:58:58 +08:00
|
|
|
std::unique_ptr<llvm::object::Archive> archive_obj(
|
2013-01-23 09:18:43 +08:00
|
|
|
new llvm::object::Archive(mb.release(), ec));
|
2012-11-14 03:58:58 +08:00
|
|
|
if (ec)
|
2012-11-14 02:39:10 +08:00
|
|
|
return;
|
2012-11-14 03:58:58 +08:00
|
|
|
_archive.swap(archive_obj);
|
2013-01-10 09:27:45 +08:00
|
|
|
|
|
|
|
// Cache symbols.
|
|
|
|
for (auto i = _archive->begin_symbols(), e = _archive->end_symbols();
|
|
|
|
i != e; ++i) {
|
|
|
|
StringRef name;
|
|
|
|
llvm::object::Archive::child_iterator member;
|
|
|
|
if ((ec = i->getName(name)))
|
|
|
|
return;
|
|
|
|
if ((ec = i->getMember(member)))
|
|
|
|
return;
|
|
|
|
_symbolMemberMap[name] = member;
|
|
|
|
}
|
2012-11-14 02:39:10 +08:00
|
|
|
}
|
2013-01-10 09:27:45 +08:00
|
|
|
|
|
|
|
std::unordered_map<StringRef, llvm::object::Archive::child_iterator> _symbolMemberMap;
|
2012-11-14 02:39:10 +08:00
|
|
|
}; // class FileArchive
|
|
|
|
|
|
|
|
// Returns a vector of Files that are contained in the archive file
|
|
|
|
// pointed to by the MemoryBuffer
|
|
|
|
error_code ReaderArchive::parseFile(std::unique_ptr<llvm::MemoryBuffer> mb,
|
2013-01-23 09:18:43 +08:00
|
|
|
std::vector<std::unique_ptr<File>> &result){
|
2012-11-14 02:39:10 +08:00
|
|
|
error_code ec;
|
|
|
|
|
2013-01-23 09:18:43 +08:00
|
|
|
if (_options._forceLoadArchives) {
|
2012-11-14 02:39:10 +08:00
|
|
|
_archive.reset(new llvm::object::Archive(mb.release(), ec));
|
|
|
|
if (ec)
|
|
|
|
return ec;
|
|
|
|
|
|
|
|
for (auto mf = _archive->begin_children(),
|
2012-11-14 03:58:58 +08:00
|
|
|
me = _archive->end_children(); mf != me; ++mf) {
|
2013-01-23 09:18:43 +08:00
|
|
|
LinkerInput li(std::unique_ptr<MemoryBuffer>(mf->getBuffer()));
|
|
|
|
if ((ec = _getReader(li)->parseFile(li.takeBuffer(), result)))
|
2012-11-14 02:39:10 +08:00
|
|
|
return ec;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
std::unique_ptr<File> f;
|
2013-01-23 09:18:43 +08:00
|
|
|
f.reset(new FileArchive(_targetInfo, _getReader, std::move(mb), ec));
|
2012-11-14 02:39:10 +08:00
|
|
|
if (ec)
|
|
|
|
return ec;
|
|
|
|
|
|
|
|
result.push_back(std::move(f));
|
|
|
|
}
|
|
|
|
return llvm::error_code::success();
|
|
|
|
}
|
2013-01-23 09:18:43 +08:00
|
|
|
} // end namespace lld
|