forked from OSchip/llvm-project
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:
parent
adb3864744
commit
1d510428e8
|
@ -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:
|
||||
|
|
|
@ -26,6 +26,7 @@ namespace lld {
|
|||
namespace mach_o {
|
||||
class ArchHandler;
|
||||
class MachODylibFile;
|
||||
class MachOFile;
|
||||
}
|
||||
|
||||
class MachOLinkingContext : public LinkingContext {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -33,12 +33,22 @@ namespace {
|
|||
/// \brief The FileArchive class represents an Archive Library file
|
||||
class FileArchive : public lld::ArchiveLibraryFile {
|
||||
public:
|
||||
FileArchive(const Registry ®istry, 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 ®,
|
||||
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 ®,
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 ®istry,
|
||||
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 ®istry,
|
||||
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>(
|
||||
|
|
|
@ -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 §ionName,
|
||||
|
@ -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!");
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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 ®istry,
|
||||
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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue