summaryrefslogtreecommitdiffstats
path: root/lld/lib/ReaderWriter/PECOFF
diff options
context:
space:
mode:
Diffstat (limited to 'lld/lib/ReaderWriter/PECOFF')
-rw-r--r--lld/lib/ReaderWriter/PECOFF/Atoms.h19
-rw-r--r--lld/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h2
-rw-r--r--lld/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp42
-rw-r--r--lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp459
-rw-r--r--lld/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp54
-rw-r--r--lld/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp21
6 files changed, 305 insertions, 292 deletions
diff --git a/lld/lib/ReaderWriter/PECOFF/Atoms.h b/lld/lib/ReaderWriter/PECOFF/Atoms.h
index 50c983d9261..2057dd5bb42 100644
--- a/lld/lib/ReaderWriter/PECOFF/Atoms.h
+++ b/lld/lib/ReaderWriter/PECOFF/Atoms.h
@@ -27,13 +27,11 @@ class COFFDefinedAtom;
/// to be fixed up so that the address points to atom Y's address.
class COFFReference LLVM_FINAL : public Reference {
public:
- explicit COFFReference(Kind kind) : _target(nullptr), _offsetInAtom(0) {
- _kind = kind;
- }
-
- COFFReference(const Atom *target, uint32_t offsetInAtom, uint16_t relocType)
- : _target(target), _offsetInAtom(offsetInAtom) {
- setKind(static_cast<Reference::Kind>(relocType));
+ COFFReference(const Atom *target, uint32_t offsetInAtom, uint16_t relocType,
+ Reference::KindNamespace ns=Reference::KindNamespace::COFF,
+ Reference::KindArch arch=Reference::KindArch::x86)
+ : Reference(ns, arch, relocType),
+ _target(target), _offsetInAtom(offsetInAtom) {
}
virtual const Atom *target() const { return _target; }
@@ -326,7 +324,7 @@ private:
class VirtualFile : public SimpleFile {
public:
VirtualFile(const LinkingContext &ctx)
- : SimpleFile(ctx, "<virtual-file>"), _nextOrdinal(0) {
+ : SimpleFile("<virtual-file>"), _nextOrdinal(0) {
setOrdinal(ctx.getNextOrdinalAndIncrement());
}
@@ -343,8 +341,9 @@ private:
//===----------------------------------------------------------------------===//
template <typename T, typename U>
-void addLayoutEdge(T *a, U *b, lld::Reference::Kind kind) {
- auto ref = new COFFReference(kind);
+void addLayoutEdge(T *a, U *b, uint32_t which) {
+ auto ref = new COFFReference(nullptr, 0, which, Reference::KindNamespace::all,
+ Reference::KindArch::all);
ref->setTarget(b);
a->addReference(std::unique_ptr<COFFReference>(ref));
}
diff --git a/lld/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h b/lld/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h
index 06b453c816a..248aaabbef4 100644
--- a/lld/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h
+++ b/lld/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h
@@ -21,7 +21,7 @@ namespace pecoff {
class LinkerGeneratedSymbolFile : public SimpleFile {
public:
LinkerGeneratedSymbolFile(const PECOFFLinkingContext &ctx)
- : SimpleFile(ctx, "<linker-internal-file>"),
+ : SimpleFile("<linker-internal-file>"),
_imageBaseAtom(*this, ctx.decorateSymbol("__ImageBase"),
Atom::scopeGlobal, ctx.getBaseAddress()) {
addAtom(_imageBaseAtom);
diff --git a/lld/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp b/lld/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp
index 2560e45ad68..251812e386b 100644
--- a/lld/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp
+++ b/lld/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp
@@ -78,7 +78,6 @@ bool PECOFFLinkingContext::validateImpl(raw_ostream &diagnostics) {
return false;
}
- _reader = createReaderPECOFF(*this);
_writer = createWriterPECOFF(*this);
return true;
}
@@ -87,7 +86,7 @@ std::unique_ptr<File> PECOFFLinkingContext::createEntrySymbolFile() const {
if (entrySymbolName().empty())
return nullptr;
std::unique_ptr<SimpleFile> entryFile(
- new SimpleFile(*this, "command line option /entry"));
+ new SimpleFile("command line option /entry"));
entryFile->addAtom(
*(new (_allocator) SimpleUndefinedAtom(*entryFile, entrySymbolName())));
return std::move(entryFile);
@@ -97,7 +96,7 @@ std::unique_ptr<File> PECOFFLinkingContext::createUndefinedSymbolFile() const {
if (_initialUndefinedSymbols.empty())
return nullptr;
std::unique_ptr<SimpleFile> undefinedSymFile(
- new SimpleFile(*this, "command line option /c (or) /include"));
+ new SimpleFile("command line option /c (or) /include"));
for (auto undefSymStr : _initialUndefinedSymbols)
undefinedSymFile->addAtom(*(new (_allocator) SimpleUndefinedAtom(
*undefinedSymFile, undefSymStr)));
@@ -208,40 +207,6 @@ StringRef PECOFFLinkingContext::decorateSymbol(StringRef name) const {
Writer &PECOFFLinkingContext::writer() const { return *_writer; }
-ErrorOr<Reference::Kind>
-PECOFFLinkingContext::relocKindFromString(StringRef str) const {
-#define LLD_CASE(name) .Case(#name, llvm::COFF::name)
- int32_t ret = llvm::StringSwitch<int32_t>(str)
- LLD_CASE(IMAGE_REL_I386_ABSOLUTE)
- LLD_CASE(IMAGE_REL_I386_DIR32)
- LLD_CASE(IMAGE_REL_I386_DIR32NB)
- LLD_CASE(IMAGE_REL_I386_SECTION)
- LLD_CASE(IMAGE_REL_I386_SECREL)
- LLD_CASE(IMAGE_REL_I386_REL32)
- .Default(-1);
-#undef LLD_CASE
- if (ret == -1)
- return make_error_code(YamlReaderError::illegal_value);
- return ret;
-}
-
-ErrorOr<std::string>
-PECOFFLinkingContext::stringFromRelocKind(Reference::Kind kind) const {
- switch (kind) {
-#define LLD_CASE(name) \
- case llvm::COFF::name: \
- return std::string(#name);
-
- LLD_CASE(IMAGE_REL_I386_ABSOLUTE)
- LLD_CASE(IMAGE_REL_I386_DIR32)
- LLD_CASE(IMAGE_REL_I386_DIR32NB)
- LLD_CASE(IMAGE_REL_I386_SECTION)
- LLD_CASE(IMAGE_REL_I386_SECREL)
- LLD_CASE(IMAGE_REL_I386_REL32)
-#undef LLD_CASE
- }
- return make_error_code(YamlReaderError::illegal_value);
-}
void PECOFFLinkingContext::setSectionSetMask(StringRef sectionName,
uint32_t newFlags) {
@@ -270,7 +235,8 @@ uint32_t PECOFFLinkingContext::getSectionAttributes(StringRef sectionName,
uint32_t clearMask = (ci == _sectionClearMask.end()) ? 0 : ci->second;
return (flags | setMask) & ~clearMask;
}
-
+
+
void PECOFFLinkingContext::addPasses(PassManager &pm) {
pm.add(std::unique_ptr<Pass>(new pecoff::SetSubsystemPass(*this)));
pm.add(std::unique_ptr<Pass>(new pecoff::EdataPass(*this)));
diff --git a/lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp b/lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp
index 95c1acf897a..bc5c7cc8f10 100644
--- a/lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp
+++ b/lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp
@@ -59,11 +59,13 @@ private:
typedef std::map<const coff_section *, SymbolVectorT> SectionToSymbolsT;
typedef std::map<const StringRef, Atom *> SymbolNameToAtomT;
typedef std::map<const coff_section *, vector<COFFDefinedFileAtom *> >
- SectionToAtomsT;
+ SectionToAtomsT;
public:
- FileCOFF(const PECOFFLinkingContext &context,
- std::unique_ptr<MemoryBuffer> mb, error_code &ec);
+ typedef const std::map<std::string, std::string> StringMap;
+
+ FileCOFF(std::unique_ptr<MemoryBuffer> mb, StringMap &altNames,
+ error_code &ec);
virtual const atom_collection<DefinedAtom> &defined() const {
return _definedAtoms;
@@ -81,11 +83,10 @@ public:
return _absoluteAtoms;
}
- virtual const LinkingContext &getLinkingContext() const { return _context; }
-
StringRef getLinkerDirectives() const { return _directives; }
private:
+
error_code readSymbolTable(vector<const coff_symbol *> &result);
void createAbsoluteAtoms(const SymbolVectorT &symbols,
@@ -95,16 +96,19 @@ private:
vector<const UndefinedAtom *> &result);
error_code createDefinedSymbols(const SymbolVectorT &symbols,
+ StringMap &altNames,
vector<const DefinedAtom *> &result);
error_code cacheSectionAttributes();
error_code
- AtomizeDefinedSymbolsInSection(const coff_section *section,
- vector<const coff_symbol *> &symbols,
- vector<COFFDefinedFileAtom *> &atoms);
+ AtomizeDefinedSymbolsInSection(const coff_section *section,
+ StringMap &altNames,
+ vector<const coff_symbol *> &symbols,
+ vector<COFFDefinedFileAtom *> &atoms);
error_code AtomizeDefinedSymbols(SectionToSymbolsT &definedSymbols,
+ StringMap &altNames,
vector<const DefinedAtom *> &definedAtoms);
error_code findAtomAt(const coff_section *section, uint32_t targetAddress,
@@ -153,10 +157,9 @@ private:
// the section.
std::map<const coff_section *,
std::map<uint32_t, std::vector<COFFDefinedAtom *> > >
- _definedAtomLocations;
+ _definedAtomLocations;
mutable llvm::BumpPtrAllocator _alloc;
- const PECOFFLinkingContext &_context;
uint64_t _ordinal;
};
@@ -173,34 +176,6 @@ private:
llvm::BumpPtrAllocator _alloc;
};
-class ReaderCOFF : public Reader {
-public:
- explicit ReaderCOFF(PECOFFLinkingContext &context)
- : Reader(context), _PECOFFLinkingContext(context) {}
-
- error_code parseFile(std::unique_ptr<MemoryBuffer> &mb,
- std::vector<std::unique_ptr<File> > &result) const;
-
-private:
- error_code handleDirectiveSection(StringRef directives) const;
-
- ErrorOr<std::string>
- writeResToTemporaryFile(std::unique_ptr<MemoryBuffer> mb) const;
-
- ErrorOr<std::string>
- convertResourceFileToCOFF(std::unique_ptr<MemoryBuffer> mb) const;
-
- error_code convertAndParseResourceFile(
- std::unique_ptr<MemoryBuffer> &mb,
- std::vector<std::unique_ptr<File> > &result) const;
-
- error_code parseCOFFFile(std::unique_ptr<MemoryBuffer> &mb,
- std::vector<std::unique_ptr<File> > &result) const;
-
- PECOFFLinkingContext &_PECOFFLinkingContext;
- mutable BumpPtrStringSaver _stringSaver;
-};
-
// Converts the COFF symbol attribute to the LLD's atom attribute.
Atom::Scope getScope(const coff_symbol *symbol) {
switch (symbol->StorageClass) {
@@ -278,10 +253,9 @@ DefinedAtom::Merge getMerge(const coff_aux_section_definition *auxsym) {
}
}
-FileCOFF::FileCOFF(const PECOFFLinkingContext &context,
- std::unique_ptr<MemoryBuffer> mb, error_code &ec)
- : File(mb->getBufferIdentifier(), kindObject), _context(context),
- _ordinal(0) {
+FileCOFF::FileCOFF(std::unique_ptr<MemoryBuffer> mb, StringMap &altNames,
+ error_code &ec)
+ : File(mb->getBufferIdentifier(), kindObject), _ordinal(0) {
OwningPtr<llvm::object::Binary> bin;
ec = llvm::object::createBinary(mb.release(), bin);
if (ec)
@@ -304,7 +278,7 @@ FileCOFF::FileCOFF(const PECOFFLinkingContext &context,
createAbsoluteAtoms(symbols, _absoluteAtoms._atoms);
if ((ec = createUndefinedAtoms(symbols, _undefinedAtoms._atoms)))
return;
- if ((ec = createDefinedSymbols(symbols, _definedAtoms._atoms)))
+ if ((ec = createDefinedSymbols(symbols, altNames, _definedAtoms._atoms)))
return;
if ((ec = addRelocationReferenceToAtoms()))
@@ -427,6 +401,7 @@ FileCOFF::createUndefinedAtoms(const SymbolVectorT &symbols,
/// the other two, because in order to create the atom for the defined symbol
/// we need to know the adjacent symbols.
error_code FileCOFF::createDefinedSymbols(const SymbolVectorT &symbols,
+ StringMap &altNames,
vector<const DefinedAtom *> &result) {
// A defined atom can be merged if its section attribute allows its contents
// to be merged. In COFF, it's not very easy to get the section attribute
@@ -499,7 +474,7 @@ error_code FileCOFF::createDefinedSymbols(const SymbolVectorT &symbols,
}
// Atomize the defined symbols.
- if (error_code ec = AtomizeDefinedSymbols(definedSymbols, result))
+ if (error_code ec = AtomizeDefinedSymbols(definedSymbols, altNames, result))
return ec;
return error_code::success();
@@ -552,17 +527,19 @@ error_code FileCOFF::cacheSectionAttributes() {
/// assumed to have been defined in the \p section.
error_code
FileCOFF::AtomizeDefinedSymbolsInSection(const coff_section *section,
+ StringMap &altNames,
vector<const coff_symbol *> &symbols,
vector<COFFDefinedFileAtom *> &atoms) {
- // Sort symbols by position.
+ // Sort symbols by position.
std::stable_sort(
symbols.begin(), symbols.end(),
// For some reason MSVC fails to allow the lambda in this context with a
// "illegal use of local type in type instantiation". MSVC is clearly
// wrong here. Force a conversion to function pointer to work around.
- static_cast<bool (*)(const coff_symbol *, const coff_symbol *)>([](
- const coff_symbol * a,
- const coff_symbol * b)->bool { return a->Value < b->Value; }));
+ static_cast<bool(*)(const coff_symbol *, const coff_symbol *)>(
+ [](const coff_symbol * a, const coff_symbol * b)->bool {
+ return a->Value < b->Value;
+ }));
StringRef sectionName;
if (error_code ec = _obj->getSectionName(section, sectionName))
@@ -626,12 +603,10 @@ FileCOFF::AtomizeDefinedSymbolsInSection(const coff_section *section,
// if this is the last symbol, take up the remaining data.
const uint8_t *end = (si + 1 == se) ? secData.data() + secData.size()
: secData.data() + (*(si + 1))->Value;
- StringRef symbolName = _symbolName[*si];
- StringRef alias = _context.getAlternateName(symbolName);
-
- if (!alias.empty()) {
+ auto pos = altNames.find(_symbolName[*si]);
+ if (pos != altNames.end()) {
auto *atom = new (_alloc) COFFDefinedAtom(
- *this, alias, sectionName, getScope(*si), type, isComdat, perms,
+ *this, pos->second, sectionName, getScope(*si), type, isComdat, perms,
DefinedAtom::mergeAsWeak, ArrayRef<uint8_t>(), _ordinal++);
atoms.push_back(atom);
_symbolAtom[*si] = atom;
@@ -655,6 +630,7 @@ FileCOFF::AtomizeDefinedSymbolsInSection(const coff_section *section,
error_code
FileCOFF::AtomizeDefinedSymbols(SectionToSymbolsT &definedSymbols,
+ StringMap &altNames,
vector<const DefinedAtom *> &definedAtoms) {
// For each section, make atoms for all the symbols defined in the
// section, and append the atoms to the result objects.
@@ -662,7 +638,8 @@ FileCOFF::AtomizeDefinedSymbols(SectionToSymbolsT &definedSymbols,
const coff_section *section = i.first;
vector<const coff_symbol *> &symbols = i.second;
vector<COFFDefinedFileAtom *> atoms;
- if (error_code ec = AtomizeDefinedSymbolsInSection(section, symbols, atoms))
+ if (error_code ec =
+ AtomizeDefinedSymbolsInSection(section, altNames, symbols, atoms))
return ec;
// Connect atoms with layout-before/layout-after edges.
@@ -815,127 +792,6 @@ error_code FileCOFF::maybeReadLinkerDirectives() {
return error_code::success();
}
-error_code
-ReaderCOFF::parseFile(std::unique_ptr<MemoryBuffer> &mb,
- std::vector<std::unique_ptr<File> > &result) const {
- StringRef magic(mb->getBufferStart(), mb->getBufferSize());
-
- // The input file should be a resource file, an archive file, a regular COFF
- // file, or an import library member file. Try to parse in that order. If
- // the input file does not start with a known magic, parseCOFFImportLibrary
- // will return an error object.
- llvm::sys::fs::file_magic fileType = llvm::sys::fs::identify_magic(magic);
-
- if (fileType == llvm::sys::fs::file_magic::windows_resource)
- return convertAndParseResourceFile(mb, result);
- if (fileType == llvm::sys::fs::file_magic::coff_import_library)
- return lld::pecoff::parseCOFFImportLibrary(_context, mb, result);
- return parseCOFFFile(mb, result);
-}
-
-// 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.
-error_code ReaderCOFF::handleDirectiveSection(StringRef directives) 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, _PECOFFLinkingContext,
- stream, /*isDirective*/ true);
- stream.flush();
-
- // Print error message if error.
- if (parseFailed) {
- llvm::errs() << "Failed to parse '" << directives << "'\n"
- << "Reason: " << errorMessage;
- return make_error_code(llvm::object::object_error::invalid_file_type);
- }
- if (!errorMessage.empty()) {
- llvm::errs() << "lld warning: " << errorMessage << "\n";
- }
- return error_code::success();
-}
-
-ErrorOr<std::string>
-ReaderCOFF::writeResToTemporaryFile(std::unique_ptr<MemoryBuffer> mb) const {
- // Get a temporary file path for .res file.
- SmallString<128> tempFilePath;
- if (error_code ec =
- llvm::sys::fs::createTemporaryFile("tmp", "res", tempFilePath))
- return ec;
-
- // Write the memory buffer contents to .res file, so that we can run
- // cvtres.exe on it.
- OwningPtr<llvm::FileOutputBuffer> buffer;
- if (error_code ec = llvm::FileOutputBuffer::create(
- tempFilePath.str(), mb->getBufferSize(), buffer))
- return ec;
- memcpy(buffer->getBufferStart(), mb->getBufferStart(), mb->getBufferSize());
- if (error_code ec = buffer->commit())
- return ec;
-
- // Convert SmallString -> StringRef -> std::string.
- return tempFilePath.str().str();
-}
-
-ErrorOr<std::string>
-ReaderCOFF::convertResourceFileToCOFF(std::unique_ptr<MemoryBuffer> mb) const {
- // Write the resource file to a temporary file.
- ErrorOr<std::string> inFilePath = writeResToTemporaryFile(std::move(mb));
- if (!inFilePath)
- return error_code(inFilePath);
- llvm::FileRemover inFileRemover(*inFilePath);
-
- // Create an output file path.
- SmallString<128> outFilePath;
- if (error_code ec =
- llvm::sys::fs::createTemporaryFile("tmp", "obj", outFilePath))
- return ec;
- std::string outFileArg = ("/out:" + outFilePath).str();
-
- // Construct CVTRES.EXE command line and execute it.
- std::string program = "cvtres.exe";
- std::string programPath = llvm::sys::FindProgramByName(program);
- if (programPath.empty()) {
- llvm::errs() << "Unable to find " << program << " in PATH\n";
- return llvm::errc::broken_pipe;
- }
- std::vector<const char *> args;
- args.push_back(programPath.c_str());
- args.push_back("/machine:x86");
- args.push_back("/readonly");
- args.push_back("/nologo");
- args.push_back(outFileArg.c_str());
- args.push_back(inFilePath->c_str());
- args.push_back(nullptr);
-
- DEBUG({
- for (const char **p = &args[0]; *p; ++p)
- llvm::dbgs() << *p << " ";
- llvm::dbgs() << "\n";
- });
-
- if (llvm::sys::ExecuteAndWait(programPath.c_str(), &args[0]) != 0) {
- llvm::errs() << program << " failed\n";
- return llvm::errc::broken_pipe;
- }
- return outFilePath.str().str();
-}
-
// Convert .res file to .coff file and then parse it. Resource file is a file
// containing various types of data, such as icons, translation texts,
// etc. "cvtres.exe" command reads an RC file to create a COFF file which
@@ -943,57 +799,226 @@ ReaderCOFF::convertResourceFileToCOFF(std::unique_ptr<MemoryBuffer> mb) const {
//
// The linker is not capable to handle RC files directly. Instead, it runs
// cvtres.exe on RC files and then then link its outputs.
-error_code ReaderCOFF::convertAndParseResourceFile(
- std::unique_ptr<MemoryBuffer> &mb,
- std::vector<std::unique_ptr<File> > &result) const {
- // Convert an RC to a COFF
- ErrorOr<std::string> coffFilePath = convertResourceFileToCOFF(std::move(mb));
- if (!coffFilePath)
- return error_code(coffFilePath);
- llvm::FileRemover coffFileRemover(*coffFilePath);
-
- // Read and parse the COFF
- OwningPtr<MemoryBuffer> opmb;
- if (error_code ec = MemoryBuffer::getFile(*coffFilePath, opmb))
- return ec;
- std::unique_ptr<MemoryBuffer> newmb(opmb.take());
- return parseCOFFFile(newmb, result);
-}
+class ResourceFileReader : public Reader {
+public:
+ virtual bool canParse(file_magic magic, StringRef ext,
+ const MemoryBuffer &) const {
+ return (magic == llvm::sys::fs::file_magic::windows_resource);
+ }
-error_code
-ReaderCOFF::parseCOFFFile(std::unique_ptr<MemoryBuffer> &mb,
- std::vector<std::unique_ptr<File> > &result) const {
- // Parse the memory buffer as PECOFF file.
- error_code ec;
- std::unique_ptr<FileCOFF> file(
- new FileCOFF(_PECOFFLinkingContext, std::move(mb), ec));
- if (ec)
- return ec;
+ virtual error_code
+ parseFile(std::unique_ptr<MemoryBuffer> &mb, const class Registry &,
+ std::vector<std::unique_ptr<File> > &result) const {
+ // Convert RC file to COFF
+ ErrorOr<std::string> coffPath = convertResourceFileToCOFF(std::move(mb));
+ if (!coffPath)
+ return error_code(coffPath);
+ llvm::FileRemover coffFileRemover(*coffPath);
+
+ // Read and parse the COFF
+ OwningPtr<MemoryBuffer> opmb;
+ if (error_code ec = MemoryBuffer::getFile(*coffPath, opmb))
+ return ec;
+ std::unique_ptr<MemoryBuffer> newmb(opmb.take());
+ error_code ec;
+ FileCOFF::StringMap emptyMap;
+ std::unique_ptr<FileCOFF> file(
+ new FileCOFF(std::move(newmb), emptyMap, ec));
+ if (ec)
+ return ec;
+ result.push_back(std::move(file));
+ return error_code::success();
+ }
+
+private:
+ static ErrorOr<std::string>
+ writeResToTemporaryFile(std::unique_ptr<MemoryBuffer> mb) {
+ // Get a temporary file path for .res file.
+ SmallString<128> tempFilePath;
+ if (error_code ec =
+ llvm::sys::fs::createTemporaryFile("tmp", "res", tempFilePath))
+ return ec;
+
+ // Write the memory buffer contents to .res file, so that we can run
+ // cvtres.exe on it.
+ OwningPtr<llvm::FileOutputBuffer> buffer;
+ if (error_code ec = llvm::FileOutputBuffer::create(
+ tempFilePath.str(), mb->getBufferSize(), buffer))
+ return ec;
+ memcpy(buffer->getBufferStart(), mb->getBufferStart(), mb->getBufferSize());
+ if (error_code ec = buffer->commit())
+ return ec;
+
+ // Convert SmallString -> StringRef -> std::string.
+ return tempFilePath.str().str();
+ }
- DEBUG({
- llvm::dbgs() << "Defined atoms:\n";
- for (const auto &atom : file->defined()) {
- llvm::dbgs() << " " << atom->name() << "\n";
- for (const Reference *ref : *atom)
- llvm::dbgs() << " @" << ref->offsetInAtom() << " -> "
- << ref->target()->name() << "\n";
+ static ErrorOr<std::string>
+ convertResourceFileToCOFF(std::unique_ptr<MemoryBuffer> mb) {
+ // Write the resource file to a temporary file.
+ ErrorOr<std::string> inFilePath = writeResToTemporaryFile(std::move(mb));
+ if (!inFilePath)
+ return error_code(inFilePath);
+ llvm::FileRemover inFileRemover(*inFilePath);
+
+ // Create an output file path.
+ SmallString<128> outFilePath;
+ if (error_code ec =
+ llvm::sys::fs::createTemporaryFile("tmp", "obj", outFilePath))
+ return ec;
+ std::string outFileArg = ("/out:" + outFilePath).str();
+
+ // Construct CVTRES.EXE command line and execute it.
+ std::string program = "cvtres.exe";
+ std::string programPath = llvm::sys::FindProgramByName(program);
+ if (programPath.empty()) {
+ llvm::errs() << "Unable to find " << program << " in PATH\n";
+ return llvm::errc::broken_pipe;
+ }
+ std::vector<const char *> args;
+ args.push_back(programPath.c_str());
+ args.push_back("/machine:x86");
+ args.push_back("/readonly");
+ args.push_back("/nologo");
+ args.push_back(outFileArg.c_str());
+ args.push_back(inFilePath->c_str());
+ args.push_back(nullptr);
+
+ DEBUG({
+ for (const char **p = &args[0]; *p; ++p)
+ llvm::dbgs() << *p << " ";
+ llvm::dbgs() << "\n";
+ });
+
+ if (llvm::sys::ExecuteAndWait(programPath.c_str(), &args[0]) != 0) {
+ llvm::errs() << program << " failed\n";
+ return llvm::errc::broken_pipe;
}
- });
+ return outFilePath.str().str();
+ }
+};
+
+class COFFObjectReader : public Reader {
+public:
+ COFFObjectReader(PECOFFLinkingContext &ctx) : _context(ctx) {}
+
+ virtual bool canParse(file_magic magic, StringRef ext,
+ const MemoryBuffer &) const {
+ return (magic == llvm::sys::fs::file_magic::coff_object);
+ }
- // Interpret .drectve section if the section has contents.
- StringRef directives = file->getLinkerDirectives();
- if (!directives.empty())
- if (error_code ec = handleDirectiveSection(directives))
+ virtual error_code
+ parseFile(std::unique_ptr<MemoryBuffer> &mb, const Registry &registry,
+ std::vector<std::unique_ptr<File> > &result) const {
+ // Parse the memory buffer as PECOFF file.
+ error_code ec;
+ std::unique_ptr<FileCOFF> file(
+ new FileCOFF(std::move(mb), _context.alternateNames(), ec));
+ if (ec)
return ec;
- result.push_back(std::move(file));
- return error_code::success();
-}
+ // Interpret .drectve section if the section has contents.
+ StringRef directives = file->getLinkerDirectives();
+ if (!directives.empty())
+ if (error_code ec2 = handleDirectiveSection(registry, directives))
+ return ec2;
+
+ result.push_back(std::move(file));
+ return error_code::success();
+ }
+
+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.
+ error_code handleDirectiveSection(const Registry &registry,
+ StringRef directives) 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, _context, stream,
+ /*isDirective*/ true);
+ stream.flush();
+ // Print error message if error.
+ if (parseFailed) {
+ llvm::errs() << "Failed to parse '" << directives << "'\n"
+ << "Reason: " << errorMessage;
+ return make_error_code(llvm::object::object_error::invalid_file_type);
+ }
+ if (!errorMessage.empty()) {
+ llvm::errs() << "lld warning: " << errorMessage << "\n";
+ }
+ return error_code::success();
+ }
+
+ PECOFFLinkingContext &_context;
+ mutable BumpPtrStringSaver _stringSaver;
+};
+
+using namespace llvm::COFF;
+
+const Registry::KindStrings kindStringsI386[] = {
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_ABSOLUTE),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_DIR16),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_REL16),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_DIR32),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_DIR32NB),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_SEG12),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_SECTION),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_SECREL),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_TOKEN),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_SECREL7),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_REL32), LLD_KIND_STRING_END
+};
+
+const Registry::KindStrings kindStringsAMD64[] = {
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_ABSOLUTE),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_ADDR64),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_ADDR32),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_ADDR32NB),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32_1),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32_2),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32_3),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32_4),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32_5),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_SECTION),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_SECREL),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_SECREL7),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_TOKEN),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_SREL32),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_PAIR),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_SSPAN32), LLD_KIND_STRING_END
+};
} // end namespace anonymous
namespace lld {
-std::unique_ptr<Reader> createReaderPECOFF(PECOFFLinkingContext &context) {
- return std::unique_ptr<Reader>(new ReaderCOFF(context));
+
+void Registry::addSupportCOFFObjects(PECOFFLinkingContext &ctx) {
+ add(std::unique_ptr<Reader>(new COFFObjectReader(ctx)));
+ addKindTable(Reference::KindNamespace::COFF, Reference::KindArch::x86,
+ kindStringsI386);
+ addKindTable(Reference::KindNamespace::COFF, Reference::KindArch::x86_64,
+ kindStringsAMD64);
}
+
+void Registry::addSupportWindowsResourceFiles() {
+ add(std::unique_ptr<Reader>(new ResourceFileReader()));
+}
+
}
diff --git a/lld/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp b/lld/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp
index c16f53977a0..a6ad676546a 100644
--- a/lld/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp
+++ b/lld/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp
@@ -125,6 +125,7 @@
#include "lld/Core/File.h"
#include "lld/Core/Error.h"
#include "lld/Core/SharedLibraryAtom.h"
+#include "lld/ReaderWriter/PECOFFLinkingContext.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Object/COFF.h"
@@ -143,16 +144,15 @@
#include <cstring>
using namespace lld;
+using namespace lld::pecoff;
using namespace llvm;
namespace lld {
-namespace pecoff {
namespace {
-uint8_t FuncAtomContent[] = {
- 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *0x0
- 0xcc, 0xcc // int 3; int 3
+uint8_t FuncAtomContent[] = { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *0x0
+ 0xcc, 0xcc // int 3; int 3
};
/// The defined atom for jump table.
@@ -174,15 +174,14 @@ public:
class FileImportLibrary : public File {
public:
- FileImportLibrary(const LinkingContext &context,
- std::unique_ptr<MemoryBuffer> mb, error_code &ec)
- : File(mb->getBufferIdentifier(), kindSharedLibrary), _context(context) {
+ FileImportLibrary(std::unique_ptr<MemoryBuffer> mb, error_code &ec)
+ : File(mb->getBufferIdentifier(), kindSharedLibrary) {
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 (end - buf != sizeof(COFF::ImportHeader) + dataSize) {
@@ -191,14 +190,14 @@ public:
}
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;
@@ -231,8 +230,6 @@ public:
return _noAbsoluteAtoms;
}
- virtual const LinkingContext &getLinkingContext() const { return _context; }
-
private:
const COFFSharedLibraryAtom *addSharedLibraryAtom(uint16_t hint,
StringRef symbolName,
@@ -256,7 +253,6 @@ private:
atom_collection_vector<DefinedAtom> _definedAtoms;
atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
- const LinkingContext &_context;
mutable llvm::BumpPtrAllocator _alloc;
// Does the same thing as StringRef::ltrim() but removes at most one
@@ -294,8 +290,32 @@ private:
}
};
+class COFFImportLibraryReader : public Reader {
+public:
+ virtual bool canParse(file_magic magic, StringRef,
+ const MemoryBuffer &mb) const {
+ if (mb.getBufferSize() < sizeof(COFF::ImportHeader))
+ return false;
+ return (magic == llvm::sys::fs::file_magic::coff_import_library);
+ }
+
+ virtual error_code
+ parseFile(std::unique_ptr<MemoryBuffer> &mb, const class Registry &,
+ std::vector<std::unique_ptr<File> > &result) const {
+ error_code ec;
+ auto file = std::unique_ptr<File>(new FileImportLibrary(std::move(mb), ec));
+ if (ec)
+ return ec;
+ result.push_back(std::move(file));
+ return error_code::success();
+ }
+
+};
+
} // end anonymous namespace
+namespace pecoff {
+
error_code parseCOFFImportLibrary(const LinkingContext &targetInfo,
std::unique_ptr<MemoryBuffer> &mb,
std::vector<std::unique_ptr<File> > &result) {
@@ -308,8 +328,7 @@ error_code parseCOFFImportLibrary(const LinkingContext &targetInfo,
return make_error_code(NativeReaderError::unknown_file_format);
error_code ec;
- auto file = std::unique_ptr<File>(
- new FileImportLibrary(targetInfo, std::move(mb), ec));
+ auto file = std::unique_ptr<File>(new FileImportLibrary(std::move(mb), ec));
if (ec)
return ec;
result.push_back(std::move(file));
@@ -317,4 +336,9 @@ error_code parseCOFFImportLibrary(const LinkingContext &targetInfo,
}
} // end namespace pecoff
+
+void Registry::addSupportCOFFImportLibraries() {
+ add(std::unique_ptr<Reader>(new COFFImportLibraryReader()));
+}
+
} // end namespace lld
diff --git a/lld/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp b/lld/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp
index 05621416015..a1b81894208 100644
--- a/lld/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp
+++ b/lld/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp
@@ -72,7 +72,7 @@ public:
};
explicit Chunk(Kind kind) : _kind(kind), _size(0) {}
- virtual ~Chunk() {};
+ virtual ~Chunk() {}
virtual void write(uint8_t *buffer) = 0;
virtual uint64_t size() const { return _size; }
virtual uint64_t align() const { return 1; }
@@ -106,7 +106,7 @@ public:
: HeaderChunk(), _context(ctx) {
// Minimum size of DOS stub is 64 bytes. The next block (PE header) needs to
// be aligned on 8 byte boundary.
- size_t size = std::max(_context.getDosStub().size(), (size_t)64);
+ size_t size = std::max(_context.getDosStub().size(), (size_t) 64);
_size = llvm::RoundUpToAlignment(size, 8);
}
@@ -303,8 +303,8 @@ private:
// Create the content of a relocation block.
std::vector<uint8_t>
- createBaseRelocBlock(uint64_t pageAddr,
- const std::vector<uint16_t> &offsets) const;
+ createBaseRelocBlock(uint64_t pageAddr,
+ const std::vector<uint16_t> &offsets) const;
std::vector<uint8_t> _contents;
};
@@ -454,10 +454,9 @@ void AtomChunk::applyRelocations(uint8_t *buffer,
for (const auto *layout : _atomLayouts) {
const DefinedAtom *atom = cast<DefinedAtom>(layout->_atom);
for (const Reference *ref : *atom) {
- // Skip if this reference is not for relocation.
- if (ref->kind() < lld::Reference::kindTargetLow)
+ // Skip if this reference is not for COFF relocation.
+ if (ref->kindNamespace() != Reference::KindNamespace::COFF)
continue;
-
auto relocSite32 = reinterpret_cast<ulittle32_t *>(
buffer + layout->_fileOffset + ref->offsetInAtom());
auto relocSite16 = reinterpret_cast<ulittle16_t *>(relocSite32);
@@ -465,8 +464,7 @@ void AtomChunk::applyRelocations(uint8_t *buffer,
// Also account for whatever offset is already stored at the relocation
// site.
targetAddr += *relocSite32;
-
- switch (ref->kind()) {
+ switch (ref->kindValue()) {
case llvm::COFF::IMAGE_REL_I386_ABSOLUTE:
// This relocation is no-op.
break;
@@ -539,7 +537,8 @@ void AtomChunk::addBaseRelocations(std::vector<uint64_t> &relocSites) const {
for (const auto *layout : _atomLayouts) {
const DefinedAtom *atom = cast<DefinedAtom>(layout->_atom);
for (const Reference *ref : *atom)
- if (ref->kind() == llvm::COFF::IMAGE_REL_I386_DIR32)
+ if ((ref->kindNamespace() == Reference::KindNamespace::COFF) &&
+ (ref->kindValue() == llvm::COFF::IMAGE_REL_I386_DIR32))
relocSites.push_back(layout->_virtualAddr + ref->offsetInAtom());
}
}
@@ -753,7 +752,7 @@ private:
void setImageSizeOnDisk();
void setAddressOfEntryPoint(AtomChunk *text, PEHeaderChunk *peHeader);
uint64_t
- calcSectionSize(llvm::COFF::SectionCharacteristics sectionType) const;
+ calcSectionSize(llvm::COFF::SectionCharacteristics sectionType) const;
uint64_t calcSizeOfInitializedData() const {
return calcSectionSize(llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA);
OpenPOWER on IntegriCloud