Add COFF reader.
There are no tests for this yet because I still need to finish the YAML -> COFF converter so we don't get binary files checked in. llvm-svn: 156100
This commit is contained in:
parent
64cc29cb84
commit
60d835fa59
|
@ -0,0 +1,29 @@
|
|||
//===- Reader.h - Create object file readers ------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_READER_READER_H_
|
||||
#define LLD_READER_READER_H_
|
||||
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace llvm {
|
||||
class error_code;
|
||||
class MemoryBuffer;
|
||||
}
|
||||
|
||||
namespace lld {
|
||||
class File;
|
||||
|
||||
llvm::error_code parseCOFFObjectFile(std::unique_ptr<llvm::MemoryBuffer> MB,
|
||||
std::unique_ptr<File> &Result);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,3 +1,4 @@
|
|||
add_subdirectory(Core)
|
||||
add_subdirectory(Passes)
|
||||
add_subdirectory(Platforms)
|
||||
add_subdirectory(Reader)
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
add_lld_library(lldReader
|
||||
COFFReader.cpp
|
||||
)
|
|
@ -0,0 +1,366 @@
|
|||
//===- COFFReader.h - PECOFF Object File Reader ---------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "lld/Reader/Reader.h"
|
||||
#include "lld/Core/File.h"
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/Object/COFF.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/Memory.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/system_error.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
using namespace lld;
|
||||
using llvm::object::coff_symbol;
|
||||
|
||||
class COFFAbsoluteAtom : public AbsoluteAtom {
|
||||
public:
|
||||
COFFAbsoluteAtom(const File &F, llvm::StringRef N, uint64_t V)
|
||||
: OwningFile(F)
|
||||
, Name(N)
|
||||
, Value(V)
|
||||
{}
|
||||
|
||||
virtual const class File& file() const {
|
||||
return OwningFile;
|
||||
}
|
||||
|
||||
virtual llvm::StringRef name() const {
|
||||
return Name;
|
||||
}
|
||||
|
||||
virtual uint64_t value() const {
|
||||
return Value;
|
||||
}
|
||||
|
||||
private:
|
||||
const File &OwningFile;
|
||||
llvm::StringRef Name;
|
||||
uint64_t Value;
|
||||
};
|
||||
|
||||
class COFFUndefinedAtom : public UndefinedAtom {
|
||||
public:
|
||||
COFFUndefinedAtom(const File &F, llvm::StringRef N)
|
||||
: OwningFile(F)
|
||||
, Name(N)
|
||||
{}
|
||||
|
||||
virtual const class File& file() const {
|
||||
return OwningFile;
|
||||
}
|
||||
|
||||
virtual llvm::StringRef name() const {
|
||||
return Name;
|
||||
}
|
||||
|
||||
virtual CanBeNull canBeNull() const {
|
||||
return CanBeNull::canBeNullNever;
|
||||
}
|
||||
|
||||
private:
|
||||
const File &OwningFile;
|
||||
llvm::StringRef Name;
|
||||
};
|
||||
|
||||
class COFFDefinedAtom : public DefinedAtom {
|
||||
public:
|
||||
COFFDefinedAtom( const File &F
|
||||
, llvm::StringRef N
|
||||
, const llvm::object::coff_symbol *Symb
|
||||
, const llvm::object::coff_section *Sec
|
||||
, llvm::ArrayRef<uint8_t> D)
|
||||
: OwningFile(F)
|
||||
, Name(N)
|
||||
, Symbol(Symb)
|
||||
, Section(Sec)
|
||||
, Data(D)
|
||||
{}
|
||||
|
||||
virtual const class File& file() const {
|
||||
return OwningFile;
|
||||
}
|
||||
|
||||
virtual llvm::StringRef name() const {
|
||||
return Name;
|
||||
}
|
||||
|
||||
virtual uint64_t ordinal() const {
|
||||
return reinterpret_cast<intptr_t>(Symbol);
|
||||
}
|
||||
|
||||
virtual uint64_t size() const {
|
||||
return Data.size();
|
||||
}
|
||||
|
||||
virtual Scope scope() const {
|
||||
if (!Symbol)
|
||||
return scopeTranslationUnit;
|
||||
switch (Symbol->StorageClass) {
|
||||
case llvm::COFF::IMAGE_SYM_CLASS_EXTERNAL:
|
||||
return scopeGlobal;
|
||||
case llvm::COFF::IMAGE_SYM_CLASS_STATIC:
|
||||
return scopeTranslationUnit;
|
||||
}
|
||||
llvm_unreachable("Unknown scope!");
|
||||
}
|
||||
|
||||
virtual Interposable interposable() const {
|
||||
return interposeNo;
|
||||
}
|
||||
|
||||
virtual Merge merge() const {
|
||||
return mergeNo;
|
||||
}
|
||||
|
||||
virtual ContentType contentType() const {
|
||||
if (Section->Characteristics & llvm::COFF::IMAGE_SCN_CNT_CODE)
|
||||
return typeCode;
|
||||
if (Section->Characteristics & llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA)
|
||||
return typeData;
|
||||
if (Section->Characteristics & llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
|
||||
return typeZeroFill;
|
||||
return typeUnknown;
|
||||
}
|
||||
|
||||
virtual Alignment alignment() const {
|
||||
return Alignment(1);
|
||||
}
|
||||
|
||||
virtual SectionChoice sectionChoice() const {
|
||||
return sectionBasedOnContent;
|
||||
}
|
||||
|
||||
virtual llvm::StringRef customSectionName() const {
|
||||
return "";
|
||||
}
|
||||
|
||||
virtual DeadStripKind deadStrip() const {
|
||||
return deadStripNormal;
|
||||
}
|
||||
|
||||
virtual ContentPermissions permissions() const {
|
||||
if ( Section->Characteristics & llvm::COFF::IMAGE_SCN_MEM_READ
|
||||
&& Section->Characteristics & llvm::COFF::IMAGE_SCN_MEM_WRITE)
|
||||
return permRW_;
|
||||
if ( Section->Characteristics & llvm::COFF::IMAGE_SCN_MEM_READ
|
||||
&& Section->Characteristics & llvm::COFF::IMAGE_SCN_MEM_EXECUTE)
|
||||
return permR_X;
|
||||
if (Section->Characteristics & llvm::COFF::IMAGE_SCN_MEM_READ)
|
||||
return permR__;
|
||||
return perm___;
|
||||
}
|
||||
|
||||
virtual bool isThumb() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool isAlias() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual llvm::ArrayRef<uint8_t> rawContent() const {
|
||||
return Data;
|
||||
}
|
||||
|
||||
virtual reference_iterator begin() const {
|
||||
return reference_iterator(*this, nullptr);
|
||||
}
|
||||
|
||||
virtual reference_iterator end() const {
|
||||
return reference_iterator(*this, nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual const Reference* derefIterator(const void* iter) const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual void incrementIterator(const void*& iter) const {
|
||||
|
||||
}
|
||||
|
||||
const File &OwningFile;
|
||||
llvm::StringRef Name;
|
||||
const llvm::object::coff_symbol *Symbol;
|
||||
const llvm::object::coff_section *Section;
|
||||
llvm::ArrayRef<uint8_t> Data;
|
||||
};
|
||||
|
||||
class COFFReader : public File {
|
||||
public:
|
||||
COFFReader(std::unique_ptr<llvm::MemoryBuffer> MB, llvm::error_code &EC)
|
||||
: File(MB->getBufferIdentifier()) {
|
||||
llvm::OwningPtr<llvm::object::Binary> Bin;
|
||||
EC = llvm::object::createBinary(MB.release(), Bin);
|
||||
if (EC)
|
||||
return;
|
||||
|
||||
Obj.reset(llvm::dyn_cast<const llvm::object::COFFObjectFile>(Bin.get()));
|
||||
if (Obj)
|
||||
Bin.take();
|
||||
else {
|
||||
EC = make_error_code(llvm::object::object_error::invalid_file_type);
|
||||
return;
|
||||
}
|
||||
|
||||
const llvm::object::coff_file_header *Header = nullptr;
|
||||
if ((EC = Obj->getHeader(Header)))
|
||||
return;
|
||||
|
||||
// Assign each symbol to the section it's in. If it does not belong to a
|
||||
// section, create an atom for it now.
|
||||
std::map< const llvm::object::coff_section*
|
||||
, std::vector<const llvm::object::coff_symbol*>> SectionSymbols;
|
||||
|
||||
for (uint32_t i = 0, e = Header->NumberOfSymbols; i != e; ++i) {
|
||||
const llvm::object::coff_symbol *Symb;
|
||||
if ((EC = Obj->getSymbol(i, Symb)))
|
||||
return;
|
||||
llvm::StringRef Name;
|
||||
if ((EC = Obj->getSymbolName(Symb, Name)))
|
||||
return;
|
||||
int16_t SectionIndex = Symb->SectionNumber;
|
||||
assert(SectionIndex != llvm::COFF::IMAGE_SYM_DEBUG &&
|
||||
"Cannot atomize IMAGE_SYM_DEBUG!");
|
||||
if (SectionIndex == llvm::COFF::IMAGE_SYM_ABSOLUTE) {
|
||||
// Create an absolute atom.
|
||||
AbsoluteAtoms._atoms.push_back(
|
||||
new (AtomStorage.Allocate<COFFAbsoluteAtom>())
|
||||
COFFAbsoluteAtom(*this, Name, Symb->Value));
|
||||
} else if (SectionIndex == llvm::COFF::IMAGE_SYM_UNDEFINED) {
|
||||
// Create an undefined atom.
|
||||
UndefinedAtoms._atoms.push_back(
|
||||
new (AtomStorage.Allocate<COFFUndefinedAtom>())
|
||||
COFFUndefinedAtom(*this, Name));
|
||||
} else {
|
||||
// This is actually a defined symbol. Add it to its section's list of
|
||||
// symbols.
|
||||
uint8_t SC = Symb->StorageClass;
|
||||
// If Symb->Value actually means section offset.
|
||||
if ( SC == llvm::COFF::IMAGE_SYM_CLASS_EXTERNAL
|
||||
|| SC == llvm::COFF::IMAGE_SYM_CLASS_STATIC
|
||||
|| SC == llvm::COFF::IMAGE_SYM_CLASS_FUNCTION) {
|
||||
const llvm::object::coff_section *Sec;
|
||||
if ((EC = Obj->getSection(SectionIndex, Sec)))
|
||||
return;
|
||||
assert(Sec && "SectionIndex > 0, Sec must be non-null!");
|
||||
SectionSymbols[Sec].push_back(Symb);
|
||||
} else {
|
||||
llvm::errs() << "Unable to create atom for: " << Name << "\n";
|
||||
EC = llvm::object::object_error::parse_failed;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Skip aux symbols.
|
||||
i += Symb->NumberOfAuxSymbols;
|
||||
}
|
||||
|
||||
// For each section, sort its symbols by address, then create a defined atom
|
||||
// for each range.
|
||||
for (auto i = SectionSymbols.begin(), e = SectionSymbols.end();
|
||||
i != e; ++i) {
|
||||
auto &Symbs = i->second;
|
||||
// Sort symbols by position.
|
||||
std::stable_sort(Symbs.begin(), Symbs.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;
|
||||
}));
|
||||
|
||||
if (Symbs.empty()) {
|
||||
// Create an atom for the entire section.
|
||||
llvm::ArrayRef<uint8_t> Data;
|
||||
DefinedAtoms._atoms.push_back(
|
||||
new (AtomStorage.Allocate<COFFDefinedAtom>())
|
||||
COFFDefinedAtom(*this, "", nullptr, i->first, Data));
|
||||
continue;
|
||||
}
|
||||
|
||||
llvm::ArrayRef<uint8_t> SecData;
|
||||
if ((EC = Obj->getSectionContents(i->first, SecData)))
|
||||
return;
|
||||
|
||||
// Create an unnamed atom if the first atom isn't at the start of the
|
||||
// section.
|
||||
if (Symbs[0]->Value != 0) {
|
||||
uint64_t Size = Symbs[0]->Value;
|
||||
llvm::ArrayRef<uint8_t> Data(SecData.data(), Size);
|
||||
DefinedAtoms._atoms.push_back(
|
||||
new (AtomStorage.Allocate<COFFDefinedAtom>())
|
||||
COFFDefinedAtom(*this, "", nullptr, i->first, Data));
|
||||
}
|
||||
|
||||
for (auto si = Symbs.begin(), se = Symbs.end(); si != se; ++si) {
|
||||
// if this is the last symbol, take up the remaining data.
|
||||
llvm::ArrayRef<uint8_t> Data;
|
||||
if (si + 1 == se) {
|
||||
Data = llvm::ArrayRef<uint8_t>( SecData.data() + (*si)->Value
|
||||
, SecData.end());
|
||||
} else {
|
||||
Data = llvm::ArrayRef<uint8_t>( SecData.data() + (*si)->Value
|
||||
, (*(si + 1))->Value - (*si)->Value);
|
||||
}
|
||||
llvm::StringRef Name;
|
||||
if ((EC = Obj->getSymbolName(*si, Name)))
|
||||
return;
|
||||
DefinedAtoms._atoms.push_back(
|
||||
new (AtomStorage.Allocate<COFFDefinedAtom>())
|
||||
COFFDefinedAtom(*this, Name, *si, i->first, Data));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void addAtom(const Atom&) {
|
||||
llvm_unreachable("cannot add atoms to native .obj files");
|
||||
}
|
||||
|
||||
virtual const atom_collection<DefinedAtom> &defined() const {
|
||||
return DefinedAtoms;
|
||||
}
|
||||
|
||||
virtual const atom_collection<UndefinedAtom> &undefined() const {
|
||||
return UndefinedAtoms;
|
||||
}
|
||||
|
||||
virtual const atom_collection<SharedLibraryAtom> &sharedLibrary() const {
|
||||
return SharedLibraryAtoms;
|
||||
}
|
||||
|
||||
virtual const atom_collection<AbsoluteAtom> &absolute() const {
|
||||
return AbsoluteAtoms;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<const llvm::object::COFFObjectFile> Obj;
|
||||
atom_collection_vector<DefinedAtom> DefinedAtoms;
|
||||
atom_collection_vector<UndefinedAtom> UndefinedAtoms;
|
||||
atom_collection_vector<SharedLibraryAtom> SharedLibraryAtoms;
|
||||
atom_collection_vector<AbsoluteAtom> AbsoluteAtoms;
|
||||
llvm::BumpPtrAllocator AtomStorage;
|
||||
};
|
||||
|
||||
llvm::error_code
|
||||
lld::parseCOFFObjectFile(std::unique_ptr<llvm::MemoryBuffer> MB,
|
||||
std::unique_ptr<File> &Result) {
|
||||
llvm::error_code EC;
|
||||
Result.reset(new COFFReader(std::move(MB), EC));
|
||||
if (EC)
|
||||
Result.release();
|
||||
return EC;
|
||||
}
|
|
@ -1,11 +1,13 @@
|
|||
set(LLVM_USED_LIBS
|
||||
lldCore
|
||||
lldReader
|
||||
lldPasses
|
||||
lldDarwinPlatform
|
||||
)
|
||||
|
||||
set(LLVM_LINK_COMPONENTS
|
||||
support
|
||||
Object
|
||||
)
|
||||
|
||||
add_lld_executable(lld-core
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "lld/Core/Resolver.h"
|
||||
#include "lld/Core/YamlReader.h"
|
||||
#include "lld/Core/YamlWriter.h"
|
||||
#include "lld/Reader/Reader.h"
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
|
@ -348,10 +349,9 @@ const TestingPlatform::KindMapping TestingPlatform::_s_kindMappings[] = {
|
|||
} // anon namespace
|
||||
|
||||
|
||||
llvm::cl::opt<std::string>
|
||||
cmdLineInputFilePath(llvm::cl::Positional,
|
||||
llvm::cl::desc("<input file>"),
|
||||
llvm::cl::init("-"));
|
||||
llvm::cl::list<std::string>
|
||||
cmdLineInputFilePaths(llvm::cl::Positional,
|
||||
llvm::cl::desc("<input file>"));
|
||||
|
||||
llvm::cl::opt<std::string>
|
||||
cmdLineOutputFilePath("o",
|
||||
|
@ -421,6 +421,9 @@ int main(int argc, char *argv[]) {
|
|||
// parse options
|
||||
llvm::cl::ParseCommandLineOptions(argc, argv);
|
||||
|
||||
if (cmdLineInputFilePaths.empty())
|
||||
cmdLineInputFilePaths.emplace_back("-");
|
||||
|
||||
// create platform for testing
|
||||
Platform* platform = nullptr;
|
||||
switch ( platformSelected ) {
|
||||
|
@ -434,9 +437,23 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
// read input YAML doc into object file(s)
|
||||
std::vector<std::unique_ptr<const File>> files;
|
||||
if (error(yaml::parseObjectTextFileOrSTDIN(cmdLineInputFilePath,
|
||||
*platform, files))) {
|
||||
return 1;
|
||||
for (auto path : cmdLineInputFilePaths) {
|
||||
OwningPtr<llvm::MemoryBuffer> ofile;
|
||||
if (error(llvm::MemoryBuffer::getFileOrSTDIN(path, ofile)))
|
||||
return 1;
|
||||
std::unique_ptr<llvm::MemoryBuffer> file(ofile.take());
|
||||
if (llvm::sys::fs::identify_magic(file->getBuffer())
|
||||
== llvm::sys::fs::file_magic::coff_object) {
|
||||
std::unique_ptr<File> f;
|
||||
if (error(parseCOFFObjectFile(std::move(file), f)))
|
||||
return 1;
|
||||
files.push_back(std::move(f));
|
||||
} else {
|
||||
if (error(yaml::parseObjectText( file.release()
|
||||
, *platform
|
||||
, files)))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// create options for resolving
|
||||
|
|
Loading…
Reference in New Issue