Separate file parsing from File's constructors.

This is a second patch for InputGraph cleanup.

Sorry about the size of the patch, but what I did in this
patch is basically moving code from constructor to a new
method, parse(), so the amount of new code is small.
This has no change in functionality.

We've discussed the issue that we have too many classes
to represent a concept of "file". We have File subclasses
that represent files read from disk. In addition to that,
we have bunch of InputElement subclasses (that are part
of InputGraph) that represent command line arguments for
input file names. InputElement is a wrapper for File.

InputElement has parseFile method. The method instantiates
a File. The File's constructor reads a file from disk and
parses that.

Because parseFile method is called from multiple worker
threads, file parsing is processed in parallel. In other
words, one reason why we needed the wrapper classes is
because a File would start reading a file as soon as it
is instantiated.

So, the reason why we have too many classes here is at
least partly because of the design flaw of File class.
Just like threads in a good threading library, we need
to separate instantiation from "start" method, so that
we can instantiate File objects when we need them (which
should be very fast because it involves only one mmap()
and no real file IO) and use them directly instead of
the wrapper classes. Later, we call parse() on each
file in parallel to let them do actual file IO.

In this design, we can eliminate a reason to have the
wrapper classes.

In order to minimize the size of the patch, I didn't go so
far as to replace the wrapper classes with File classes.
The wrapper classes are still there.

In this patch, we call parse() immediately after
instantiating a File, so this really has no change in
functionality. Eventually the call of parse() should be
moved to Driver::link(). That'll be done in another patch.

llvm-svn: 224102
This commit is contained in:
Rui Ueyama 2014-12-12 07:31:09 +00:00
parent adb3864744
commit 1d510428e8
20 changed files with 442 additions and 368 deletions

View File

@ -16,6 +16,7 @@
#include "lld/Core/SharedLibraryAtom.h"
#include "lld/Core/UndefinedAtom.h"
#include "lld/Core/range.h"
#include "llvm/ADT/Optional.h"
#include "llvm/Support/ErrorHandling.h"
#include <functional>
#include <vector>
@ -153,9 +154,26 @@ public:
/// all AbsoluteAtoms in this File.
virtual const atom_collection<AbsoluteAtom> &absolute() const = 0;
/// \brief Subclasses should override this method to parse the
/// memory buffer passed to this file's constructor.
virtual std::error_code doParse() { return std::error_code(); }
/// \brief If a file is parsed using a different method than doParse(),
/// one must use this method to set the last error status, so that
/// doParse will not be called twice. Only YAML reader uses this
/// (because YAML reader does not read blobs but structured data).
void setLastError(std::error_code err) { _lastError = err; }
std::error_code parse() {
if (!_lastError.hasValue())
_lastError = doParse();
return _lastError.getValue();
}
protected:
/// \brief only subclasses of File can be instantiated
File(StringRef p, Kind kind) : _path(p), _kind(kind), _ordinal(UINT64_MAX) {}
File(StringRef p, Kind kind)
: _path(p), _kind(kind), _ordinal(UINT64_MAX) {}
/// \brief This is a convenience class for File subclasses which manage their
/// atoms as a simple std::vector<>.
@ -211,6 +229,7 @@ protected:
static atom_collection_empty<UndefinedAtom> _noUndefinedAtoms;
static atom_collection_empty<SharedLibraryAtom> _noSharedLibraryAtoms;
static atom_collection_empty<AbsoluteAtom> _noAbsoluteAtoms;
llvm::Optional<std::error_code> _lastError;
mutable llvm::BumpPtrAllocator _allocator;
private:

View File

@ -26,6 +26,7 @@ namespace lld {
namespace mach_o {
class ArchHandler;
class MachODylibFile;
class MachOFile;
}
class MachOLinkingContext : public LinkingContext {

View File

@ -24,11 +24,8 @@ public:
static ErrorOr<std::unique_ptr<AArch64ELFFile>>
create(std::unique_ptr<MemoryBuffer> mb, bool atomizeStrings) {
std::unique_ptr<AArch64ELFFile<ELFT>> file(
return std::unique_ptr<AArch64ELFFile<ELFT>>(
new AArch64ELFFile<ELFT>(std::move(mb), atomizeStrings));
if (std::error_code ec = file->parse())
return ec;
return std::move(file);
}
};

View File

@ -55,8 +55,51 @@ public:
*this, name, _soname, sym->second._symbol);
}
std::error_code doParse() override {
std::error_code ec;
_objFile.reset(
new llvm::object::ELFFile<ELFT>(_mb.release()->getBuffer(), ec));
if (ec)
return ec;
llvm::object::ELFFile<ELFT> &obj = *_objFile;
_soname = obj.getLoadName();
if (_soname.empty())
_soname = llvm::sys::path::filename(path());
// Create a map from names to dynamic symbol table entries.
// TODO: This should use the object file's build in hash table instead if
// it exists.
for (auto i = obj.begin_dynamic_symbols(), e = obj.end_dynamic_symbols();
i != e; ++i) {
auto name = obj.getSymbolName(i);
if ((ec = name.getError()))
return ec;
// TODO: Add absolute symbols
if (i->st_shndx == llvm::ELF::SHN_ABS)
continue;
if (i->st_shndx == llvm::ELF::SHN_UNDEF) {
if (!_useShlibUndefines)
continue;
// Create an undefined atom.
if (!name->empty()) {
auto *newAtom = new (_alloc) ELFUndefinedAtom<ELFT>(*this, *name, &*i);
_undefinedAtoms._atoms.push_back(newAtom);
}
continue;
}
_nameToSym[*name]._symbol = &*i;
}
return std::error_code();
}
private:
DynamicFile(StringRef name) : SharedLibraryFile(name) {}
DynamicFile(std::unique_ptr<MemoryBuffer> mb, bool useShlibUndefines)
: SharedLibraryFile(mb->getBufferIdentifier()),
_mb(std::move(mb)), _useShlibUndefines(useShlibUndefines) {}
mutable llvm::BumpPtrAllocator _alloc;
std::unique_ptr<llvm::object::ELFFile<ELFT>> _objFile;
@ -73,6 +116,8 @@ private:
const SharedLibraryAtom *_atom;
};
std::unique_ptr<MemoryBuffer> _mb;
bool _useShlibUndefines;
mutable std::unordered_map<StringRef, SymAtomPair> _nameToSym;
};
@ -80,49 +125,8 @@ template <class ELFT>
ErrorOr<std::unique_ptr<DynamicFile<ELFT>>>
DynamicFile<ELFT>::create(std::unique_ptr<llvm::MemoryBuffer> mb,
bool useShlibUndefines) {
std::unique_ptr<DynamicFile> file(new DynamicFile(mb->getBufferIdentifier()));
std::error_code ec;
file->_objFile.reset(
new llvm::object::ELFFile<ELFT>(mb.release()->getBuffer(), ec));
if (ec)
return ec;
llvm::object::ELFFile<ELFT> &obj = *file->_objFile;
file->_soname = obj.getLoadName();
if (file->_soname.empty())
file->_soname = llvm::sys::path::filename(file->path());
// Create a map from names to dynamic symbol table entries.
// TODO: This should use the object file's build in hash table instead if
// it exists.
for (auto i = obj.begin_dynamic_symbols(), e = obj.end_dynamic_symbols();
i != e; ++i) {
auto name = obj.getSymbolName(i);
if ((ec = name.getError()))
return ec;
// TODO: Add absolute symbols
if (i->st_shndx == llvm::ELF::SHN_ABS)
continue;
if (i->st_shndx == llvm::ELF::SHN_UNDEF) {
if (!useShlibUndefines)
continue;
// Create an undefined atom.
if (!name->empty()) {
auto *newAtom =
new (file->_alloc) ELFUndefinedAtom<ELFT>(*file.get(), *name, &*i);
file->_undefinedAtoms._atoms.push_back(newAtom);
}
continue;
}
file->_nameToSym[*name]._symbol = &*i;
}
return std::move(file);
return std::unique_ptr<DynamicFile>(
new DynamicFile(std::move(mb), useShlibUndefines));
}
} // end namespace elf

