diff options
Diffstat (limited to 'lld/tools/lld-core/lld-core.cpp')
| -rw-r--r-- | lld/tools/lld-core/lld-core.cpp | 480 |
1 files changed, 85 insertions, 395 deletions
diff --git a/lld/tools/lld-core/lld-core.cpp b/lld/tools/lld-core/lld-core.cpp index 229ed868614..37e69cdca47 100644 --- a/lld/tools/lld-core/lld-core.cpp +++ b/lld/tools/lld-core/lld-core.cpp @@ -9,13 +9,17 @@ #include "lld/Core/Atom.h" #include "lld/Core/LLVM.h" -#include "lld/Core/NativeReader.h" -#include "lld/Core/NativeWriter.h" #include "lld/Core/Pass.h" #include "lld/Core/Resolver.h" -#include "lld/Core/YamlReader.h" -#include "lld/Core/YamlWriter.h" -#include "lld/Reader/Reader.h" +#include "lld/ReaderWriter/Reader.h" +#include "lld/ReaderWriter/ReaderNative.h" +#include "lld/ReaderWriter/ReaderYAML.h" +#include "lld/ReaderWriter/Writer.h" +#include "lld/ReaderWriter/WriterELF.h" +#include "lld/ReaderWriter/WriterMachO.h" +#include "lld/ReaderWriter/WriterNative.h" +#include "lld/ReaderWriter/WriterPECOFF.h" +#include "lld/ReaderWriter/WriterYAML.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Support/CommandLine.h" @@ -29,6 +33,8 @@ #include <vector> +#include "TestingHelpers.hpp" + using namespace lld; static void error(Twine message) { @@ -43,311 +49,6 @@ static bool error(error_code ec) { return false; } -namespace { - - -// -// Simple atom created by the stubs pass. -// -class TestingStubAtom : public DefinedAtom { -public: - TestingStubAtom(const File& f, const Atom& shlib) : - _file(f), _shlib(shlib) { - static uint32_t lastOrdinal = 0; - _ordinal = lastOrdinal++; - } - - virtual const File& file() const { - return _file; - } - - virtual StringRef name() const { - return StringRef(); - } - - virtual uint64_t ordinal() const { - return _ordinal; - } - - virtual uint64_t size() const { - return 0; - } - - virtual Scope scope() const { - return DefinedAtom::scopeLinkageUnit; - } - - virtual Interposable interposable() const { - return DefinedAtom::interposeNo; - } - - virtual Merge merge() const { - return DefinedAtom::mergeNo; - } - - virtual ContentType contentType() const { - return DefinedAtom::typeStub; - } - - virtual Alignment alignment() const { - return Alignment(0,0); - } - - virtual SectionChoice sectionChoice() const { - return DefinedAtom::sectionBasedOnContent; - } - - virtual StringRef customSectionName() const { - return StringRef(); - } - virtual DeadStripKind deadStrip() const { - return DefinedAtom::deadStripNormal; - } - - virtual ContentPermissions permissions() const { - return DefinedAtom::permR_X; - } - - virtual bool isThumb() const { - return false; - } - - virtual bool isAlias() const { - return false; - } - - virtual ArrayRef<uint8_t> rawContent() const { - return ArrayRef<uint8_t>(); - } - - virtual reference_iterator begin() const { - return reference_iterator(*this, nullptr); - } - - virtual reference_iterator end() const { - return reference_iterator(*this, nullptr); - } - - virtual const Reference* derefIterator(const void* iter) const { - return nullptr; - } - - virtual void incrementIterator(const void*& iter) const { - - } - -private: - const File& _file; - const Atom& _shlib; - uint32_t _ordinal; -}; - - - - -// -// Simple atom created by the GOT pass. -// -class TestingGOTAtom : public DefinedAtom { -public: - TestingGOTAtom(const File& f, const Atom& shlib) : - _file(f), _shlib(shlib) { - static uint32_t lastOrdinal = 0; - _ordinal = lastOrdinal++; - } - - virtual const File& file() const { - return _file; - } - - virtual StringRef name() const { - return StringRef(); - } - - virtual uint64_t ordinal() const { - return _ordinal; - } - - virtual uint64_t size() const { - return 0; - } - - virtual Scope scope() const { - return DefinedAtom::scopeLinkageUnit; - } - - virtual Interposable interposable() const { - return DefinedAtom::interposeNo; - } - - virtual Merge merge() const { - return DefinedAtom::mergeNo; - } - - virtual ContentType contentType() const { - return DefinedAtom::typeGOT; - } - - virtual Alignment alignment() const { - return Alignment(3,0); - } - - virtual SectionChoice sectionChoice() const { - return DefinedAtom::sectionBasedOnContent; - } - - virtual StringRef customSectionName() const { - return StringRef(); - } - virtual DeadStripKind deadStrip() const { - return DefinedAtom::deadStripNormal; - } - - virtual ContentPermissions permissions() const { - return DefinedAtom::permRW_; - } - - virtual bool isThumb() const { - return false; - } - - virtual bool isAlias() const { - return false; - } - - virtual ArrayRef<uint8_t> rawContent() const { - return ArrayRef<uint8_t>(); - } - - virtual reference_iterator begin() const { - return reference_iterator(*this, nullptr); - } - - virtual reference_iterator end() const { - return reference_iterator(*this, nullptr); - } - - virtual const Reference* derefIterator(const void* iter) const { - return nullptr; - } - - virtual void incrementIterator(const void*& iter) const { - - } - -private: - const File& _file; - const Atom& _shlib; - uint32_t _ordinal; -}; - -// -// A simple platform for testing. -// -class TestingPlatform : public Platform { -public: - - virtual void addFiles(InputFiles&) { - } - - struct KindMapping { - const char* string; - Reference::Kind value; - bool isBranch; - bool isGotLoad; - bool isGotUse; - }; - - static const KindMapping _s_kindMappings[]; - - virtual Reference::Kind kindFromString(StringRef kindName) { - for (const KindMapping* p = _s_kindMappings; p->string != nullptr; ++p) { - if ( kindName.equals(p->string) ) - return p->value; - } - int k; - if (kindName.getAsInteger(0, k)) - k = 0; - return k; - } - - virtual StringRef kindToString(Reference::Kind value) { - for (const KindMapping* p = _s_kindMappings; p->string != nullptr; ++p) { - if ( value == p->value) - return p->string; - } - return StringRef("???"); - } - - virtual bool noTextRelocs() { - return true; - } - - virtual bool isCallSite(Reference::Kind kind) { - for (const KindMapping* p = _s_kindMappings; p->string != nullptr; ++p) { - if ( kind == p->value ) - return p->isBranch; - } - return false; - } - - virtual bool isGOTAccess(Reference::Kind kind, bool& canBypassGOT) { - for (const KindMapping* p = _s_kindMappings; p->string != nullptr; ++p) { - if ( kind == p->value ) { - canBypassGOT = p->isGotLoad; - return p->isGotUse; - } - } - return false; - } - - virtual void updateReferenceToGOT(const Reference* ref, bool targetIsNowGOT) { - if ( targetIsNowGOT ) - (const_cast<Reference*>(ref))->setKind(kindFromString("pcrel32")); - else - (const_cast<Reference*>(ref))->setKind(kindFromString("lea32wasGot")); - } - - - - virtual const DefinedAtom *getStub(const Atom& shlibAtom, File& file) { - const DefinedAtom *result = new TestingStubAtom(file, shlibAtom); - _stubs.push_back(result); - return result; - } - - virtual const DefinedAtom* makeGOTEntry(const Atom& shlibAtom, File& file) { - return new TestingGOTAtom(file, shlibAtom); - } - - virtual void addStubAtoms(File &file) { - for (const DefinedAtom *stub : _stubs) { - file.addAtom(*stub); - } - } - - virtual void writeExecutable(const lld::File &, raw_ostream &out) { - } -private: - std::vector<const DefinedAtom*> _stubs; -}; - - -// -// Table of fixup kinds in YAML documents used for testing -// -const TestingPlatform::KindMapping TestingPlatform::_s_kindMappings[] = { - { "call32", 1, true, false, false}, - { "pcrel32", 2, false, false, false }, - { "gotLoad32", 3, false, true, true }, - { "gotUse32", 4, false, false, true }, - { "lea32wasGot", 5, false, false, false }, - { nullptr, 0, false, false, false } - }; - - -} // anon namespace - llvm::cl::list<std::string> cmdLineInputFilePaths(llvm::cl::Positional, @@ -383,16 +84,18 @@ cmdLineGlobalsNotDeadStrip("keep-globals", llvm::cl::desc("All global symbols are roots for dead-strip")); -enum PlatformChoice { - platformTesting, platformDarwin +enum WriteChoice { + writeYAML, writeMachO, writePECOFF, writeELF }; -llvm::cl::opt<PlatformChoice> -platformSelected("platform", - llvm::cl::desc("Select platform"), +llvm::cl::opt<WriteChoice> +writeSelected("writer", + llvm::cl::desc("Select writer"), llvm::cl::values( - clEnumValN(platformTesting, "none", "link for testing"), - clEnumValN(platformDarwin, "darwin", "link as darwin would"), + clEnumValN(writeYAML, "YAML", "link assuming YAML format"), + clEnumValN(writeMachO, "mach-o", "link as darwin would"), + clEnumValN(writePECOFF, "PECOFF", "link as windows would"), + clEnumValN(writeELF, "ELF", "link as linux would"), clEnumValEnd)); @@ -410,8 +113,6 @@ public: - - int main(int argc, char *argv[]) { // Print a stack trace if we signal out. llvm::sys::PrintStackTraceOnErrorSignal(); @@ -421,108 +122,97 @@ int main(int argc, char *argv[]) { // parse options llvm::cl::ParseCommandLineOptions(argc, argv); + // if no input file specified, read from stdin if (cmdLineInputFilePaths.empty()) cmdLineInputFilePaths.emplace_back("-"); - // create platform for testing - Platform* platform = nullptr; - switch ( platformSelected ) { - case platformTesting: - platform = new TestingPlatform(); + // if no output path specified, write to stdout + if (cmdLineOutputFilePath.empty()) + cmdLineOutputFilePath.assign("-"); + + // create writer for final output + TestingWriterOptionsYAML writerOptionsYAML(cmdLineDoStubsPass, + cmdLineDoGotPass); + WriterOptionsMachO writerOptionsMachO; + WriterOptionsPECOFF writerOptionsPECOFF; + WriterOptionsELF writerOptionsELF; + Writer* writer = nullptr; + switch ( writeSelected ) { + case writeYAML: + writer = createWriterYAML(writerOptionsYAML); + break; + case writeMachO: + writer = createWriterMachO(writerOptionsMachO); + break; + case writePECOFF: + writer = createWriterPECOFF(writerOptionsPECOFF); break; - case platformDarwin: - platform = createDarwinPlatform(); + case writeELF: + writer = createWriterELF(writerOptionsELF); break; } - // read input YAML doc into object file(s) - std::vector<std::unique_ptr<const File>> files; + // create object to mange input files + InputFiles inputFiles; + + // read input files into in-memory File objects + TestingReaderOptionsYAML readerOptionsYAML; + Reader *reader = createReaderYAML(readerOptionsYAML); for (auto path : cmdLineInputFilePaths) { - OwningPtr<llvm::MemoryBuffer> ofile; - if (error(llvm::MemoryBuffer::getFileOrSTDIN(path, ofile))) + std::vector<std::unique_ptr<File>> files; + if ( error(reader->readFile(path, files)) ) 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; - } + inputFiles.appendFiles(files); } + + // given writer a chance to add files + writer->addFiles(inputFiles); // create options for resolving TestingResolverOptions options; - // create object to mange input files - InputFiles inputFiles; - for (const auto &file : files) { - inputFiles.appendFile(*file); - } - - platform->addFiles(inputFiles); - // merge all atom graphs Resolver resolver(options, inputFiles); resolver.resolve(); + File &mergedMasterFile = resolver.resultFile(); // run passes - if ( cmdLineDoGotPass ) { - GOTPass addGot(resolver.resultFile(), *platform); - addGot.perform(); + if ( GOTPass *pass = writer->gotPass() ) { + pass->perform(mergedMasterFile); } - if ( cmdLineDoStubsPass ) { - StubsPass addStubs(resolver.resultFile(), *platform); - addStubs.perform(); + if ( StubsPass *pass = writer->stubPass() ) { + pass->perform(mergedMasterFile); } - -// yaml::writeObjectText(resolver.resultFile(), *platform, llvm::errs()); + // showing yaml at this stage can help when debugging + const bool dumpIntermediateYAML = false; + if ( dumpIntermediateYAML ) + writer->writeFile(mergedMasterFile, "-"); - // make unique temp .o file to put generated object file - int fd; - SmallString<128> tempPath; - llvm::sys::fs::unique_file("temp%%%%%.o", fd, tempPath); - llvm::raw_fd_ostream binaryOut(fd, /*shouldClose=*/true); + // make unique temp file to put generated native object file + llvm::sys::Path tmpNativePath = llvm::sys::Path::GetTemporaryDirectory(); + if (tmpNativePath.createTemporaryFileOnDisk()) { + error("createTemporaryFileOnDisk() failed"); + return 1; + } - // write native file - writeNativeObjectFile(resolver.resultFile(), binaryOut); - binaryOut.close(); // manually close so that file can be read next - -// out << "native file: " << tempPath.str() << "\n"; + // write as native file + WriterOptionsNative optionsNativeWriter; + Writer *natWriter = createWriterNative(optionsNativeWriter); + if (error(natWriter->writeFile(mergedMasterFile, tmpNativePath.c_str()))) + return 1; - // read native file - std::unique_ptr<lld::File> natFile; - if ( error(parseNativeObjectFileOrSTDIN(tempPath, natFile)) ) + // read as native file + ReaderOptionsNative optionsNativeReader; + Reader *natReader = createReaderNative(optionsNativeReader); + std::vector<std::unique_ptr<File>> readNativeFiles; + if (error(natReader->readFile(tmpNativePath.c_str(), readNativeFiles))) return 1; - - // write new atom graph - std::string errorInfo; - const char* outPath = (cmdLineOutputFilePath.empty() ? "-" - : cmdLineOutputFilePath.c_str()); - llvm::raw_fd_ostream out(outPath, errorInfo); - if ( platformSelected == platformTesting) { - // write atom graph out as YAML doc - yaml::writeObjectText(resolver.resultFile() /* *natFile */, *platform, out); - } - else { - // write atom graph as an executable - platform->writeExecutable(resolver.resultFile() /* *natFile */, out); - // HACK. I don't see any way to set the 'executable' bit on files - // in raw_fd_ostream or in llvm/Support. -#if HAVE_SYS_STAT_H - ::chmod(outPath, 0777); -#endif - } - - // delete temp .o file - bool existed; - llvm::sys::fs::remove(tempPath.str(), existed); + // write new atom graph + const File *parsedNativeFile = readNativeFiles[0].get(); + if (error(writer->writeFile(*parsedNativeFile, cmdLineOutputFilePath))) + return 1; + return 0; } |