View File

@ -122,7 +122,7 @@ public:
: File(mb->getBufferIdentifier(), kindObject), _mb(std::move(mb)),
_ordinal(0), _doStringsMerge(atomizeStrings) {}
virtual std::error_code parse();
virtual std::error_code doParse() override;
static ErrorOr<std::unique_ptr<ELFFile>>
create(std::unique_ptr<MemoryBuffer> mb, bool atomizeStrings);
@ -417,19 +417,15 @@ public:
template <class ELFT>
ErrorOr<std::unique_ptr<ELFFile<ELFT>>>
ELFFile<ELFT>::create(std::unique_ptr<MemoryBuffer> mb, bool atomizeStrings) {
std::error_code ec;
std::unique_ptr<ELFFile<ELFT>> file(
new ELFFile<ELFT>(std::move(mb), atomizeStrings));
if (std::error_code ec = file->parse())
return ec;
return std::move(file);
}
template <class ELFT>
std::error_code ELFFile<ELFT>::parse() {
std::error_code ELFFile<ELFT>::doParse() {
std::error_code ec;
_objFile.reset(
new llvm::object::ELFFile<ELFT>(_mb.release()->getBuffer(), ec));
_objFile.reset(new llvm::object::ELFFile<ELFT>(_mb.release()->getBuffer(), ec));
if (ec)
return ec;

View File

@ -119,11 +119,8 @@ public:
static ErrorOr<std::unique_ptr<HexagonELFFile>>
create(std::unique_ptr<MemoryBuffer> mb, bool atomizeStrings) {
std::unique_ptr<HexagonELFFile<ELFT>> file(
return std::unique_ptr<HexagonELFFile<ELFT>>(
new HexagonELFFile<ELFT>(std::move(mb), atomizeStrings));
if (std::error_code ec = file->parse())
return ec;
return std::move(file);
}
virtual bool isCommonSymbol(const Elf_Sym *symbol) const {

View File

@ -85,11 +85,8 @@ public:
static ErrorOr<std::unique_ptr<MipsELFFile>>
create(std::unique_ptr<MemoryBuffer> mb, bool atomizeStrings) {
std::unique_ptr<MipsELFFile<ELFT>> file(
return std::unique_ptr<MipsELFFile<ELFT>>(
new MipsELFFile<ELFT>(std::move(mb), atomizeStrings));
if (std::error_code ec = file->parse())
return ec;
return std::move(file);
}
bool isPIC() const {
@ -103,8 +100,8 @@ public:
uint64_t getTPOffset() const { return *_tpOff; }
uint64_t getDTPOffset() const { return *_dtpOff; }
std::error_code parse() override {
if (std::error_code ec = ELFFile<ELFT>::parse())
std::error_code doParse() override {
if (std::error_code ec = ELFFile<ELFT>::doParse())
return ec;
// Retrieve some auxiliary data like GP value, TLS section address etc
// from the object file.

View File

@ -19,11 +19,14 @@ class PPCLinkingContext;
template <class ELFT> class PPCELFFile : public ELFFile<ELFT> {
public:
PPCELFFile(StringRef name) : ELFFile<ELFT>(name) {}
PPCELFFile(std::unique_ptr<MemoryBuffer> mb, bool atomizeStrings)
: ELFFile<ELFT>(std::move(mb), atomizeStrings) {}
PPCELFFile(std::unique_ptr<MemoryBuffer> mb, bool atomizeStrings,
TargetHandlerBase *handler, std::error_code &ec)
: ELFFile<ELFT>(std::move(mb), atomizeStrings, handler, ec) {}
static ErrorOr<std::unique_ptr<PPCELFFile>>
create(std::unique_ptr<MemoryBuffer> mb, bool atomizeStrings) {
return std::unique_ptr<PPCELFFile<ELFT>>(
new PPCELFFile<ELFT>(std::move(mb), atomizeStrings));
}
};
template <class ELFT> class PPCDynamicFile : public DynamicFile<ELFT> {

View File

@ -24,11 +24,8 @@ public:
static ErrorOr<std::unique_ptr<X86ELFFile>>
create(std::unique_ptr<MemoryBuffer> mb, bool atomizeStrings) {
std::unique_ptr<X86ELFFile<ELFT>> file(
return std::unique_ptr<X86ELFFile<ELFT>>(
new X86ELFFile<ELFT>(std::move(mb), atomizeStrings));
if (std::error_code ec = file->parse())
return ec;
return std::move(file);
}
};

View File

@ -24,11 +24,8 @@ public:
static ErrorOr<std::unique_ptr<X86_64ELFFile>>
create(std::unique_ptr<MemoryBuffer> mb, bool atomizeStrings) {
std::unique_ptr<X86_64ELFFile<ELFT>> file(
return std::unique_ptr<X86_64ELFFile<ELFT>>(
new X86_64ELFFile<ELFT>(std::move(mb), atomizeStrings));
if (std::error_code ec = file->parse())
return ec;
return std::move(file);
}
};

View File

@ -33,12 +33,22 @@ namespace {
/// \brief The FileArchive class represents an Archive Library file
class FileArchive : public lld::ArchiveLibraryFile {
public:
FileArchive(const Registry &registry, Archive *archive, StringRef path,
bool isWholeArchive, bool logLoading)
: ArchiveLibraryFile(path), _registry(registry),
_archive(std::move(archive)), _isWholeArchive(isWholeArchive),
FileArchive(std::unique_ptr<MemoryBuffer> &mb, const Registry &reg,
StringRef path, bool logLoading)
: ArchiveLibraryFile(path), _mb(mb), _registry(reg),
_logLoading(logLoading) {}
std::error_code doParse() override {
// Make Archive object which will be owned by FileArchive object.
std::error_code ec;
_archive.reset(new Archive(_mb->getMemBufferRef(), ec));
if (ec)
return ec;
if ((ec = buildTableOfContents()))
return ec;
return std::error_code();
}
virtual ~FileArchive() {}
/// \brief Check if any member of the archive contains an Atom with the
@ -204,6 +214,7 @@ private:
typedef std::unordered_map<StringRef, Archive::child_iterator> MemberMap;
typedef std::set<const char *> InstantiatedSet;
std::unique_ptr<MemoryBuffer> &_mb;
const Registry &_registry;
std::unique_ptr<Archive> _archive;
mutable MemberMap _symbolMemberMap;
@ -229,20 +240,8 @@ public:
std::error_code
parseFile(std::unique_ptr<MemoryBuffer> &mb, const Registry &reg,
std::vector<std::unique_ptr<File>> &result) const override {
MemoryBuffer &buff = *mb;
// Make Archive object which will be owned by FileArchive object.
std::error_code ec;
Archive *archive = new Archive(mb->getMemBufferRef(), ec);
if (ec)
return ec;
StringRef path = buff.getBufferIdentifier();
// Construct FileArchive object.
std::unique_ptr<FileArchive> file(
new FileArchive(reg, archive, path, false, _logLoading));
ec = file->buildTableOfContents();
if (ec)
return ec;
new FileArchive(mb, reg, mb->getBufferIdentifier(), _logLoading));
result.push_back(std::move(file));
return std::error_code();
}

View File

@ -24,6 +24,9 @@ using lld::mach_o::normalized::Section;
class MachOFile : public SimpleFile {
public:
MachOFile(MemoryBuffer *mb, MachOLinkingContext *ctx)
: SimpleFile(mb->getBufferIdentifier()), _mb(mb), _ctx(ctx) {}
MachOFile(StringRef path) : SimpleFile(path) {}
void addDefinedAtom(StringRef name, Atom::Scope scope,
@ -172,6 +175,19 @@ public:
visitor(offAndAtom.atom, offAndAtom.offset);
}
std::error_code doParse() override {
// Convert binary file to normalized mach-o.
std::unique_ptr<MemoryBuffer>mb(_mb);
auto normFile = normalized::readBinary(mb, _ctx->arch());
mb.release();
if (std::error_code ec = normFile.getError())
return ec;
// Convert normalized mach-o to atoms.
if (std::error_code ec = normalized::normalizedObjectToAtoms(
this, **normFile, false))
return ec;
return std::error_code();
}
private:
struct SectionOffsetAndAtom { uint64_t offset; MachODefinedAtom *atom; };
@ -190,17 +206,18 @@ private:
std::vector<SectionOffsetAndAtom>> SectionToAtoms;
typedef llvm::StringMap<const lld::Atom *> NameToAtom;
MemoryBuffer *_mb;
MachOLinkingContext *_ctx;
SectionToAtoms _sectionAtoms;
NameToAtom _undefAtoms;
};
class MachODylibFile : public SharedLibraryFile {
public:
MachODylibFile(StringRef path, StringRef installName, uint32_t compatVersion,
uint32_t currentVersion)
: SharedLibraryFile(path), _installName(installName),
_currentVersion(currentVersion), _compatVersion(compatVersion) {
}
MachODylibFile(MemoryBuffer *mb, MachOLinkingContext *ctx)
: SharedLibraryFile(mb->getBufferIdentifier()), _mb(mb), _ctx(ctx) {}
MachODylibFile(StringRef path) : SharedLibraryFile(path) {}
const SharedLibraryAtom *exports(StringRef name, bool isData) const override {
// Pass down _installName so that if this requested symbol
@ -241,11 +258,13 @@ public:
}
StringRef installName() { return _installName; }
uint32_t currentVersion() { return _currentVersion; }
uint32_t compatVersion() { return _compatVersion; }
void setInstallName(StringRef name) { _installName = name; }
void setCompatVersion(uint32_t version) { _compatVersion = version; }
void setCurrentVersion(uint32_t version) { _currentVersion = version; }
typedef std::function<MachODylibFile *(StringRef)> FindDylib;
void loadReExportedDylibs(FindDylib find) {
@ -254,6 +273,20 @@ public:
}
}
std::error_code doParse() override {
// Convert binary file to normalized mach-o.
std::unique_ptr<MemoryBuffer>mb(_mb);
auto normFile = normalized::readBinary(mb, _ctx->arch());
mb.release();
if (std::error_code ec = normFile.getError())
return ec;
// Convert normalized mach-o to atoms.
if (std::error_code ec = normalized::normalizedDylibToAtoms(
this, **normFile, false))
return ec;
return std::error_code();
}
private:
const SharedLibraryAtom *exports(StringRef name,
StringRef installName) const {
@ -295,6 +328,8 @@ private:
bool weakDef;
};
MemoryBuffer *_mb;
MachOLinkingContext *_ctx;
StringRef _installName;
uint32_t _currentVersion;
uint32_t _compatVersion;

View File

@ -285,6 +285,16 @@ readYaml(std::unique_ptr<MemoryBuffer> &mb);
/// Writes a yaml encoded mach-o files given an in-memory normalized view.
std::error_code writeYaml(const NormalizedFile &file, raw_ostream &out);
std::error_code
normalizedObjectToAtoms(MachOFile *file,
const NormalizedFile &normalizedFile,
bool copyRefs);
std::error_code
normalizedDylibToAtoms(MachODylibFile *file,
const NormalizedFile &normalizedFile,
bool copyRefs);
/// Takes in-memory normalized dylib or object and parses it into lld::File
ErrorOr<std::unique_ptr<lld::File>>
normalizedToAtoms(const NormalizedFile &normalizedFile, StringRef path,

View File

@ -505,14 +505,39 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb,
return std::move(f);
}
class MachOReader : public Reader {
class MachOObjectReader : public Reader {
public:
MachOReader(MachOLinkingContext &ctx) : _ctx(ctx) {}
MachOObjectReader(MachOLinkingContext &ctx) : _ctx(ctx) {}
bool canParse(file_magic magic, StringRef ext,
const MemoryBuffer &mb) const override {
switch (magic) {
case llvm::sys::fs::file_magic::macho_object:
return (mb.getBufferSize() > 32);
default:
return false;
}
}
std::error_code
parseFile(std::unique_ptr<MemoryBuffer> &mb, const Registry &registry,
std::vector<std::unique_ptr<File>> &result) const override {
auto *file = new MachOFile(mb.get(), &_ctx);
result.push_back(std::unique_ptr<MachOFile>(file));
return std::error_code();
}
private:
MachOLinkingContext &_ctx;
};
class MachODylibReader : public Reader {
public:
MachODylibReader(MachOLinkingContext &ctx) : _ctx(ctx) {}
bool canParse(file_magic magic, StringRef ext,
const MemoryBuffer &mb) const override {
switch (magic) {
case llvm::sys::fs::file_magic::macho_dynamically_linked_shared_lib:
case llvm::sys::fs::file_magic::macho_dynamically_linked_shared_lib_stub:
return (mb.getBufferSize() > 32);
@ -524,30 +549,22 @@ public:
std::error_code
parseFile(std::unique_ptr<MemoryBuffer> &mb, const Registry &registry,
std::vector<std::unique_ptr<File>> &result) const override {
// Convert binary file to normalized mach-o.
auto normFile = readBinary(mb, _ctx.arch());
if (std::error_code ec = normFile.getError())
return ec;
// Convert normalized mach-o to atoms.
auto file = normalizedToAtoms(**normFile, mb->getBufferIdentifier(), false);
if (std::error_code ec = file.getError())
return ec;
result.push_back(std::move(*file));
auto *file = new MachODylibFile(mb.get(), &_ctx);
result.push_back(std::unique_ptr<MachODylibFile>(file));
return std::error_code();
}
private:
MachOLinkingContext &_ctx;
};
} // namespace normalized
} // namespace mach_o
void Registry::addSupportMachOObjects(MachOLinkingContext &ctx) {
MachOLinkingContext::Arch arch = ctx.arch();
add(std::unique_ptr<Reader>(new mach_o::normalized::MachOReader(ctx)));
add(std::unique_ptr<Reader>(new mach_o::normalized::MachOObjectReader(ctx)));
add(std::unique_ptr<Reader>(new mach_o::normalized::MachODylibReader(ctx)));
addKindTable(Reference::KindNamespace::mach_o, ctx.archHandler().kindArch(),
ctx.archHandler().kindStrings());
add(std::unique_ptr<YamlIOTaggedDocumentHandler>(

View File

@ -712,9 +712,32 @@ std::error_code addEHFrameReferences(const NormalizedFile &normalizedFile,
/// Converts normalized mach-o file into an lld::File and lld::Atoms.
ErrorOr<std::unique_ptr<lld::File>>
normalizedObjectToAtoms(const NormalizedFile &normalizedFile, StringRef path,
bool copyRefs) {
objectToAtoms(const NormalizedFile &normalizedFile, StringRef path,
bool copyRefs) {
std::unique_ptr<MachOFile> file(new MachOFile(path));
if (std::error_code ec = normalizedObjectToAtoms(
file.get(), normalizedFile, copyRefs))
return ec;
return std::unique_ptr<File>(std::move(file));
}
ErrorOr<std::unique_ptr<lld::File>>
dylibToAtoms(const NormalizedFile &normalizedFile, StringRef path,
bool copyRefs) {
// Instantiate SharedLibraryFile object.
std::unique_ptr<MachODylibFile> file(new MachODylibFile(path));
normalizedDylibToAtoms(file.get(), normalizedFile, copyRefs);
return std::unique_ptr<File>(std::move(file));
}
} // anonymous namespace
namespace normalized {
std::error_code
normalizedObjectToAtoms(MachOFile *file,
const NormalizedFile &normalizedFile,
bool copyRefs) {
bool scatterable = ((normalizedFile.flags & MH_SUBSECTIONS_VIA_SYMBOLS) != 0);
// Create atoms from each section.
@ -811,18 +834,17 @@ normalizedObjectToAtoms(const NormalizedFile &normalizedFile, StringRef path,
for (const DefinedAtom* defAtom : file->defined()) {
reinterpret_cast<const SimpleDefinedAtom*>(defAtom)->sortReferences();
}
return std::unique_ptr<File>(std::move(file));
return std::error_code();
}
ErrorOr<std::unique_ptr<lld::File>>
normalizedDylibToAtoms(const NormalizedFile &normalizedFile, StringRef path,
std::error_code
normalizedDylibToAtoms(MachODylibFile *file,
const NormalizedFile &normalizedFile,
bool copyRefs) {
// Instantiate SharedLibraryFile object.
std::unique_ptr<MachODylibFile> file(
new MachODylibFile(path, normalizedFile.installName,
normalizedFile.compatVersion,
normalizedFile.currentVersion));
file->setInstallName(normalizedFile.installName);
file->setCompatVersion(normalizedFile.compatVersion);
file->setCurrentVersion(normalizedFile.currentVersion);
// Tell MachODylibFile object about all symbols it exports.
if (!normalizedFile.exportInfo.empty()) {
// If exports trie exists, use it instead of traditional symbol table.
@ -843,14 +865,9 @@ normalizedDylibToAtoms(const NormalizedFile &normalizedFile, StringRef path,
if (dep.kind == llvm::MachO::LC_REEXPORT_DYLIB)
file->addReExportedDylib(dep.path);
}
return std::unique_ptr<File>(std::move(file));
return std::error_code();
}
} // anonymous namespace
namespace normalized {
void relocatableSectionInfoForContentType(DefinedAtom::ContentType atomType,
StringRef &segmentName,
StringRef &sectionName,
@ -881,9 +898,9 @@ normalizedToAtoms(const NormalizedFile &normalizedFile, StringRef path,
switch (normalizedFile.fileType) {
case MH_DYLIB:
case MH_DYLIB_STUB:
return normalizedDylibToAtoms(normalizedFile, path, copyRefs);
return dylibToAtoms(normalizedFile, path, copyRefs);
case MH_OBJECT:
return normalizedObjectToAtoms(normalizedFile, path, copyRefs);
return objectToAtoms(normalizedFile, path, copyRefs);
default:
llvm_unreachable("unhandled MachO file type!");
}

View File

@ -259,14 +259,21 @@ private:
//
class File : public lld::File {
public:
File(std::unique_ptr<MemoryBuffer> mb)
: lld::File(mb->getBufferIdentifier(), kindObject),
_mb(std::move(mb)), // Reader now takes ownership of buffer
_header(nullptr), _targetsTable(nullptr), _targetsTableCount(0),
_strings(nullptr), _stringsMaxOffset(0), _addends(nullptr),
_addendsMaxIndex(0), _contentStart(nullptr), _contentEnd(nullptr) {
_header =
reinterpret_cast<const NativeFileHeader *>(_mb->getBufferStart());
}
/// Instantiates a File object from a native object file. Ownership
/// of the MemoryBuffer is transferred to the resulting File object.
static std::error_code make(std::unique_ptr<MemoryBuffer> mb,
std::vector<std::unique_ptr<lld::File>> &result) {
/// Parses a File object from a native object file.
std::error_code doParse() override {
const uint8_t *const base =
reinterpret_cast<const uint8_t *>(mb->getBufferStart());
StringRef path(mb->getBufferIdentifier());
reinterpret_cast<const uint8_t *>(_mb->getBufferStart());
StringRef path(_mb->getBufferIdentifier());
const NativeFileHeader *const header =
reinterpret_cast<const NativeFileHeader *>(base);
const NativeChunk *const chunks =
@ -277,7 +284,7 @@ public:
return make_error_code(NativeReaderError::unknown_file_format);
// make sure mapped file contains all needed data
const size_t fileSize = mb->getBufferSize();
const size_t fileSize = _mb->getBufferSize();
if (header->fileSize > fileSize)
return make_error_code(NativeReaderError::file_too_short);
@ -286,9 +293,6 @@ public:
<< header->fileSize << " chunkCount="
<< header->chunkCount << "\n");
// instantiate NativeFile object and add values to it as found
std::unique_ptr<File> file(new File(std::move(mb), path));
// process each chunk
for (uint32_t i = 0; i < header->chunkCount; ++i) {
std::error_code ec;
@ -301,40 +305,40 @@ public:
// process chunk, based on signature
switch ( chunk->signature ) {
case NCS_DefinedAtomsV1:
ec = file->processDefinedAtomsV1(base, chunk);
ec = processDefinedAtomsV1(base, chunk);
break;
case NCS_AttributesArrayV1:
ec = file->processAttributesV1(base, chunk);
ec = processAttributesV1(base, chunk);
break;
case NCS_UndefinedAtomsV1:
ec = file->processUndefinedAtomsV1(base, chunk);
ec = processUndefinedAtomsV1(base, chunk);
break;
case NCS_SharedLibraryAtomsV1:
ec = file->processSharedLibraryAtomsV1(base, chunk);
ec = processSharedLibraryAtomsV1(base, chunk);
break;
case NCS_AbsoluteAtomsV1:
ec = file->processAbsoluteAtomsV1(base, chunk);
ec = processAbsoluteAtomsV1(base, chunk);
break;
case NCS_AbsoluteAttributesV1:
ec = file->processAbsoluteAttributesV1(base, chunk);
ec = processAbsoluteAttributesV1(base, chunk);
break;
case NCS_ReferencesArrayV1:
ec = file->processReferencesV1(base, chunk);
ec = processReferencesV1(base, chunk);
break;
case NCS_ReferencesArrayV2:
ec = file->processReferencesV2(base, chunk);
ec = processReferencesV2(base, chunk);
break;
case NCS_TargetsTable:
ec = file->processTargetsTable(base, chunk);
ec = processTargetsTable(base, chunk);
break;
case NCS_AddendsTable:
ec = file->processAddendsTable(base, chunk);
ec = processAddendsTable(base, chunk);
break;
case NCS_Content:
ec = file->processContent(base, chunk);
ec = processContent(base, chunk);
break;
case NCS_Strings:
ec = file->processStrings(base, chunk);
ec = processStrings(base, chunk);
break;
default:
return make_error_code(NativeReaderError::unknown_chunk_type);
@ -347,7 +351,7 @@ public:
DEBUG_WITH_TYPE("ReaderNative", {
llvm::dbgs() << " ReaderNative DefinedAtoms:\n";
for (const DefinedAtom *a : file->defined()) {
for (const DefinedAtom *a : defined()) {
llvm::dbgs() << llvm::format(" 0x%09lX", a)
<< ", name=" << a->name()
<< ", size=" << a->size() << "\n";
@ -359,12 +363,11 @@ public:
}
}
});
result.push_back(std::move(file));
return make_error_code(NativeReaderError::success);
}
virtual ~File() {
// _buffer is automatically deleted because of std::unique_ptr<>
// _mb is automatically deleted because of std::unique_ptr<>
// All other ivar pointers are pointers into the MemoryBuffer, except
// the _definedAtoms array which was allocated to contain an array
@ -785,17 +788,6 @@ private:
_targetsTable[index] = newAtom;
}
// private constructor, only called by make()
File(std::unique_ptr<MemoryBuffer> mb, StringRef path)
: lld::File(path, kindObject),
_buffer(std::move(mb)), // Reader now takes ownership of buffer
_header(nullptr), _targetsTable(nullptr), _targetsTableCount(0),
_strings(nullptr), _stringsMaxOffset(0), _addends(nullptr),
_addendsMaxIndex(0), _contentStart(nullptr), _contentEnd(nullptr) {
_header =
reinterpret_cast<const NativeFileHeader *>(_buffer->getBufferStart());
}
template <typename T>
class AtomArray : public File::atom_collection<T> {
public:
@ -836,7 +828,7 @@ private:
uint32_t elementCount;
};
std::unique_ptr<MemoryBuffer> _buffer;
std::unique_ptr<MemoryBuffer> _mb;
const NativeFileHeader* _header;
AtomArray<DefinedAtom> _definedAtoms;
AtomArray<UndefinedAtom> _undefinedAtoms;
@ -1009,9 +1001,12 @@ public:
virtual std::error_code
parseFile(std::unique_ptr<MemoryBuffer> &mb, const class Registry &,
std::vector<std::unique_ptr<File>> &result) const override {
return lld::native::File::make(std::move(mb), result);
auto *file = new lld::native::File(std::move(mb));
result.push_back(std::unique_ptr<File>(file));
return std::error_code();
}
};
}
void Registry::addSupportNativeObjects() {

View File

@ -55,6 +55,21 @@ using namespace lld;
namespace {
class BumpPtrStringSaver : public llvm::cl::StringSaver {
public:
const char *SaveString(const char *str) override {
size_t len = strlen(str);
std::lock_guard<std::mutex> lock(_allocMutex);
char *copy = _alloc.Allocate<char>(len + 1);
memcpy(copy, str, len + 1);
return copy;
}
private:
llvm::BumpPtrAllocator _alloc;
std::mutex _allocMutex;
};
class FileCOFF : public File {
private:
typedef std::vector<llvm::object::COFFSymbolRef> SymbolVectorT;
@ -66,10 +81,12 @@ private:
public:
typedef const std::map<std::string, std::string> StringMap;
FileCOFF(std::unique_ptr<MemoryBuffer> mb, std::error_code &ec);
FileCOFF(std::unique_ptr<MemoryBuffer> mb, PECOFFLinkingContext &ctx)
: File(mb->getBufferIdentifier(), kindObject), _mb(std::move(mb)),
_compatibleWithSEH(false), _ordinal(0),
_machineType(llvm::COFF::MT_Invalid), _ctx(ctx) {}
std::error_code parse();
StringRef getLinkerDirectives() const { return _directives; }
std::error_code doParse() override;
bool isCompatibleWithSEH() const { return _compatibleWithSEH; }
llvm::COFF::MachineTypes getMachineType() { return _machineType; }
@ -98,6 +115,11 @@ public:
_undefinedAtoms._atoms.push_back(new (_alloc) COFFUndefinedAtom(*this, sym));
}
AliasAtom *createAlias(StringRef name, const DefinedAtom *target);
void createAlternateNameAtoms();
std::error_code parseDirectiveSection(
StringRef directives, std::set<StringRef> *undefinedSymbols);
mutable llvm::BumpPtrAllocator _alloc;
private:
@ -155,9 +177,6 @@ private:
// The target type of the object.
Reference::KindArch _referenceArch;
// The contents of .drectve section.
StringRef _directives;
// True if the object has "@feat.00" symbol.
bool _compatibleWithSEH;
@ -192,21 +211,8 @@ private:
uint64_t _ordinal;
llvm::COFF::MachineTypes _machineType;
};
class BumpPtrStringSaver : public llvm::cl::StringSaver {
public:
const char *SaveString(const char *str) override {
size_t len = strlen(str);
std::lock_guard<std::mutex> lock(_allocMutex);
char *copy = _alloc.Allocate<char>(len + 1);
memcpy(copy, str, len + 1);
return copy;
}
private:
llvm::BumpPtrAllocator _alloc;
std::mutex _allocMutex;
PECOFFLinkingContext &_ctx;
mutable BumpPtrStringSaver _stringSaver;
};
// Converts the COFF symbol attribute to the LLD's atom attribute.
@ -290,33 +296,54 @@ DefinedAtom::Merge getMerge(const coff_aux_section_definition *auxsym) {
}
}
FileCOFF::FileCOFF(std::unique_ptr<MemoryBuffer> mb, std::error_code &ec)
: File(mb->getBufferIdentifier(), kindObject), _mb(std::move(mb)),
_compatibleWithSEH(false), _ordinal(0),
_machineType(llvm::COFF::MT_Invalid) {
StringRef getMachineName(llvm::COFF::MachineTypes Type) {
switch (Type) {
default: llvm_unreachable("unsupported machine type");
case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
return "ARM";
case llvm::COFF::IMAGE_FILE_MACHINE_I386:
return "X86";
case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
return "X64";
}
}
std::error_code FileCOFF::doParse() {
auto binaryOrErr = llvm::object::createBinary(_mb->getMemBufferRef());
if ((ec = binaryOrErr.getError()))
return;
if (std::error_code ec = binaryOrErr.getError())
return ec;
std::unique_ptr<llvm::object::Binary> bin = std::move(binaryOrErr.get());
_obj.reset(dyn_cast<const llvm::object::COFFObjectFile>(bin.get()));
if (!_obj) {
ec = make_error_code(llvm::object::object_error::invalid_file_type);
return;
}
if (!_obj)
return make_error_code(llvm::object::object_error::invalid_file_type);
bin.release();
_machineType = static_cast<llvm::COFF::MachineTypes>(_obj->getMachine());
if (getMachineType() != llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN &&
getMachineType() != _ctx.getMachineType()) {
llvm::errs() << "module machine type '"
<< getMachineName(getMachineType())
<< "' conflicts with target machine type '"
<< getMachineName(_ctx.getMachineType()) << "'\n";
return NativeReaderError::conflicting_target_machine;
}
// The set to contain the symbols specified as arguments of
// /INCLUDE option.
std::set<StringRef> undefinedSymbols;
// Interpret .drectve section if the section has contents.
// Read .drectve section if exists.
ArrayRef<uint8_t> directives;
if ((ec = getSectionContents(".drectve", directives)))
return;
if (std::error_code ec = getSectionContents(".drectve", directives))
return ec;
if (!directives.empty())
_directives = ArrayRefToString(directives);
}
if (std::error_code ec = parseDirectiveSection(
ArrayRefToString(directives), &undefinedSymbols))
return ec;
std::error_code FileCOFF::parse() {
if (std::error_code ec = getReferenceArch(_referenceArch))
return ec;
@ -329,7 +356,7 @@ std::error_code FileCOFF::parse() {
createAbsoluteAtoms(symbols, _absoluteAtoms._atoms);
if (std::error_code ec =
createUndefinedAtoms(symbols, _undefinedAtoms._atoms))
createUndefinedAtoms(symbols, _undefinedAtoms._atoms))
return ec;
if (std::error_code ec = createDefinedSymbols(symbols, _definedAtoms._atoms))
return ec;
@ -337,6 +364,37 @@ std::error_code FileCOFF::parse() {
return ec;
if (std::error_code ec = maybeCreateSXDataAtoms())
return ec;
// Check for /SAFESEH.
if (_ctx.requireSEH() && !isCompatibleWithSEH()) {
llvm::errs() << "/SAFESEH is specified, but "
<< _mb->getBufferIdentifier()
<< " is not compatible with SEH.\n";
return llvm::object::object_error::parse_failed;
}
// Add /INCLUDE'ed symbols to the file as if they existed in the
// file as undefined symbols.
for (StringRef sym : undefinedSymbols)
addUndefinedSymbol(sym);
// One can define alias symbols using /alternatename:<sym>=<sym> option.
// The mapping for /alternatename is in the context object. This helper
// function iterate over defined atoms and create alias atoms if needed.
createAlternateNameAtoms();
// Acquire the mutex to mutate _ctx.
std::lock_guard<std::recursive_mutex> lock(_ctx.getMutex());
// In order to emit SEH table, all input files need to be compatible with
// SEH. Disable SEH if the file being read is not compatible.
if (!isCompatibleWithSEH())
_ctx.setSafeSEH(false);
if (_ctx.deadStrip())
for (StringRef sym : undefinedSymbols)
_ctx.addDeadStripRoot(sym);
return std::error_code();
}
@ -804,6 +862,67 @@ std::error_code FileCOFF::getSectionContents(StringRef sectionName,
return std::error_code();
}
AliasAtom *FileCOFF::createAlias(StringRef name,
const DefinedAtom *target) {
AliasAtom *alias = new (_alloc) AliasAtom(*this, name);
alias->addReference(Reference::KindNamespace::all, Reference::KindArch::all,
Reference::kindLayoutAfter, 0, target, 0);
alias->setMerge(DefinedAtom::mergeAsWeak);
if (target->contentType() == DefinedAtom::typeCode)
alias->setDeadStrip(DefinedAtom::deadStripNever);
return alias;
}
void FileCOFF::createAlternateNameAtoms() {
std::vector<AliasAtom *> aliases;
for (const DefinedAtom *atom : defined()) {
auto it = _ctx.alternateNames().find(atom->name());
if (it != _ctx.alternateNames().end())
aliases.push_back(createAlias(it->second, atom));
}
for (AliasAtom *alias : aliases)
addDefinedAtom(alias);
}
// Interpret the contents of .drectve section. If exists, the section contains
// a string containing command line options. The linker is expected to
// interpret the options as if they were given via the command line.
//
// The section mainly contains /defaultlib (-l in Unix), but can contain any
// options as long as they are valid.
std::error_code
FileCOFF::parseDirectiveSection(StringRef directives,
std::set<StringRef> *undefinedSymbols) {
DEBUG(llvm::dbgs() << ".drectve: " << directives << "\n");
// Split the string into tokens, as the shell would do for argv.
SmallVector<const char *, 16> tokens;
tokens.push_back("link"); // argv[0] is the command name. Will be ignored.
llvm::cl::TokenizeWindowsCommandLine(directives, _stringSaver, tokens);
tokens.push_back(nullptr);
// Calls the command line parser to interpret the token string as if they
// were given via the command line.
int argc = tokens.size() - 1;
const char **argv = &tokens[0];
std::string errorMessage;
llvm::raw_string_ostream stream(errorMessage);
bool parseFailed = !WinLinkDriver::parse(argc, argv, _ctx, stream,
/*isDirective*/ true,
undefinedSymbols);
stream.flush();
// Print error message if error.
if (parseFailed) {
auto msg = Twine("Failed to parse '") + directives + "'\n"
+ "Reason: " + errorMessage;
return make_dynamic_error_code(msg);
}
if (!errorMessage.empty()) {
llvm::errs() << "lld warning: " << errorMessage << "\n";
}
return std::error_code();
}
/// Returns the target machine type of the current object file.
std::error_code FileCOFF::getReferenceArch(Reference::KindArch &result) {
switch (_obj->getMachine()) {
@ -945,18 +1064,6 @@ StringRef FileCOFF::ArrayRefToString(ArrayRef<uint8_t> array) {
return StringRef(*contents).trim();
}
StringRef getMachineName(llvm::COFF::MachineTypes Type) {
switch (Type) {
default: llvm_unreachable("unsupported machine type");
case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
return "ARM";
case llvm::COFF::IMAGE_FILE_MACHINE_I386:
return "X86";
case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
return "X64";
}
}
class COFFObjectReader : public Reader {
public:
COFFObjectReader(PECOFFLinkingContext &ctx) : _ctx(ctx) {}
@ -967,136 +1074,16 @@ public:
}
std::error_code
parseFile(std::unique_ptr<MemoryBuffer> &mb, const Registry &registry,
parseFile(std::unique_ptr<MemoryBuffer> &mb, const Registry &,
std::vector<std::unique_ptr<File>> &result) const override {
// Parse the memory buffer as PECOFF file.
const char *mbName = mb->getBufferIdentifier();
std::error_code ec;
std::unique_ptr<FileCOFF> file(new FileCOFF(std::move(mb), ec));
if (ec)
return ec;
if (file->getMachineType() != llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN &&
file->getMachineType() != _ctx.getMachineType()) {
llvm::errs() << "module machine type '"
<< getMachineName(file->getMachineType())
<< "' conflicts with target machine type '"
<< getMachineName(_ctx.getMachineType()) << "'\n";
return NativeReaderError::conflicting_target_machine;
}
// The set to contain the symbols specified as arguments of
// /INCLUDE option.
std::set<StringRef> undefinedSymbols;
// Interpret .drectve section if the section has contents.
StringRef directives = file->getLinkerDirectives();
if (!directives.empty())
if (std::error_code ec = handleDirectiveSection(
directives, &undefinedSymbols))
return ec;
if (std::error_code ec = file->parse())
return ec;
// Check for /SAFESEH.
if (_ctx.requireSEH() && !file->isCompatibleWithSEH()) {
llvm::errs() << "/SAFESEH is specified, but " << mbName
<< " is not compatible with SEH.\n";
return llvm::object::object_error::parse_failed;
}
// Add /INCLUDE'ed symbols to the file as if they existed in the
// file as undefined symbols.
for (StringRef sym : undefinedSymbols)
file->addUndefinedSymbol(sym);
// One can define alias symbols using /alternatename:<sym>=<sym> option.
// The mapping for /alternatename is in the context object. This helper
// function iterate over defined atoms and create alias atoms if needed.
createAlternateNameAtoms(*file);
// Acquire the mutex to mutate _ctx.
std::lock_guard<std::recursive_mutex> lock(_ctx.getMutex());
// In order to emit SEH table, all input files need to be compatible with
// SEH. Disable SEH if the file being read is not compatible.
if (!file->isCompatibleWithSEH())
_ctx.setSafeSEH(false);
if (_ctx.deadStrip())
for (StringRef sym : undefinedSymbols)
_ctx.addDeadStripRoot(sym);
result.push_back(std::move(file));
auto *file = new FileCOFF(std::move(mb), _ctx);
result.push_back(std::unique_ptr<File>(file));
return std::error_code();
}
private:
// Interpret the contents of .drectve section. If exists, the section contains
// a string containing command line options. The linker is expected to
// interpret the options as if they were given via the command line.
//
// The section mainly contains /defaultlib (-l in Unix), but can contain any
// options as long as they are valid.
std::error_code handleDirectiveSection(StringRef directives,
std::set<StringRef> *undefinedSymbols) const {
DEBUG(llvm::dbgs() << ".drectve: " << directives << "\n");
// Split the string into tokens, as the shell would do for argv.
SmallVector<const char *, 16> tokens;
tokens.push_back("link"); // argv[0] is the command name. Will be ignored.
llvm::cl::TokenizeWindowsCommandLine(directives, _stringSaver, tokens);
tokens.push_back(nullptr);
// Calls the command line parser to interpret the token string as if they
// were given via the command line.
int argc = tokens.size() - 1;
const char **argv = &tokens[0];
std::string errorMessage;
llvm::raw_string_ostream stream(errorMessage);
bool parseFailed = !WinLinkDriver::parse(argc, argv, _ctx, stream,
/*isDirective*/ true,
undefinedSymbols);
stream.flush();
// Print error message if error.
if (parseFailed) {
auto msg = Twine("Failed to parse '") + directives + "'\n"
+ "Reason: " + errorMessage;
return make_dynamic_error_code(msg);
}
if (!errorMessage.empty()) {
llvm::errs() << "lld warning: " << errorMessage << "\n";
}
return std::error_code();
}
AliasAtom *createAlias(FileCOFF &file, StringRef name,
const DefinedAtom *target) const {
AliasAtom *alias = new (file._alloc) AliasAtom(file, name);
alias->addReference(Reference::KindNamespace::all, Reference::KindArch::all,
Reference::kindLayoutAfter, 0, target, 0);
alias->setMerge(DefinedAtom::mergeAsWeak);
if (target->contentType() == DefinedAtom::typeCode)
alias->setDeadStrip(DefinedAtom::deadStripNever);
return alias;
}
// Iterates over defined atoms and create alias atoms if needed.
void createAlternateNameAtoms(FileCOFF &file) const {
std::vector<AliasAtom *> aliases;
for (const DefinedAtom *atom : file.defined()) {
auto it = _ctx.alternateNames().find(atom->name());
if (it != _ctx.alternateNames().end())
aliases.push_back(createAlias(file, it->second, atom));
}
for (AliasAtom *alias : aliases) {
file.addDefinedAtom(alias);
}
}
PECOFFLinkingContext &_ctx;
mutable BumpPtrStringSaver _stringSaver;
};
using namespace llvm::COFF;

View File

@ -197,31 +197,31 @@ private:
class FileImportLibrary : public File {
public:
FileImportLibrary(std::unique_ptr<MemoryBuffer> mb, std::error_code &ec,
MachineTypes machine)
: File(mb->getBufferIdentifier(), kindSharedLibrary), _machine(machine) {
const char *buf = mb->getBufferStart();
const char *end = mb->getBufferEnd();
FileImportLibrary(std::unique_ptr<MemoryBuffer> mb, MachineTypes machine)
: File(mb->getBufferIdentifier(), kindSharedLibrary),
_mb(std::move(mb)), _machine(machine) {}
std::error_code doParse() override {
const char *buf = _mb->getBufferStart();
const char *end = _mb->getBufferEnd();
// The size of the string that follows the header.
uint32_t dataSize = *reinterpret_cast<const support::ulittle32_t *>(
buf + offsetof(COFF::ImportHeader, SizeOfData));
buf + offsetof(COFF::ImportHeader, SizeOfData));
// Check if the total size is valid.
if (std::size_t(end - buf) != sizeof(COFF::ImportHeader) + dataSize) {
ec = make_error_code(NativeReaderError::unknown_file_format);
return;
}
if (std::size_t(end - buf) != sizeof(COFF::ImportHeader) + dataSize)
return make_error_code(NativeReaderError::unknown_file_format);
uint16_t hint = *reinterpret_cast<const support::ulittle16_t *>(
buf + offsetof(COFF::ImportHeader, OrdinalHint));
buf + offsetof(COFF::ImportHeader, OrdinalHint));
StringRef symbolName(buf + sizeof(COFF::ImportHeader));
StringRef dllName(buf + sizeof(COFF::ImportHeader) + symbolName.size() + 1);
// TypeInfo is a bitfield. The least significant 2 bits are import
// type, followed by 3 bit import name type.
uint16_t typeInfo = *reinterpret_cast<const support::ulittle16_t *>(
buf + offsetof(COFF::ImportHeader, TypeInfo));
buf + offsetof(COFF::ImportHeader, TypeInfo));
int type = typeInfo & 0x3;
int nameType = (typeInfo >> 2) & 0x7;
@ -235,7 +235,7 @@ public:
if (type == llvm::COFF::IMPORT_CODE)
addFuncAtom(symbolName, dllName, dataAtom);
ec = std::error_code();
return std::error_code();
}
const atom_collection<DefinedAtom> &defined() const override {
@ -309,6 +309,7 @@ private:
return *str;
}
std::unique_ptr<MemoryBuffer> _mb;
MachineTypes _machine;
};
@ -326,12 +327,8 @@ public:
std::error_code
parseFile(std::unique_ptr<MemoryBuffer> &mb, const class Registry &,
std::vector<std::unique_ptr<File> > &result) const override {
std::error_code ec;
auto file = std::unique_ptr<File>(
new FileImportLibrary(std::move(mb), ec, _machine));
if (ec)
return ec;
result.push_back(std::move(file));
auto *file = new FileImportLibrary(std::move(mb), _machine);
result.push_back(std::unique_ptr<File>(file));
return std::error_code();
}

View File

@ -7,6 +7,7 @@
//
//===----------------------------------------------------------------------===//
#include "lld/Core/File.h"
#include "lld/ReaderWriter/Reader.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Errc.h"
@ -38,9 +39,16 @@ Registry::parseFile(std::unique_ptr<MemoryBuffer> &mb,
StringRef extension = llvm::sys::path::extension(mb->getBufferIdentifier());
// Ask each registered reader if it can handle this file type or extension.
for (const std::unique_ptr<Reader> &reader : _readers)
if (reader->canParse(fileType, extension, *mb))
return reader->parseFile(mb, *this, result);
for (const std::unique_ptr<Reader> &reader : _readers) {
if (!reader->canParse(fileType, extension, *mb))
continue;
if (std::error_code ec = reader->parseFile(mb, *this, result))
return ec;
for (std::unique_ptr<File> &file : result)
if (std::error_code ec = file->parse())
return ec;
return std::error_code();
}
// No Reader could parse this file.
return make_error_code(llvm::errc::executable_format_error);

View File

@ -1351,6 +1351,7 @@ public:
for (const File *file : createdFiles) {
// Note: parseFile() should return vector of *const* File
File *f = const_cast<File *>(file);
f->setLastError(std::error_code());
result.emplace_back(f);
}
return make_error_code(lld::YamlReaderError::success);