diff options
Diffstat (limited to 'lld')
74 files changed, 2848 insertions, 1705 deletions
diff --git a/lld/docs/README.txt b/lld/docs/README.txt index e50ae59a6c8..eb09a2d2b7e 100644 --- a/lld/docs/README.txt +++ b/lld/docs/README.txt @@ -5,3 +5,8 @@ The lld documentation is written using the Sphinx documentation generator. It is currently tested with Sphinx 1.1.3. We currently use the 'nature' theme and a Beaker inspired structure. + +To rebuild documents into html: + + [/lld/docs]> make html + diff --git a/lld/docs/design.rst b/lld/docs/design.rst index 8c40ee92419..19ea8110d3a 100644 --- a/lld/docs/design.rst +++ b/lld/docs/design.rst @@ -108,13 +108,32 @@ The overall steps in linking are: The Resolving and Passes steps are done purely on the master graph of atoms, so they have no notion of file formats such as mach-o or ELF. + +Input Files +~~~~~~~~~~~ + +Existing developer tools using different file formats for object files. +A goal of lld is to be file format independent. This is done +through a plug-in model for reading object files. The lld::Reader is the base +class for all object file readers. A Reader follows the factory method pattern. +A Reader instantiates an lld::File object (which is a graph of Atoms) from a +given object file (on disk or in-memory). + +Every Reader subclass defines its own "options" class (for instance the mach-o +Reader defines the class ReaderOptionsMachO). This options class is the +one-and-only way to control how the Reader operates when parsing an input file +into an Atom graph. For instance, you may want the Reader to only accept +certain architectures. The options class can be instantiated from command +line options, or it can be subclassed and the ivars programatically set. + + Resolving ~~~~~~~~~ -The resolving step takes all the atoms' graphs from each object file and combines -them into one master object graph. Unfortunately, it is not as simple as -appending the atom list from each file into one big list. There are many cases -where atoms need to be coalesced. That is, two or more atoms need to be +The resolving step takes all the atoms' graphs from each object file and +combines them into one master object graph. Unfortunately, it is not as simple +as appending the atom list from each file into one big list. There are many +cases where atoms need to be coalesced. That is, two or more atoms need to be coalesced into one atom. This is necessary to support: C language "tentative definitions", C++ weak symbols for templates and inlines defined in headers, replacing undefined atoms with actual definition atoms, and for merging copies @@ -189,6 +208,7 @@ each proxy atom needed, and these new atoms are added to the current lld::File object. Next, all the noted call sites to shared library atoms have their References altered to point to the stub atom instead of the shared library atom. + Generate Output File ~~~~~~~~~~~~~~~~~~~~ @@ -196,17 +216,31 @@ Once the passes are done, the output file writer is given current lld::File object. The writer's job is to create the executable content file wrapper and place the content of the atoms into it. -Sometimes the output generator needs access to particular atoms (for instance, -it may need to know which atom is "main" in order to specifiy the entry -point in the executable. The way to do this is to have the platform create -an Atom with a Reference to the required atom(s) and provide this atom -in the initialize set of atoms for the resolver. If a particular symbol name -is required, this arrangment will also cause core linking to fail if the -symbol is not defined (e.g. "main" is undefined). +lld uses a plug-in model for writing output files. All concrete writers (e.g. +ELF, mach-o, etc) are subclasses of the lld::Writer classs. -Sometimes a platform supports lazily created symbols. To support this, the -platform can create a File object which vends no initial atoms, but does -lazily supply atoms by name as needed. +Unlike the Reader class which has just one method to instantiate an lld::File, +the Writer class has multiple methods. The crucial method is to generate the +output file, but there are also methods which allow the Writer to contribute +Atoms to the resolver and specify passes to run. + +An example of contributing +atoms is that if the Writer knows a main executable is being linked and such +an executable requires a specially named entry point (e.g. "_main"), the Writer +can add an UndefinedAtom with that special name to the resolver. This will +cause the resolver to issue an error if that symbol is not defined. + +Sometimes a Writer supports lazily created symbols, such as names for the start +of sections. To support this, the Writer can create a File object which vends +no initial atoms, but does lazily supply atoms by name as needed. + +Every Writer subclass defines its own "options" class (for instance the mach-o +Writer defines the class WriterOptionsMachO). This options class is the +one-and-only way to control how the Writer operates when producing an output +file from an Atom graph. For instance, you may want the Writer to optimize +the output for certain OS versions, or strip local symbols, etc. The options +class can be instantiated from command line options, or it can be subclassed +and the ivars programatically set. lld::File representations @@ -262,6 +296,10 @@ With this model for the native file format, files can be read and turned into the in-memory graph of lld::Atoms with just a few memory allocations. And the format can easily adapt over time to new features. +The binary file format follows the ReaderWriter patterns used in lld. The lld +library comes with the classes: ReaderNative and WriterNative. So, switching +between file formats is as easy as switching which Reader subclass is used. + Textual representations in YAML ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -300,8 +338,12 @@ feature trying to be tested. By writing test cases in the linkers own textual format, we can exactly specify every attribute of every atom and thus target specific linker logic. +The textual/YAML format follows the ReaderWriter patterns used in lld. The lld +library comes with the classes: ReaderYAML and WriterYAML. + + Testing -~~~~~~~ +------- The lld project contains a test suite which is being built up as new code is added to lld. All new lld functionality should have a tests added to the test diff --git a/lld/include/lld/Core/AliasAtom.h b/lld/include/lld/Core/AliasAtom.h deleted file mode 100644 index 22dfca162ec..00000000000 --- a/lld/include/lld/Core/AliasAtom.h +++ /dev/null @@ -1,56 +0,0 @@ -//===- Core/AliasAtom.h - Alias to another Atom ---------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_CORE_ALIAS_ATOM_H_ -#define LLD_CORE_ALIAS_ATOM_H_ - -#include "lld/Core/Atom.h" - -#include "llvm/ADT/StringRef.h" - -namespace lld { - -class AliasAtom : public Atom { -public: - AliasAtom(StringRef nm, const Atom &target, Atom::Scope scope) - : Atom( target.definition() - , Atom::combineNever - , scope - , target.contentType() - , target.sectionChoice() - , target.userVisibleName() - , target.deadStrip() - , target.isThumb() - , true - , target.alignment() - ) - , _name(nm) - , _aliasOf(target) {} - - // overrides of Atom - virtual const File *file() const { - return _aliasOf.file(); - } - - virtual bool translationUnitSource(StringRef &path) const { - return _aliasOf.translationUnitSource(path); - } - - virtual StringRef name() const { - return _name; - } - -private: - const StringRef _name; - const Atom &_aliasOf; -}; - -} // namespace lld - -#endif // LLD_CORE_ALIAS_ATOM_H_ diff --git a/lld/include/lld/Core/ArchiveLibraryFile.h b/lld/include/lld/Core/ArchiveLibraryFile.h index f80b11a5221..fbeb2964838 100644 --- a/lld/include/lld/Core/ArchiveLibraryFile.h +++ b/lld/include/lld/Core/ArchiveLibraryFile.h @@ -26,8 +26,6 @@ namespace lld { /// class ArchiveLibraryFile : public File { public: - ArchiveLibraryFile(StringRef path) : File(path) { - } virtual ~ArchiveLibraryFile() { } @@ -47,6 +45,9 @@ public: /// specified name and return the File object for that member, or nullptr. virtual const File *find(StringRef name, bool dataSymbolOnly) const = 0; +protected: + /// only subclasses of ArchiveLibraryFile can be instantiated + ArchiveLibraryFile(StringRef path) : File(path) { } }; } // namespace lld diff --git a/lld/include/lld/Core/DefinedAtom.h b/lld/include/lld/Core/DefinedAtom.h index 05bbf15e780..b7e269f3559 100644 --- a/lld/include/lld/Core/DefinedAtom.h +++ b/lld/include/lld/Core/DefinedAtom.h @@ -1,4 +1,4 @@ -//===- Core/DefinedAtom.h - The Fundamental Unit of Linking ---------------===// +//===- Core/DefinedAtom.h - An Atom with content --------------------------===// // // The LLVM Linker // diff --git a/lld/include/lld/Core/InputFiles.h b/lld/include/lld/Core/InputFiles.h index f3111f8d16a..c98f0d4d613 100644 --- a/lld/include/lld/Core/InputFiles.h +++ b/lld/include/lld/Core/InputFiles.h @@ -37,12 +37,14 @@ public: InputFiles(); virtual ~InputFiles(); - /// Used by platforms to insert platform specific files. + /// Used by Writers to insert writer specific files. virtual void prependFile(const File&); - /// Used by platforms to insert platform specific files. + /// Used by Writers to insert writer specific files. virtual void appendFile(const File&); + /// Transfers ownership of a vector of Files to this InputFile object. + virtual void appendFiles(std::vector<std::unique_ptr<File>> &files); /// @brief iterates all atoms in initial files virtual void forEachInitialAtom(Handler &) const; diff --git a/lld/include/lld/Core/LLVM.h b/lld/include/lld/Core/LLVM.h index 873dce80ffb..25bd3702ccb 100644 --- a/lld/include/lld/Core/LLVM.h +++ b/lld/include/lld/Core/LLVM.h @@ -23,6 +23,7 @@ namespace llvm { // ADT's. class StringRef; class Twine; + class MemoryBuffer; template<typename T> class ArrayRef; template<class T> class OwningPtr; template<unsigned InternalLen> class SmallString; @@ -55,6 +56,7 @@ namespace lld { // ADT's. using llvm::StringRef; using llvm::Twine; + using llvm::MemoryBuffer; using llvm::ArrayRef; using llvm::OwningPtr; using llvm::SmallString; diff --git a/lld/include/lld/Core/NativeReader.h b/lld/include/lld/Core/NativeReader.h deleted file mode 100644 index 1f17d07d0ef..00000000000 --- a/lld/include/lld/Core/NativeReader.h +++ /dev/null @@ -1,40 +0,0 @@ -//===- Core/NativeReader.h - Reads llvm native object files ---------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_CORE_NATIVE_READER_H_ -#define LLD_CORE_NATIVE_READER_H_ - -#include "lld/Core/File.h" - -#include "llvm/Support/system_error.h" - -#include <memory> -#include <vector> - -namespace llvm { - class MemoryBuffer; - class StringRef; -} - -namespace lld { - /// parseNativeObjectFileOrSTDIN - Open the specified native object file (use - /// stdin if the path is "-") and instantiate into an lld::File object. - error_code parseNativeObjectFileOrSTDIN( StringRef path - , std::unique_ptr<File> &result); - - - /// parseNativeObjectFile - Parse the specified native object file - /// (in a buffer) and instantiate into an lld::File object. - error_code parseNativeObjectFile( std::unique_ptr<llvm::MemoryBuffer> &mb - , StringRef path - , std::unique_ptr<File> &result); - -} // namespace lld - -#endif // LLD_CORE_NATIVE_READER_H_ diff --git a/lld/include/lld/Core/NativeWriter.h b/lld/include/lld/Core/NativeWriter.h deleted file mode 100644 index 80c9fe2aaa2..00000000000 --- a/lld/include/lld/Core/NativeWriter.h +++ /dev/null @@ -1,34 +0,0 @@ -//===- Core/NativeWriter.h - Writes native object file --------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_CORE_NATIVE_WRITER_H_ -#define LLD_CORE_NATIVE_WRITER_H_ - -#include "lld/Core/File.h" - -#include "llvm/Support/raw_ostream.h" - -namespace llvm { - class StringRef; -} - - -namespace lld { - - /// writeNativeObjectFile - writes the lld::File object in native object - /// file format to the specified file path. - int writeNativeObjectFile(const lld::File &, StringRef path); - - /// writeNativeObjectFile - writes the lld::File object in native object - /// file format to the specified stream. - int writeNativeObjectFile(const lld::File &, raw_ostream &); - -} // namespace lld - -#endif // LLD_CORE_NATIVE_WRITER_H_ diff --git a/lld/include/lld/Core/Pass.h b/lld/include/lld/Core/Pass.h index de72b7d1be9..28859f0d3c1 100644 --- a/lld/include/lld/Core/Pass.h +++ b/lld/include/lld/Core/Pass.h @@ -11,11 +11,12 @@ #define LLD_CORE_PASS_H_ #include "lld/Core/Atom.h" -#include "lld/Core/Platform.h" +#include "lld/Core/Reference.h" #include <vector> namespace lld { +class DefinedAtom; /// @@ -34,43 +35,88 @@ namespace lld { class Pass { public: /// Do the actual work of the Pass. - virtual void perform() = 0; + virtual void perform(File& mergedFile) = 0; protected: // Only subclassess can be instantiated. - Pass(File& f, Platform& p) : _file(f), _platform(p) {} - - - File& _file; - Platform& _platform; + Pass() { } }; /// /// Pass for adding stubs (PLT entries) for calls to functions -/// outside the linkage unit. +/// outside the linkage unit. This class is subclassed by each +/// file format Writer which implements the pure virtual methods. /// class StubsPass : public Pass { public: - StubsPass(File& f, Platform& p) : Pass(f, p) {} + StubsPass() : Pass() {} /// Scans all Atoms looking for call-site uses of SharedLibraryAtoms - /// and transfroms the call-site to call a stub instead. - virtual void perform(); + /// and transfroms the call-site to call a stub instead using the + /// helper methods below. + virtual void perform(File& mergedFile); + + /// If true, the pass should use stubs for references + /// to shared library symbols. If false, the pass + /// will generate relocations on the text segment which the + /// runtime loader will use to patch the program at runtime. + virtual bool noTextRelocs() = 0; + + /// Returns whether the Reference kind is for a call site. The pass + /// uses this to find calls that need to be indirected through a stub. + virtual bool isCallSite(Reference::Kind) = 0; + + /// Returns a file format specific atom for a stub/PLT entry which contains + /// instructions which jump to the specified atom. May be called multiple + /// times for the same target atom, in which case this method should return + /// the same stub atom. + virtual const DefinedAtom* getStub(const Atom &target) = 0; + + /// After the default implementation of perform() is done calling getStub(), + /// it will call this method to add all the stub (and support) atoms to the + /// master file object. + virtual void addStubAtoms(File &masterFile) = 0; }; + /// /// Pass for adding GOT entries for pointers to functions/data -/// outside the linkage unit. +/// outside the linkage unit. This class is subclassed by each +/// file format Writer which implements the pure virtual methods. /// class GOTPass : public Pass { public: - GOTPass(File& f, Platform& p) : Pass(f, p) {} + GOTPass() : Pass() {} /// Scans all Atoms looking for pointer to SharedLibraryAtoms - /// and transfroms them to a pointer to a GOT entry. - virtual void perform(); + /// and transfroms them to a pointer to a GOT entry using the + /// helper methods below. + virtual void perform(File& mergedFile); + + /// If true, the pass will use GOT entries for references + /// to shared library symbols. If false, the pass + /// will generate relocations on the text segment which the + /// runtime loader will use to patch the program at runtime. + virtual bool noTextRelocs() = 0; + + /// Returns whether the Reference kind is a pre-instantiated GOT access. + /// The default implementation of perform() uses this to figure out + /// what GOT entries to instantiate. + virtual bool isGOTAccess(Reference::Kind, bool& canBypassGOT) = 0; + + /// The file format Writer needs to alter the reference kind from a + /// pre-instantiated GOT access to an actual access. If targetIsNowGOT is + /// true, the pass has instantiated a GOT atom and altered the reference's + /// target to point to that atom. If targetIsNowGOT is false, the pass + /// determined a GOT entry is not needed because the reference site can + /// directly access the target. + virtual void updateReferenceToGOT(const Reference*, bool targetIsNowGOT) = 0; + + /// Returns a file format specific atom for a GOT entry targeting + /// the specified atom. + virtual const DefinedAtom* makeGOTEntry(const Atom& target) = 0; }; diff --git a/lld/include/lld/Core/Platform.h b/lld/include/lld/Core/Platform.h deleted file mode 100644 index 2b2c8e8b5a2..00000000000 --- a/lld/include/lld/Core/Platform.h +++ /dev/null @@ -1,99 +0,0 @@ -//===- Core/Platform.h - Platform Interface -------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_CORE_PLATFORM_H_ -#define LLD_CORE_PLATFORM_H_ - -#include "lld/Core/Reference.h" -#include "lld/Core/LLVM.h" -#include <vector> - -namespace lld { -class Atom; -class DefinedAtom; -class UndefinedAtom; -class SharedLibraryAtom; -class File; -class InputFiles; - - -/// The Platform class encapsulated plaform specific linking knowledge. -/// -/// Much of what it does is driving by platform specific linker options. -class Platform { -public: - virtual ~Platform(); - - virtual void addFiles(InputFiles&) = 0; - - /// Converts a reference kind string to a in-memory numeric value. - /// For use with parsing YAML encoded object files. - virtual Reference::Kind kindFromString(StringRef) = 0; - - /// Converts an in-memory reference kind value to a string. - /// For use with writing YAML encoded object files. - virtual StringRef kindToString(Reference::Kind) = 0; - - /// If true, the linker will use stubs and GOT entries for - /// references to shared library symbols. If false, the linker - /// will generate relocations on the text segment which the - /// runtime loader will use to patch the program at runtime. - virtual bool noTextRelocs() = 0; - - /// Returns if the Reference kind is for a call site. The "stubs" Pass uses - /// this to find calls that need to be indirected through a stub. - virtual bool isCallSite(Reference::Kind) = 0; - - /// Returns if the Reference kind is a pre-instantiated GOT access. - /// The "got" Pass uses this to figure out what GOT entries to instantiate. - virtual bool isGOTAccess(Reference::Kind, bool& canBypassGOT) = 0; - - /// The platform needs to alter the reference kind from a pre-instantiated - /// GOT access to an actual access. If targetIsNowGOT is true, the "got" - /// Pass has instantiated a GOT atom and altered the reference's target - /// to point to that atom. If targetIsNowGOT is false, the "got" Pass - /// determined a GOT entry is not needed because the reference site can - /// directly access the target. - virtual void updateReferenceToGOT(const Reference*, bool targetIsNowGOT) = 0; - - /// Returns a platform specific atom for a stub/PLT entry which will - /// jump to the specified atom. May be called multiple times for the same - /// target atom, in which case this method should return the same stub - /// atom. The platform needs to maintain a list of all stubs (and - /// associated atoms) it has created for use by addStubAtoms(). - virtual const DefinedAtom* getStub(const Atom &target, File&) = 0; - - /// After the stubs Pass is done calling getStub(), the Pass will call - /// this method to add all the stub (and support) atoms to the master - /// file object. - virtual void addStubAtoms(File &file) = 0; - - /// Create a platform specific GOT atom. - virtual const DefinedAtom* makeGOTEntry(const Atom&, File&) = 0; - - /// Write an executable file from the supplied file object to the - /// supplied stream. - virtual void writeExecutable(const lld::File &, raw_ostream &out) = 0; - -protected: - Platform(); -}; - - - -/// -/// Creates a platform object for linking as done on Darwin (iOS/OSX). -/// -extern Platform *createDarwinPlatform(); - - - -} // namespace lld - -#endif // LLD_CORE_PLATFORM_H_ diff --git a/lld/include/lld/Core/SharedLibraryFile.h b/lld/include/lld/Core/SharedLibraryFile.h index b3cb00c94c7..9d08b0f00c5 100644 --- a/lld/include/lld/Core/SharedLibraryFile.h +++ b/lld/include/lld/Core/SharedLibraryFile.h @@ -22,8 +22,6 @@ namespace lld { /// class SharedLibraryFile : public File { public: - SharedLibraryFile(StringRef path) : File(path) { - } virtual ~SharedLibraryFile() { } @@ -44,7 +42,9 @@ public: /// symbol. Otherwise return nullptr. virtual const SharedLibraryAtom *exports(StringRef name, bool dataSymbolOnly) const; - +protected: + /// only subclasses of SharedLibraryFile can be instantiated + SharedLibraryFile(StringRef path) : File(path) { } }; } // namespace lld diff --git a/lld/include/lld/Core/YamlReader.h b/lld/include/lld/Core/YamlReader.h deleted file mode 100644 index 5a6328c23d5..00000000000 --- a/lld/include/lld/Core/YamlReader.h +++ /dev/null @@ -1,50 +0,0 @@ -//===- Core/YamlReader.h - Reads YAML -------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_CORE_YAML_READER_H_ -#define LLD_CORE_YAML_READER_H_ - -#include "lld/Core/LLVM.h" - -#include "llvm/Support/system_error.h" - -#include <memory> -#include <vector> - -namespace llvm { -class MemoryBuffer; -class StringRef; -} - -namespace lld { - -class Platform; -class File; - -namespace yaml { - - /// parseObjectTextFileOrSTDIN - Open the specified YAML file (use stdin if - /// the path is "-") and parse into lld::File object(s) and append each to - /// the specified vector<File*>. - error_code parseObjectTextFileOrSTDIN( StringRef path - , Platform& - , std::vector< - std::unique_ptr<const File>>&); - - - /// parseObjectText - Parse the specified YAML formatted MemoryBuffer - /// into lld::File object(s) and append each to the specified vector<File*>. - error_code parseObjectText( llvm::MemoryBuffer *mb - , Platform& - , std::vector<std::unique_ptr<const File>>&); - -} // namespace yaml -} // namespace lld - -#endif // LLD_CORE_YAML_READER_H_ diff --git a/lld/include/lld/Core/YamlWriter.h b/lld/include/lld/Core/YamlWriter.h deleted file mode 100644 index 949e11a19da..00000000000 --- a/lld/include/lld/Core/YamlWriter.h +++ /dev/null @@ -1,31 +0,0 @@ -//===- Core/YamlWriter.h - Writes YAML formatted object files -------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_CORE_YAML_WRITER_H_ -#define LLD_CORE_YAML_WRITER_H_ - -#include "lld/Core/LLVM.h" - -#include "llvm/Support/raw_ostream.h" - -namespace lld { - -class Platform; -class File; - -namespace yaml { - - /// writeObjectText - writes the lld::File object as in YAML - /// format to the specified stream. - void writeObjectText(const lld::File &, Platform &, raw_ostream &); - -} // namespace yaml -} // namespace lld - -#endif // LLD_CORE_YAML_WRITER_H_ diff --git a/lld/include/lld/Reader/Reader.h b/lld/include/lld/Reader/Reader.h deleted file mode 100644 index c74615b0bfe..00000000000 --- a/lld/include/lld/Reader/Reader.h +++ /dev/null @@ -1,29 +0,0 @@ -//===- 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 diff --git a/lld/include/lld/ReaderWriter/Reader.h b/lld/include/lld/ReaderWriter/Reader.h new file mode 100644 index 00000000000..8f590bc333b --- /dev/null +++ b/lld/include/lld/ReaderWriter/Reader.h @@ -0,0 +1,74 @@ +//===- ReaderWriter/Reader.h - Abstract File Format Reading Interface -----===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READERWRITER_READER_H_ +#define LLD_READERWRITER_READER_H_ + +#include "lld/Core/LLVM.h" +#include <memory> +#include <vector> + +namespace lld { +class File; + +/// +/// The Reader is an abstract class for reading object files, +/// library files, and executable files. Each file format +/// (e.g. ELF, mach-o, PECOFF, native, etc) have a concrete subclass +/// of Reader. +/// +class Reader { +public: + virtual ~Reader(); + + + /// Parse a file given its file system path and create a File object. + virtual error_code readFile(StringRef path, + std::vector<std::unique_ptr<File>> &result); + + /// Parse a supplied buffer (already filled with the contents of a file) + /// and create a File object. + /// On success, the resulting File object takes ownership of + /// the MemoryBuffer. + virtual error_code parseFile(std::unique_ptr<MemoryBuffer> mb, + std::vector<std::unique_ptr<File>> &result) = 0; + +protected: + // only concrete subclasses can be instantiated + Reader(); +}; + + + +/// +/// The ReaderOptions encapsulates the options used by all Readers. +/// Each file format defines a subclass of ReaderOptions +/// to hold file format specific options. The option objects are the only +/// way to control the behaviour of Readers. +/// +class ReaderOptions { +public: + // Any options common to all file format Readers will go here. + +protected: + // only concrete subclasses can be instantiated + ReaderOptions(); +}; + + + + + +} // namespace lld + +#endif // LLD_READERWRITER_READER_H_ + + + + diff --git a/lld/include/lld/ReaderWriter/ReaderELF.h b/lld/include/lld/ReaderWriter/ReaderELF.h new file mode 100644 index 00000000000..5644b81fa25 --- /dev/null +++ b/lld/include/lld/ReaderWriter/ReaderELF.h @@ -0,0 +1,65 @@ +//===- ReaderWriter/ReaderELF.h - ELF File Format Reading Interface -------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READERWRITER_READER_ELF_H_ +#define LLD_READERWRITER_READER_ELF_H_ + +#include "lld/ReaderWriter/Reader.h" +#include "lld/Core/LLVM.h" + + +namespace lld { + +/// +/// The ReaderOptionsELF class encapsulates options needed +/// to process mach-o files. You can create an ReaderOptionsELF +/// instance from command line arguments or by subclassing and setting the +/// instance variables in the subclass's constructor. +/// +class ReaderOptionsELF : public ReaderOptions { +public: + virtual ~ReaderOptionsELF(); + + /// + /// Creates a Options object from darwin linker command line arguments. + /// FIXME: to be replaced with new option processing mechanism. + /// + ReaderOptionsELF(int argc, const char* argv[]); + + /// + /// Creates a Options object with default settings. For use when + /// programmatically constructing options. + /// + ReaderOptionsELF(); + + + +protected: +}; + + + + +/// +/// The only way to instantiate a ReaderELF object +/// is via this createReaderELF function. The is no public +/// ReaderELF class that you might be tempted to subclass. +/// Support for all variants must be represented in the ReaderOptionsELF +/// object. +/// The Reader object created retains a reference to the +/// ReaderOptionsELF object supplied, so the objects object must not be +/// destroyed before the Reader object. +/// +Reader* createReaderELF(const ReaderOptionsELF &options); + + + +} // namespace lld + +#endif // LLD_READERWRITER_READER_ELF_H_ diff --git a/lld/include/lld/ReaderWriter/ReaderMachO.h b/lld/include/lld/ReaderWriter/ReaderMachO.h new file mode 100644 index 00000000000..669a199b7ab --- /dev/null +++ b/lld/include/lld/ReaderWriter/ReaderMachO.h @@ -0,0 +1,68 @@ +//===- ReaderWriter/ReaderMachO.h - MachO File Format Reading Interface ---===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READER_WRITER_READER_MACHO_H_ +#define LLD_READER_WRITER_READER_MACHO_H_ + +#include "lld/ReaderWriter/Reader.h" +#include "lld/Core/LLVM.h" +#include "llvm/ADT/StringRef.h" + + +namespace lld { + +/// +/// The ReaderOptionsMachO class encapsulates options needed +/// to process mach-o files. You can create an ReaderOptionsMachO +/// instance from command line arguments or by subclassing and setting the +/// instance variables in the subclass's constructor. +/// +class ReaderOptionsMachO : public ReaderOptions { +public: + virtual ~ReaderOptionsMachO() { } + + /// + /// Creates a Options object from darwin linker command line arguments. + /// FIXME: to be replaced with new option processing mechanism. + /// + ReaderOptionsMachO(int argc, const char* argv[]); + + /// + /// Creates a Options object with default settings. For use when + /// programmatically constructing options. + /// + ReaderOptionsMachO(); + + + StringRef archName() const { return _archName; } + +protected: + StringRef _archName; +}; + + + + +/// +/// The only way to instantiate a ReaderMachO object +/// is via this createReaderMachO function. The is no public +/// ReaderMachO class that you might be tempted to subclass. +/// Support for all variants must be represented in the ReaderOptionsMachO +/// object. +/// The Reader object created retains a reference to the +/// ReaderOptionsMachO object supplied, so the objects object must not be +/// destroyed before the Reader object. +/// +Reader* createReaderMachO(const ReaderOptionsMachO &options); + + + +} // namespace lld + +#endif // LLD_READER_WRITER_READER_MACHO_H_ diff --git a/lld/include/lld/ReaderWriter/ReaderNative.h b/lld/include/lld/ReaderWriter/ReaderNative.h new file mode 100644 index 00000000000..21f4415536d --- /dev/null +++ b/lld/include/lld/ReaderWriter/ReaderNative.h @@ -0,0 +1,63 @@ +//===- ReaderWriter/ReaderNative.h - Native File Format Reading Interface ---===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READERWRITER_READER_NATIVE_H_ +#define LLD_READERWRITER_READER_NATIVE_H_ + +#include "lld/ReaderWriter/Reader.h" +#include "lld/Core/LLVM.h" + + +namespace lld { + +/// +/// The ReaderOptionsNative class encapsulates options needed +/// to process mach-o files. You can create an ReaderOptionsNative +/// instance from command line arguments or by subclassing and setting the +/// instance variables in the subclass's constructor. +/// +class ReaderOptionsNative : public ReaderOptions { +public: + virtual ~ReaderOptionsNative(); + + /// + /// Creates a Options object from darwin linker command line arguments. + /// FIXME: to be replaced with new option processing mechanism. + /// + ReaderOptionsNative(int argc, const char* argv[]); + + /// + /// Creates a Options object with default settings. For use when + /// programmatically constructing options. + /// + ReaderOptionsNative(); + +protected: +}; + + + + +/// +/// The only way to instantiate a ReaderNative object +/// is via this createReaderNative function. The is no public +/// ReaderNative class that you might be tempted to subclass. +/// Support for all variants must be represented in the ReaderOptionsNative +/// object. +/// The Reader object created retains a reference to the +/// ReaderOptionsNative object supplied, so the objects object must not be +/// destroyed before the Reader object. +/// +Reader* createReaderNative(const ReaderOptionsNative &options); + + + +} // namespace lld + +#endif // LLD_READERWRITER_READER_NATIVE_H_ diff --git a/lld/include/lld/ReaderWriter/ReaderPECOFF.h b/lld/include/lld/ReaderWriter/ReaderPECOFF.h new file mode 100644 index 00000000000..cb1dc375491 --- /dev/null +++ b/lld/include/lld/ReaderWriter/ReaderPECOFF.h @@ -0,0 +1,64 @@ +//===- ReaderWriter/ReaderPECOFF.h - PECOFF File Format Reading Interface ---===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READERWRITER_READER_PECOFF_H_ +#define LLD_READERWRITER_READER_PECOFF_H_ + +#include "lld/ReaderWriter/Reader.h" +#include "lld/Core/LLVM.h" + + +namespace lld { + +/// +/// The ReaderOptionsPECOFF class encapsulates options needed +/// to process mach-o files. You can create an ReaderOptionsPECOFF +/// instance from command line arguments or by subclassing and setting the +/// instance variables in the subclass's constructor. +/// +class ReaderOptionsPECOFF : public ReaderOptions { +public: + virtual ~ReaderOptionsPECOFF(); + + /// + /// Creates a Options object from darwin linker command line arguments. + /// FIXME: to be replaced with new option processing mechanism. + /// + ReaderOptionsPECOFF(int argc, const char* argv[]); + + /// + /// Creates a Options object with default settings. For use when + /// programmatically constructing options. + /// + ReaderOptionsPECOFF(); + + +protected: +}; + + + + +/// +/// The only way to instantiate a ReaderPECOFF object +/// is via this createReaderPECOFF function. The is no public +/// ReaderPECOFF class that you might be tempted to subclass. +/// Support for all variants must be represented in the ReaderOptionsPECOFF +/// object. +/// The Reader object created retains a reference to the +/// ReaderOptionsPECOFF object supplied, so the objects object must not be +/// destroyed before the Reader object. +/// +Reader* createReaderPECOFF(const ReaderOptionsPECOFF &options); + + + +} // namespace lld + +#endif // LLD_READERWRITER_READER_PECOFF_H_ diff --git a/lld/include/lld/ReaderWriter/ReaderYAML.h b/lld/include/lld/ReaderWriter/ReaderYAML.h new file mode 100644 index 00000000000..c49711f5b7b --- /dev/null +++ b/lld/include/lld/ReaderWriter/ReaderYAML.h @@ -0,0 +1,73 @@ +//===- ReaderWriter/ReaderYAML.h - YAML File Format Reading Interface -----===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READERWRITER_READER_YAML_H_ +#define LLD_READERWRITER_READER_YAML_H_ + +#include "lld/ReaderWriter/Reader.h" +#include "lld/Core/LLVM.h" +#include "lld/Core/Reference.h" +#include "llvm/ADT/StringRef.h" + + +namespace lld { + +/// +/// The ReaderOptionsYAML class encapsulates options needed +/// to process mach-o files. You can create an ReaderOptionsYAML +/// instance from command line arguments or by subclassing and setting the +/// instance variables in the subclass's constructor. +/// +class ReaderOptionsYAML : public ReaderOptions { +public: + virtual ~ReaderOptionsYAML(); + + /// + /// Creates a Options object from darwin linker command line arguments. + /// FIXME: to be replaced with new option processing mechanism. + /// + ReaderOptionsYAML(int argc, const char* argv[]); + + /// + /// Creates a Options object with default settings. For use when + /// programmatically constructing options. + /// + ReaderOptionsYAML(); + + + /// Converts a reference kind string to a in-memory numeric value. + /// Used when parsing YAML encoded object files. + virtual Reference::Kind kindFromString(StringRef) const = 0; + + +protected: +}; + + + + +/// +/// The only way to instantiate a ReaderYAML object +/// is via this createReaderYAML function. The is no public +/// ReaderYAML class that you might be tempted to subclass. +/// Support for all variants must be represented in the ReaderOptionsYAML +/// object. +/// The Reader object created retains a reference to the +/// ReaderOptionsYAML object supplied, so the objects object must not be +/// destroyed before the Reader object. +/// +Reader* createReaderYAML(const ReaderOptionsYAML &options); + + + +} // namespace lld + +#endif // LLD_READERWRITER_READER_YAML_H_ + + diff --git a/lld/include/lld/ReaderWriter/Writer.h b/lld/include/lld/ReaderWriter/Writer.h new file mode 100644 index 00000000000..7165fb6abde --- /dev/null +++ b/lld/include/lld/ReaderWriter/Writer.h @@ -0,0 +1,86 @@ +//===- ReaderWriter/Writer.h - Abstract File Format Interface -------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READERWRITER_WRITER_H_ +#define LLD_READERWRITER_WRITER_H_ + +#include "lld/Core/LLVM.h" +#include <memory> +#include <vector> + +namespace lld { +class File; +class InputFiles; +class StubsPass; +class GOTPass; + + +/// +/// The Writer is an abstract class for writing object files, +/// shared library files, and executable files. Each file format +/// (e.g. ELF, mach-o, PECOFF, native, etc) have a concrete subclass +/// of Writer. +/// +class Writer { +public: + virtual ~Writer(); + + /// Write a file from the supplied File object + virtual error_code writeFile(const lld::File &linkedFile, StringRef path) = 0; + + /// Return a Pass object for creating stubs/PLT entries + virtual StubsPass *stubPass() { + return nullptr; + } + + /// Return a Pass object for creating GOT entries + virtual GOTPass *gotPass() { + return nullptr; + } + + /// This method is called by Core Linking to give the Writer a chance to + /// add file format specific "files" to set of files to be linked. + /// This is how file format specific atoms can be added to the link. + virtual void addFiles(InputFiles&) { + } + + +protected: + // only concrete subclasses can be instantiated + Writer(); +}; + + + +/// +/// The WriterOptions encapsulates the options used by Writers. +/// Each file format defines a subclass of WriterOptions +/// to hold file format specific options. The option objects are the only +/// way to control the behaviour of Writers. +/// +class WriterOptions { +public: + // Any options common to all file formats will go here. + +protected: + // only concrete subclasses can be instantiated + WriterOptions(); +}; + + + + + +} // namespace lld + +#endif // LLD_READERWRITER_WRITER_H_ + + + + diff --git a/lld/include/lld/ReaderWriter/WriterELF.h b/lld/include/lld/ReaderWriter/WriterELF.h new file mode 100644 index 00000000000..6a182de4912 --- /dev/null +++ b/lld/include/lld/ReaderWriter/WriterELF.h @@ -0,0 +1,64 @@ +//===- ReaderWriter/WriterELF.h - ELF File Format Writing Interface -------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READERWRITER_WRITER_ELF_H_ +#define LLD_READERWRITER_WRITER_ELF_H_ + +#include "lld/ReaderWriter/Writer.h" +#include "lld/Core/LLVM.h" +#include "llvm/ADT/StringRef.h" + + +namespace lld { + +/// +/// The WriterOptionsELF class encapsulates options needed +/// to process mach-o files. You can create an WriterOptionsELF +/// instance from command line arguments or by subclassing and setting the +/// instance variables in the subclass's constructor. +/// +class WriterOptionsELF : public WriterOptions { +public: + virtual ~WriterOptionsELF(); + + /// + /// Creates a Options object from darwin linker command line arguments. + /// FIXME: to be replaced with new option processing mechanism. + /// + WriterOptionsELF(int argc, const char* argv[]); + + /// + /// Creates a Options object with default settings. For use when + /// programmatically constructing options. + /// + WriterOptionsELF(); + +protected: +}; + + + + +/// +/// The only way to instantiate a WriterELF object +/// is via this createWriterELF function. The is no public +/// WriterELF class that you might be tempted to subclass. +/// Support for all variants must be represented in the WriterOptionsELF +/// object. +/// The Writer object created retains a reference to the +/// WriterOptionsELF object supplied, so it must not be destroyed +/// before the Writer object. +/// +Writer* createWriterELF(const WriterOptionsELF &options); + + + +} // namespace lld + +#endif // LLD_READERWRITER_WRITER_ELF_H_ diff --git a/lld/include/lld/ReaderWriter/WriterMachO.h b/lld/include/lld/ReaderWriter/WriterMachO.h new file mode 100644 index 00000000000..b1a84137c5a --- /dev/null +++ b/lld/include/lld/ReaderWriter/WriterMachO.h @@ -0,0 +1,109 @@ +//===- ReaderWriter/WriterMachO.h - MachO File Format Reading Interface ---===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READERWRITER_WRITER_MACHO_H_ +#define LLD_READERWRITER_WRITER_MACHO_H_ + +#include "lld/ReaderWriter/Writer.h" +#include "lld/Core/LLVM.h" +#include "llvm/ADT/StringRef.h" + + +namespace lld { + +/// +/// The WriterOptionsMachO class encapsulates options needed +/// to process mach-o files. You can create an WriterOptionsMachO +/// instance from command line arguments or by subclassing and setting the +/// instance variables in the subclass's constructor. +/// +class WriterOptionsMachO : public WriterOptions { +public: + virtual ~WriterOptionsMachO(); + + /// + /// Creates a Options object from darwin linker command line arguments. + /// FIXME: to be replaced with new option processing mechanism. + /// + WriterOptionsMachO(int argc, const char* argv[]); + + /// + /// Creates a Options object with default settings. For use when + /// programmatically constructing options. + /// + WriterOptionsMachO(); + + + + enum OutputKind { + outputDynamicExecutable, + outputDylib, + outputBundle, + outputObjectFile + }; + + enum Architecture { + arch_x86_64, + arch_x86, + arch_arm, + }; + + OutputKind outputKind() const { return _outputkind; } + Architecture architecture() const { return _architecture; } + StringRef archName() const { return _archName; } + uint64_t pageZeroSize() const { return _pageZeroSize; } + uint32_t cpuType() const { return _cpuType; } + uint32_t cpuSubtype() const { return _cpuSubtype; } + bool noTextRelocations() const { return _noTextRelocations; } + +protected: + OutputKind _outputkind; + StringRef _archName; + Architecture _architecture; + uint64_t _pageZeroSize; + uint32_t _cpuType; + uint32_t _cpuSubtype; + bool _noTextRelocations; +}; + + + + +/// +/// The only way to instantiate a WriterMachO object +/// is via this createWriterMachO function. The is no public +/// WriterMachO class that you might be tempted to subclass. +/// Support for all variants must be represented in the +/// WriterOptionsMachO object. +/// The Writer object created retains a reference to the +/// WriterOptionsMachO object supplied, so it must not be destroyed +/// before the Writer object. +/// +Writer* createWriterMachO(const WriterOptionsMachO &options); + + +/// +/// Returns an options object that can be used with the +/// WriterYAML to write mach-o object files as YAML. +/// +const class WriterOptionsYAML& writerOptionsMachOAsYAML(); + + +/// +/// Returns an options object that can be used with the +/// ReaderYAML to reader YAML encoded mach-o files. +/// +const class ReaderOptionsYAML& readerOptionsMachOAsYAML(); + + + + +} // namespace lld + +#endif // LLD_READERWRITER_WRITER_MACHO_H_ diff --git a/lld/include/lld/ReaderWriter/WriterNative.h b/lld/include/lld/ReaderWriter/WriterNative.h new file mode 100644 index 00000000000..fdc99cf28a5 --- /dev/null +++ b/lld/include/lld/ReaderWriter/WriterNative.h @@ -0,0 +1,63 @@ +//===- ReaderWriter/WriterNative.h - Native File Format Reading Interface ---===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READERWRITER_WRITER_NATIVE_H_ +#define LLD_READERWRITER_WRITER_NATIVE_H_ + +#include "lld/ReaderWriter/Writer.h" +#include "lld/Core/LLVM.h" + + +namespace lld { + +/// +/// The WriterOptionsNative class encapsulates options needed +/// to process mach-o files. You can create an WriterOptionsNative +/// instance from command line arguments or by subclassing and setting the +/// instance variables in the subclass's constructor. +/// +class WriterOptionsNative : public WriterOptions { +public: + virtual ~WriterOptionsNative(); + + /// + /// Creates a Options object from darwin linker command line arguments. + /// FIXME: to be replaced with new option processing mechanism. + /// + WriterOptionsNative(int argc, const char* argv[]); + + /// + /// Creates a Options object with default settings. For use when + /// programmatically constructing options. + /// + WriterOptionsNative(); + +protected: +}; + + + + +/// +/// The only way to instantiate a WriterNative object +/// is via this createWriterNative function. The is no public +/// WriterNative class that you might be tempted to subclass. +/// Support for all variants must be represented in the WriterOptionsNative +/// object. +/// The Writer object created retains a reference to the +/// WriterOptionsNative object supplied, so it must not be destroyed +/// before the Writer object. +/// +Writer* createWriterNative(const WriterOptionsNative &options); + + + +} // namespace lld + +#endif // LLD_READERWRITER_WRITER_NATIVE_H_ diff --git a/lld/include/lld/ReaderWriter/WriterPECOFF.h b/lld/include/lld/ReaderWriter/WriterPECOFF.h new file mode 100644 index 00000000000..740190729e0 --- /dev/null +++ b/lld/include/lld/ReaderWriter/WriterPECOFF.h @@ -0,0 +1,63 @@ +//===- ReaderWriter/WriterPECOFF.h - PECOFF File Format Writing Interface -===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READERWRITER_WRITER_PECOFF_H_ +#define LLD_READERWRITER_WRITER_PECOFF_H_ + +#include "lld/ReaderWriter/Writer.h" +#include "lld/Core/LLVM.h" +#include "llvm/ADT/StringRef.h" + + +namespace lld { + +/// +/// The WriterOptionsPECOFF class encapsulates options needed +/// to process mach-o files. You can create an WriterOptionsPECOFF +/// instance from command line arguments or by subclassing and setting the +/// instance variables in the subclass's constructor. +/// +class WriterOptionsPECOFF : public WriterOptions { +public: + virtual ~WriterOptionsPECOFF(); + + /// + /// Creates a Options object from darwin linker command line arguments. + /// FIXME: to be replaced with new option processing mechanism. + /// + WriterOptionsPECOFF(int argc, const char* argv[]); + + /// + /// Creates a Options object with default settings. For use when + /// programmatically constructing options. + /// + WriterOptionsPECOFF(); + +protected: +}; + + + +/// +/// The only way to instantiate a WriterPECOFF object +/// is via this createWriterPECOFF function. The is no public +/// WriterPECOFF class that you might be tempted to subclass. +/// Support for all variants must be represented in the WriterOptionsPECOFF +/// object. +/// The Writer object created retains a reference to the +/// WriterOptionsPECOFF object supplied, so it must not be destroyed +/// before the Writer object. +/// +Writer* createWriterPECOFF(const WriterOptionsPECOFF &options); + + + +} // namespace lld + +#endif // LLD_READERWRITER_WRITER_PECOFF_H_ diff --git a/lld/include/lld/ReaderWriter/WriterYAML.h b/lld/include/lld/ReaderWriter/WriterYAML.h new file mode 100644 index 00000000000..26dfbb852c5 --- /dev/null +++ b/lld/include/lld/ReaderWriter/WriterYAML.h @@ -0,0 +1,82 @@ +//===- ReaderWriter/WriterYAML.h - YAML File Format Writing Interface -----===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READERWRITER_WRITER_YAML_H_ +#define LLD_READERWRITER_WRITER_YAML_H_ + +#include "lld/ReaderWriter/Writer.h" + +#include "lld/Core/LLVM.h" +#include "lld/Core/Reference.h" +#include "lld/Core/Pass.h" + +#include "llvm/ADT/StringRef.h" + + +namespace lld { + +/// +/// The WriterOptionsYAML class encapsulates options needed +/// to process mach-o files. You can create an WriterOptionsYAML +/// instance from command line arguments or by subclassing and setting the +/// instance variables in the subclass's constructor. +/// +class WriterOptionsYAML : public WriterOptions { +public: + virtual ~WriterOptionsYAML(); + + /// + /// Creates a Options object from darwin linker command line arguments. + /// FIXME: to be replaced with new option processing mechanism. + /// + WriterOptionsYAML(int argc, const char* argv[]); + + /// + /// Creates a Options object with default settings. For use when + /// programmatically constructing options. + /// + WriterOptionsYAML(); + + + /// Converts an in-memory reference kind value to a string. + /// Used when writing YAML encoded object files. + virtual StringRef kindToString(Reference::Kind) const = 0; + + + /// Enable Stubs pass to be run + virtual StubsPass *stubPass() const { + return nullptr; + } + + /// Enable GOT pass to be run + virtual GOTPass *gotPass() const { + return nullptr; + } + +}; + + + + +/// +/// The only way to instantiate a WriterYAML object +/// is via this createWriterYAML function. The is no public +/// WriterYAML class that you might be tempted to subclass. +/// Support for all variants must be represented in the WriterOptionsYAML +/// object. +/// The Writer object created retains a reference to the +/// WriterOptionsYAML object supplied, so it must not be destroyed +/// before the Writer object. +/// +Writer* createWriterYAML(const WriterOptionsYAML &options); + + +} // namespace lld + +#endif // LLD_READERWRITER_WRITER_YAML_H_ diff --git a/lld/lib/CMakeLists.txt b/lld/lib/CMakeLists.txt index 2ce187cf1d6..6a0bf989e0a 100644 --- a/lld/lib/CMakeLists.txt +++ b/lld/lib/CMakeLists.txt @@ -1,4 +1,3 @@ add_subdirectory(Core) add_subdirectory(Passes) -add_subdirectory(Platforms) -add_subdirectory(Reader) +add_subdirectory(ReaderWriter) diff --git a/lld/lib/Core/CMakeLists.txt b/lld/lib/Core/CMakeLists.txt index 076d3351504..1a38b39d2a3 100644 --- a/lld/lib/Core/CMakeLists.txt +++ b/lld/lib/Core/CMakeLists.txt @@ -2,14 +2,6 @@ add_lld_library(lldCore Error.cpp File.cpp InputFiles.cpp - NativeFileFormat.h - NativeReader.cpp - NativeWriter.cpp - Platform.cpp Resolver.cpp SymbolTable.cpp - YamlKeyValues.cpp - YamlKeyValues.h - YamlReader.cpp - YamlWriter.cpp ) diff --git a/lld/lib/Core/InputFiles.cpp b/lld/lib/Core/InputFiles.cpp index e9a423d9a30..78c8405c5ed 100644 --- a/lld/lib/Core/InputFiles.cpp +++ b/lld/lib/Core/InputFiles.cpp @@ -35,6 +35,12 @@ void InputFiles::appendFile(const File &file) { _files.push_back(&file); } +void InputFiles::appendFiles(std::vector<std::unique_ptr<File>> &files) { + for (std::unique_ptr<File> &f : files) { + _files.push_back(f.release()); + } +} + bool InputFiles::searchLibraries(StringRef name, bool searchSharedLibs, bool searchArchives, bool dataSymbolOnly, diff --git a/lld/lib/Core/Resolver.cpp b/lld/lib/Core/Resolver.cpp index f16a67a94fe..d50a772fed3 100644 --- a/lld/lib/Core/Resolver.cpp +++ b/lld/lib/Core/Resolver.cpp @@ -7,15 +7,17 @@ // //===----------------------------------------------------------------------===// -#include "lld/Core/LLVM.h" -#include "lld/Core/Resolver.h" #include "lld/Core/Atom.h" #include "lld/Core/File.h" +#include "lld/Core/LLVM.h" #include "lld/Core/InputFiles.h" #include "lld/Core/LLVM.h" +#include "lld/Core/Resolver.h" #include "lld/Core/SymbolTable.h" #include "lld/Core/UndefinedAtom.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/ErrorHandling.h" @@ -65,6 +67,8 @@ private: // add all atoms from all initial .o files void Resolver::buildInitialAtomList() { + DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "Resolver initial atom list:\n"); + // each input files contributes initial atoms _atoms.reserve(1024); _inputFiles.forEachInitialAtom(*this); @@ -79,7 +83,14 @@ void Resolver::doFile(const File &file) { void Resolver::doUndefinedAtom(const class UndefinedAtom& atom) { - // add to list of known atoms + DEBUG_WITH_TYPE("resolver", llvm::dbgs() + << " UndefinedAtom: " + << llvm::format("0x%09lX", &atom) + << ", name=" + << atom.name() + << "\n"); + + // add to list of known atoms _atoms.push_back(&atom); // tell symbol table @@ -89,6 +100,13 @@ void Resolver::doUndefinedAtom(const class UndefinedAtom& atom) { // called on each atom when a file is added void Resolver::doDefinedAtom(const DefinedAtom &atom) { + DEBUG_WITH_TYPE("resolver", llvm::dbgs() + << " DefinedAtom: " + << llvm::format("0x%09lX", &atom) + << ", name=" + << atom.name() + << "\n"); + // add to list of known atoms _atoms.push_back(&atom); @@ -97,7 +115,7 @@ void Resolver::doDefinedAtom(const DefinedAtom &atom) { // tell symbol table about non-static atoms _symbolTable.add(atom); } - + if (_options.deadCodeStripping()) { // add to set of dead-strip-roots, all symbols that // the compiler marks as don't strip @@ -107,6 +125,13 @@ void Resolver::doDefinedAtom(const DefinedAtom &atom) { } void Resolver::doSharedLibraryAtom(const SharedLibraryAtom& atom) { + DEBUG_WITH_TYPE("resolver", llvm::dbgs() + << " SharedLibraryAtom: " + << llvm::format("0x%09lX", &atom) + << ", name=" + << atom.name() + << "\n"); + // add to list of known atoms _atoms.push_back(&atom); @@ -115,6 +140,13 @@ void Resolver::doSharedLibraryAtom(const SharedLibraryAtom& atom) { } void Resolver::doAbsoluteAtom(const AbsoluteAtom& atom) { + DEBUG_WITH_TYPE("resolver", llvm::dbgs() + << " AbsoluteAtom: " + << llvm::format("0x%09lX", &atom) + << ", name=" + << atom.name() + << "\n"); + // add to list of known atoms _atoms.push_back(&atom); @@ -159,7 +191,7 @@ void Resolver::resolveUndefines() { _symbolTable.tentativeDefinitions(tentDefNames); for ( StringRef tentDefName : tentDefNames ) { // Load for previous tentative may also have loaded - // something that overrode this tentative, so always check. + // something that overrode this tentative, so always check. const Atom *curAtom = _symbolTable.findByName(tentDefName); assert(curAtom != nullptr); if (const DefinedAtom* curDefAtom = dyn_cast<DefinedAtom>(curAtom)) { @@ -228,7 +260,7 @@ void Resolver::deadStripOptimize() { _deadStripRoots.insert(defAtom); } } - + // Or, use list of names that are dead stip roots. const std::vector<StringRef> &names = _options.deadStripRootNames(); for ( const StringRef &name : names ) { @@ -332,7 +364,13 @@ void Resolver::MergedFile::addAtom(const Atom& atom) { } void Resolver::MergedFile::addAtoms(std::vector<const Atom*>& all) { + DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "Resolver final atom list:\n"); for ( const Atom *atom : all ) { + DEBUG_WITH_TYPE("resolver", llvm::dbgs() + << llvm::format(" 0x%09lX", atom) + << ", name=" + << atom->name() + << "\n"); this->addAtom(*atom); } } diff --git a/lld/lib/Core/SymbolTable.cpp b/lld/lib/Core/SymbolTable.cpp index 0bfe6da6a78..8707fbeb421 100644 --- a/lld/lib/Core/SymbolTable.cpp +++ b/lld/lib/Core/SymbolTable.cpp @@ -173,7 +173,7 @@ void SymbolTable::addByName(const Atom & newAtom) { else { if ( _options.warnIfCoalesableAtomsHaveDifferentCanBeNull() ) { // FIXME: need diagonstics interface for writing warning messages - llvm::errs() << "lld warning: undefined symbol " + llvm::errs() << "lld warning: undefined symbol " << existingUndef->name() << " has different weakness in " << existingUndef->file().path() @@ -198,7 +198,7 @@ void SymbolTable::addByName(const Atom & newAtom) { useNew = false; if ( _options.warnIfCoalesableAtomsHaveDifferentLoadName() ) { // FIXME: need diagonstics interface for writing warning messages - llvm::errs() << "lld warning: shared library symbol " + llvm::errs() << "lld warning: shared library symbol " << curShLib->name() << " has different load path in " << curShLib->file().path() @@ -210,7 +210,7 @@ void SymbolTable::addByName(const Atom & newAtom) { useNew = false; if ( _options.warnIfCoalesableAtomsHaveDifferentCanBeNull() ) { // FIXME: need diagonstics interface for writing warning messages - llvm::errs() << "lld warning: shared library symbol " + llvm::errs() << "lld warning: shared library symbol " << curShLib->name() << " has different weakness in " << curShLib->file().path() diff --git a/lld/lib/Passes/GOTPass.cpp b/lld/lib/Passes/GOTPass.cpp index 9bbd08a2b1e..52b70e3c356 100644 --- a/lld/lib/Passes/GOTPass.cpp +++ b/lld/lib/Passes/GOTPass.cpp @@ -24,9 +24,9 @@ // is in the same linkage unit and does not need to be interposable, and // the GOT use is just a load (not some other operation), this pass can // transform that load into an LEA (add). This optimizes away one memory load -// at runtime that could stall the pipeline. This optimization only works +// which at runtime that could stall the pipeline. This optimization only works // for architectures in which a (GOT) load instruction can be change to an -// LEA instruction that is the same size. The platform method isGOTAccess() +// LEA instruction that is the same size. The method isGOTAccess() // should only return true for "canBypassGOT" if this optimization is supported. // //===----------------------------------------------------------------------===// @@ -35,23 +35,21 @@ #include "lld/Core/File.h" #include "lld/Core/LLVM.h" #include "lld/Core/Pass.h" -#include "lld/Core/Platform.h" #include "lld/Core/Reference.h" - #include "llvm/ADT/DenseMap.h" namespace lld { -void GOTPass::perform() { +void GOTPass::perform(File& mergedFile) { // Use map so all pointers to same symbol use same GOT entry. llvm::DenseMap<const Atom*, const DefinedAtom*> targetToGOT; // Scan all references in all atoms. - for(const DefinedAtom *atom : _file.defined()) { + for(const DefinedAtom *atom : mergedFile.defined()) { for (const Reference *ref : *atom) { // Look at instructions accessing the GOT. bool canBypassGOT; - if ( _platform.isGOTAccess(ref->kind(), canBypassGOT) ) { + if ( this->isGOTAccess(ref->kind(), canBypassGOT) ) { const Atom* target = ref->target(); assert(target != nullptr); const DefinedAtom* defTarget = dyn_cast<DefinedAtom>(target); @@ -72,14 +70,14 @@ void GOTPass::perform() { // GOT to be by-passed, do that optimization and don't create // GOT entry. replaceTargetWithGOTAtom = !canBypassGOT; - } + } if ( replaceTargetWithGOTAtom ) { // Replace the target with a reference to a GOT entry. const DefinedAtom* gotEntry = nullptr; auto pos = targetToGOT.find(target); if ( pos == targetToGOT.end() ) { // This is no existing GOT entry. Create a new one. - gotEntry = _platform.makeGOTEntry(*target, _file); + gotEntry = this->makeGOTEntry(*target); assert(gotEntry != nullptr); assert(gotEntry->contentType() == DefinedAtom::typeGOT); targetToGOT[target] = gotEntry; @@ -92,16 +90,16 @@ void GOTPass::perform() { // Switch reference to GOT atom. (const_cast<Reference*>(ref))->setTarget(gotEntry); } - // Platform needs to update reference kind to reflect - // that target is a GOT entry or a direct accesss. - _platform.updateReferenceToGOT(ref, replaceTargetWithGOTAtom); + // Update reference kind to reflect + // that target is now a GOT entry or a direct accesss. + this->updateReferenceToGOT(ref, replaceTargetWithGOTAtom); } } } // add all created GOT Atoms to master file for (auto it=targetToGOT.begin(), end=targetToGOT.end(); it != end; ++it) { - _file.addAtom(*it->second); + mergedFile.addAtom(*it->second); } diff --git a/lld/lib/Passes/StubsPass.cpp b/lld/lib/Passes/StubsPass.cpp index b81d0a27a39..c468959d2cc 100644 --- a/lld/lib/Passes/StubsPass.cpp +++ b/lld/lib/Passes/StubsPass.cpp @@ -7,10 +7,10 @@ // //===----------------------------------------------------------------------===// // -// This linker pass updates call sites which have references to shared library +// This linker pass updates call-sites which have references to shared library // atoms to instead have a reference to a stub (PLT entry) for the specified -// symbol. The platform object does the work of creating the platform-specific -// StubAtom. +// symbol. Each file format defines a subclass of StubsPass which implements +// the abstract methods for creating the file format specific StubAtoms. // //===----------------------------------------------------------------------===// @@ -18,30 +18,28 @@ #include "lld/Core/File.h" #include "lld/Core/LLVM.h" #include "lld/Core/Pass.h" -#include "lld/Core/Platform.h" #include "lld/Core/Reference.h" - #include "llvm/ADT/DenseMap.h" namespace lld { -void StubsPass::perform() { +void StubsPass::perform(File& mergedFile) { // Skip this pass if output format uses text relocations instead of stubs. - if ( !_platform.noTextRelocs() ) + if ( ! this->noTextRelocs() ) return; // Scan all references in all atoms. - for(const DefinedAtom *atom : _file.defined()) { + for(const DefinedAtom *atom : mergedFile.defined()) { for (const Reference *ref : *atom) { // Look at call-sites. - if ( _platform.isCallSite(ref->kind()) ) { + if (this->isCallSite(ref->kind()) ) { const Atom* target = ref->target(); assert(target != nullptr); bool replaceCalleeWithStub = false; if ( target->definition() == Atom::definitionSharedLibrary ) { // Calls to shared libraries go through stubs. replaceCalleeWithStub = true; - } + } else if (const DefinedAtom* defTarget = dyn_cast<DefinedAtom>(target)) { if ( defTarget->interposable() != DefinedAtom::interposeNo ) { @@ -52,8 +50,8 @@ void StubsPass::perform() { } } if ( replaceCalleeWithStub ) { - // Ask platform to make stub and other support atoms. - const DefinedAtom* stub = _platform.getStub(*target, _file); + // Make file-format specific stub and other support atoms. + const DefinedAtom* stub = this->getStub(*target); assert(stub != nullptr); // Switch call site to reference stub atom instead. (const_cast<Reference*>(ref))->setTarget(stub); @@ -62,8 +60,8 @@ void StubsPass::perform() { } } - // Tell platform to add all created stubs and support Atoms to file. - _platform.addStubAtoms(_file); + // Add all created stubs and support Atoms. + this->addStubAtoms(mergedFile); } diff --git a/lld/lib/Platforms/CMakeLists.txt b/lld/lib/Platforms/CMakeLists.txt deleted file mode 100644 index 6bb912c33a2..00000000000 --- a/lld/lib/Platforms/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -add_subdirectory(Darwin) diff --git a/lld/lib/Platforms/Darwin/CMakeLists.txt b/lld/lib/Platforms/Darwin/CMakeLists.txt deleted file mode 100644 index 99dafc1cc83..00000000000 --- a/lld/lib/Platforms/Darwin/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -add_lld_library(lldDarwinPlatform - DarwinPlatform.cpp - DarwinReferenceKinds.cpp - ExecutableWriter.cpp - ) diff --git a/lld/lib/Platforms/Darwin/DarwinPlatform.cpp b/lld/lib/Platforms/Darwin/DarwinPlatform.cpp deleted file mode 100644 index 3fdc039095a..00000000000 --- a/lld/lib/Platforms/Darwin/DarwinPlatform.cpp +++ /dev/null @@ -1,180 +0,0 @@ -//===- Platforms/Darwin/DarwinPlatform.cpp --------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "DarwinPlatform.h" -#include "MachOFormat.hpp" -#include "StubAtoms.hpp" -#include "ExecutableAtoms.hpp" -#include "DarwinReferenceKinds.h" -#include "ExecutableWriter.h" - -#include "lld/Core/DefinedAtom.h" -#include "lld/Core/File.h" -#include "lld/Core/Reference.h" -#include "lld/Core/InputFiles.h" - -#include "llvm/Support/ErrorHandling.h" - -namespace lld { - -Platform *createDarwinPlatform() { - return new darwin::DarwinPlatform(); -} - - -namespace darwin { - -DarwinPlatform::DarwinPlatform() - : _helperCommonAtom(nullptr), _cRuntimeFile(nullptr) { -} - -void DarwinPlatform::addFiles(InputFiles &inputFiles) { - _cRuntimeFile = new CRuntimeFile(); - inputFiles.prependFile(*_cRuntimeFile); -} - -Reference::Kind DarwinPlatform::kindFromString(StringRef kindName) { - return ReferenceKind::fromString(kindName); -} - - -StringRef DarwinPlatform::kindToString(Reference::Kind kindValue) { - return ReferenceKind::toString(kindValue); -} - -bool DarwinPlatform::noTextRelocs() { - return true; -} - - -bool DarwinPlatform::isCallSite(Reference::Kind kind) { - return ReferenceKind::isCallSite(kind); -} - - -bool DarwinPlatform::isGOTAccess(Reference::Kind, bool& canBypassGOT) { - return false; -} - - -void DarwinPlatform::updateReferenceToGOT(const Reference*, bool nowGOT) { -} - - -const DefinedAtom* DarwinPlatform::getStub(const Atom& target, File& file) { - auto pos = _targetToStub.find(&target); - if ( pos != _targetToStub.end() ) { - // Reuse an existing stub. - assert(pos->second != nullptr); - return pos->second; - } - else { - // There is no existing stub, so create a new one. - if ( _helperCommonAtom == nullptr ) { - // Lazily create common helper code and data. - _helperCacheAtom = new X86_64NonLazyPointerAtom(file); - _stubBinderAtom = new StubBinderAtom(file); - _helperBinderAtom = new X86_64NonLazyPointerAtom(file, *_stubBinderAtom); - _helperCommonAtom = new X86_64StubHelperCommonAtom(file, - *_helperCacheAtom, *_helperBinderAtom); - } - const DefinedAtom* helper = new X86_64StubHelperAtom(file, - *_helperCommonAtom); - _stubHelperAtoms.push_back(helper); - const DefinedAtom* lp = new X86_64LazyPointerAtom(file, *helper, target); - assert(lp->contentType() == DefinedAtom::typeLazyPointer); - const DefinedAtom* stub = new X86_64StubAtom(file, *lp); - assert(stub->contentType() == DefinedAtom::typeStub); - _targetToStub[&target] = stub; - _lazyPointers.push_back(lp); - return stub; - } -} - - -void DarwinPlatform::addStubAtoms(File &file) { - // Add all stubs to master file. - for (auto it=_targetToStub.begin(), end=_targetToStub.end(); it != end; ++it) { - file.addAtom(*it->second); - } - // Add helper code atoms. - file.addAtom(*_helperCommonAtom); - for (const DefinedAtom *lp : _stubHelperAtoms) { - file.addAtom(*lp); - } - // Add GOT slots used for lazy binding. - file.addAtom(*_helperBinderAtom); - file.addAtom(*_helperCacheAtom); - // Add all lazy pointers to master file. - for (const DefinedAtom *lp : _lazyPointers) { - file.addAtom(*lp); - } - // Add sharedlibrary atom - file.addAtom(*_stubBinderAtom); -} - - -const DefinedAtom* DarwinPlatform::makeGOTEntry(const Atom&, File&) { - return nullptr; -} - -void DarwinPlatform::applyFixup(Reference::Kind kind, uint64_t addend, - uint8_t* location, uint64_t fixupAddress, - uint64_t targetAddress) { - //fprintf(stderr, "applyFixup(kind=%s, addend=0x%0llX, " - // "fixupAddress=0x%0llX, targetAddress=0x%0llX\n", - // kindToString(kind).data(), addend, - // fixupAddress, targetAddress); - if ( ReferenceKind::isRipRel32(kind) ) { - // compute rip relative value and update. - int32_t* loc32 = reinterpret_cast<int32_t*>(location); - *loc32 = (targetAddress - (fixupAddress+4)) + addend; - } - else if ( kind == ReferenceKind::pointer64 ) { - uint64_t* loc64 = reinterpret_cast<uint64_t*>(location); - *loc64 = targetAddress + addend; - } -} - -void DarwinPlatform::writeExecutable(const lld::File &file, raw_ostream &out) { - lld::darwin::writeExecutable(file, *this, out); -} - - -uint64_t DarwinPlatform::pageZeroSize() { - return 0x100000000; -} - - -void DarwinPlatform::initializeMachHeader(const lld::File& file, - mach_header& mh) { - // FIXME: Need to get cpu info from file object - mh.magic = MAGIC_64; - mh.cputype = CPU_TYPE_X86_64; - mh.cpusubtype = CPU_SUBTYPE_X86_64_ALL; - mh.filetype = MH_EXECUTE; - mh.ncmds = 0; - mh.sizeofcmds = 0; - mh.flags = 0; - mh.reserved = 0; -} - -const Atom *DarwinPlatform::mainAtom() { - assert(_cRuntimeFile != nullptr); - const Atom *result = _cRuntimeFile->mainAtom(); - assert(result != nullptr); - if ( result->definition() == Atom::definitionUndefined ) - llvm::report_fatal_error("_main not found"); - return _cRuntimeFile->mainAtom(); -} - - - -} // namespace darwin -} // namespace lld diff --git a/lld/lib/Platforms/Darwin/DarwinPlatform.h b/lld/lib/Platforms/Darwin/DarwinPlatform.h deleted file mode 100644 index c05fb9c2bbb..00000000000 --- a/lld/lib/Platforms/Darwin/DarwinPlatform.h +++ /dev/null @@ -1,61 +0,0 @@ -//===- Platform/DarwinPlatform.h - Darwin Platform Implementation ---------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_PLATFORM_DARWIN_PLATFORM_H_ -#define LLD_PLATFORM_DARWIN_PLATFORM_H_ - -#include "lld/Core/Platform.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/DenseMap.h" - -namespace lld { -namespace darwin { - -class DarwinPlatform : public Platform { -public: - DarwinPlatform(); - -/// @name Platform methods -/// @{ - virtual void addFiles(InputFiles&); - virtual Reference::Kind kindFromString(llvm::StringRef); - virtual llvm::StringRef kindToString(Reference::Kind); - virtual bool noTextRelocs(); - virtual bool isCallSite(Reference::Kind); - virtual bool isGOTAccess(Reference::Kind, bool& canBypassGOT); - virtual void updateReferenceToGOT(const Reference*, bool targetIsNowGOT); - virtual const DefinedAtom* getStub(const Atom&, File&); - virtual void addStubAtoms(File &file); - virtual const DefinedAtom* makeGOTEntry(const Atom&, File&); - virtual void applyFixup(Reference::Kind, uint64_t addend, uint8_t*, - uint64_t fixupAddress, uint64_t targetAddress); - virtual void writeExecutable(const lld::File &, raw_ostream &out); -/// @} -/// @name Darwin specific methods -/// @{ - uint64_t pageZeroSize(); - void initializeMachHeader(const lld::File& file, class mach_header& mh); - const Atom *mainAtom(); -/// @} - -private: - llvm::DenseMap<const Atom*, const DefinedAtom*> _targetToStub; - std::vector<const DefinedAtom*> _lazyPointers; - std::vector<const DefinedAtom*> _stubHelperAtoms; - const SharedLibraryAtom *_stubBinderAtom; - const DefinedAtom* _helperCommonAtom; - const DefinedAtom* _helperCacheAtom; - const DefinedAtom* _helperBinderAtom; - class CRuntimeFile *_cRuntimeFile; -}; - -} // namespace darwin -} // namespace lld - -#endif // LLD_PLATFORM_DARWIN_PLATFORM_H_ diff --git a/lld/lib/Platforms/Darwin/DarwinReferenceKinds.cpp b/lld/lib/Platforms/Darwin/DarwinReferenceKinds.cpp deleted file mode 100644 index 3cc676c6884..00000000000 --- a/lld/lib/Platforms/Darwin/DarwinReferenceKinds.cpp +++ /dev/null @@ -1,90 +0,0 @@ -//===- Platforms/Darwin/DarwinReferenceKinds.cpp --------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - - -#include "DarwinReferenceKinds.h" -#include "llvm/ADT/StringRef.h" - - -namespace lld { -namespace darwin { - - -struct Mapping { - const char* string; - Reference::Kind value; - uint32_t flags; -}; - -enum { - flagsNone = 0x0000, - flagsIsCallSite = 0x0001, - flagsUsesGOT = 0x0002, - flagsisGOTLoad = 0x0006, - flags32RipRel = 0x1000, -}; - - -static const Mapping sKindMappings[] = { - { "none", ReferenceKind::none, flagsNone }, - { "call32", ReferenceKind::call32, flagsIsCallSite | flags32RipRel }, - { "pcrel32", ReferenceKind::pcRel32, flags32RipRel }, - { "gotLoad32", ReferenceKind::gotLoad32, flagsisGOTLoad | flags32RipRel }, - { "gotUse32", ReferenceKind::gotUse32, flagsUsesGOT | flags32RipRel }, - { "lea32wasGot", ReferenceKind::lea32WasGot, flags32RipRel }, - { "lazyTarget", ReferenceKind::lazyTarget, flagsNone }, - { "lazyImm", ReferenceKind::lazyImm, flagsNone }, - { "gotTarget", ReferenceKind::gotTarget, flagsNone }, - { "pointer64", ReferenceKind::pointer64, flagsNone }, - { NULL, ReferenceKind::none, flagsNone } -}; - - -Reference::Kind ReferenceKind::fromString(StringRef kindName) { - for (const Mapping* p = sKindMappings; p->string != NULL; ++p) { - if ( kindName.equals(p->string) ) - return p->value; - } - assert(0 && "unknown darwin reference kind"); - return ReferenceKind::none; -} - -StringRef ReferenceKind::toString(Reference::Kind kindValue) { - for (const Mapping* p = sKindMappings; p->string != NULL; ++p) { - if ( kindValue == p->value) - return p->string; - } - return StringRef("???"); -} - -bool ReferenceKind::isCallSite(Reference::Kind kindValue) { - for (const Mapping* p = sKindMappings; p->string != NULL; ++p) { - if ( kindValue == p->value ) - return (p->flags & flagsIsCallSite); - } - return false; -} - -bool ReferenceKind::isRipRel32(Reference::Kind kindValue) { - for (const Mapping* p = sKindMappings; p->string != NULL; ++p) { - if ( kindValue == p->value ) - return (p->flags & flags32RipRel); - } - return false; -} - - - - - -} // namespace darwin -} // namespace lld - - - diff --git a/lld/lib/Platforms/Darwin/DarwinReferenceKinds.h b/lld/lib/Platforms/Darwin/DarwinReferenceKinds.h deleted file mode 100644 index 9cb254235cf..00000000000 --- a/lld/lib/Platforms/Darwin/DarwinReferenceKinds.h +++ /dev/null @@ -1,54 +0,0 @@ -//===- Platforms/Darwin/DarwinReferenceKinds.h ----------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - - -#include "lld/Core/LLVM.h" -#include "lld/Core/Reference.h" - - -#ifndef LLD_PLATFORM_DARWIN_REFERENCE_KINDS_H_ -#define LLD_PLATFORM_DARWIN_REFERENCE_KINDS_H_ - -namespace lld { -namespace darwin { - - -class ReferenceKind { -public: - enum { - none = 0, - call32 = 1, - pcRel32 = 2, - gotLoad32 = 3, - gotUse32 = 4, - lea32WasGot = 5, - lazyTarget = 6, - lazyImm = 7, - gotTarget = 8, - pointer64 = 9, - }; - - static Reference::Kind fromString(StringRef kindName); - - static StringRef toString(Reference::Kind kindValue); - - static bool isCallSite(Reference::Kind kindValue); - - static bool isRipRel32(Reference::Kind kindValue); -}; - - - -} // namespace darwin -} // namespace lld - - - -#endif // LLD_PLATFORM_DARWIN_REFERENCE_KINDS_H_ - diff --git a/lld/lib/Platforms/Darwin/ExecutableAtoms.hpp b/lld/lib/Platforms/Darwin/ExecutableAtoms.hpp deleted file mode 100644 index 31bd181ccb3..00000000000 --- a/lld/lib/Platforms/Darwin/ExecutableAtoms.hpp +++ /dev/null @@ -1,84 +0,0 @@ -//===- Platforms/Darwin/x86_64StubAtom.hpp --------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_PLATFORM_DARWIN_EXECUTABLE_ATOM_H_ -#define LLD_PLATFORM_DARWIN_EXECUTABLE_ATOM_H_ - - -#include "lld/Core/DefinedAtom.h" -#include "lld/Core/UndefinedAtom.h" -#include "lld/Core/File.h" -#include "lld/Core/Reference.h" - -#include "DarwinReferenceKinds.h" -#include "SimpleAtoms.hpp" - -namespace lld { -namespace darwin { - - -// -// EntryPointReferenceAtom is used to: -// 1) Require "_main" is defined. -// 2) Give Darwin Platform a pointer to the atom named "_main" -// -class EntryPointReferenceAtom : public SimpleDefinedAtom { -public: - EntryPointReferenceAtom(const File &file) - : SimpleDefinedAtom(file) - , _mainUndefAtom(file, "_main") { - this->addReference(ReferenceKind::none, 0, &_mainUndefAtom, 0); - } - - virtual ContentType contentType() const { - return DefinedAtom::typeCode; - } - - virtual uint64_t size() const { - return 0; - } - - virtual ContentPermissions permissions() const { - return DefinedAtom::permR_X; - } - - virtual ArrayRef<uint8_t> rawContent() const { - return ArrayRef<uint8_t>(); - } -private: - friend class CRuntimeFile; - SimpleUndefinedAtom _mainUndefAtom; -}; - - -class CRuntimeFile : public SimpleFile { -public: - CRuntimeFile() - : SimpleFile("C runtime") - , _atom(*this) { - this->addAtom(_atom); - this->addAtom(_atom._mainUndefAtom); - } - - const Atom *mainAtom() { - const Reference *ref = *(_atom.begin()); - return ref->target(); - } - -private: - EntryPointReferenceAtom _atom; -}; - - - -} // namespace darwin -} // namespace lld - - -#endif // LLD_PLATFORM_DARWIN_EXECUTABLE_ATOM_H_ diff --git a/lld/lib/Platforms/Darwin/ExecutableWriter.h b/lld/lib/Platforms/Darwin/ExecutableWriter.h deleted file mode 100644 index 5980f85b6ad..00000000000 --- a/lld/lib/Platforms/Darwin/ExecutableWriter.h +++ /dev/null @@ -1,35 +0,0 @@ -//===- Platforms/Darwin/ExecutableWriter.h --------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - - -#include "lld/Core/LLVM.h" - - -#ifndef LLD_PLATFORM_DARWIN_EXECUTABLE_WRITER_H_ -#define LLD_PLATFORM_DARWIN_EXECUTABLE_WRITER_H_ - -namespace lld { - -class File; - -namespace darwin { - -class DarwinPlatform; - -void writeExecutable(const lld::File &file, DarwinPlatform &platform, - raw_ostream &out); - - -} // namespace darwin -} // namespace lld - - - -#endif // LLD_PLATFORM_DARWIN_EXECUTABLE_WRITER_H_ - diff --git a/lld/lib/Reader/CMakeLists.txt b/lld/lib/Reader/CMakeLists.txt deleted file mode 100644 index c8f2421649c..00000000000 --- a/lld/lib/Reader/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -add_lld_library(lldReader - COFFReader.cpp - ) diff --git a/lld/lib/ReaderWriter/CMakeLists.txt b/lld/lib/ReaderWriter/CMakeLists.txt new file mode 100644 index 00000000000..85ec90bc60f --- /dev/null +++ b/lld/lib/ReaderWriter/CMakeLists.txt @@ -0,0 +1,9 @@ +add_subdirectory(ELF) +add_subdirectory(MachO) +add_subdirectory(Native) +add_subdirectory(PECOFF) +add_subdirectory(YAML) +add_lld_library(lldReaderWriter + Reader.cpp + Writer.cpp + ) diff --git a/lld/lib/ReaderWriter/ELF/CMakeLists.txt b/lld/lib/ReaderWriter/ELF/CMakeLists.txt new file mode 100644 index 00000000000..4a28b631915 --- /dev/null +++ b/lld/lib/ReaderWriter/ELF/CMakeLists.txt @@ -0,0 +1,4 @@ +add_lld_library(lldELF + ReaderELF.cpp + WriterELF.cpp + ) diff --git a/lld/lib/ReaderWriter/ELF/ReaderELF.cpp b/lld/lib/ReaderWriter/ELF/ReaderELF.cpp new file mode 100644 index 00000000000..ba23990ea0a --- /dev/null +++ b/lld/lib/ReaderWriter/ELF/ReaderELF.cpp @@ -0,0 +1,41 @@ +//===- lib/ReaderWriter/ELF/ReaderELF.cpp --------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/ReaderWriter/ReaderELF.h" +#include "lld/Core/File.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> + + +namespace lld { + +ReaderOptionsELF::ReaderOptionsELF() { +} + +ReaderOptionsELF::~ReaderOptionsELF() { +} + + + +Reader* createReaderELF(const ReaderOptionsELF &options) { + assert(0 && "ELF Reader not yet implemented"); + return nullptr; +} + + +} // namespace + diff --git a/lld/lib/ReaderWriter/ELF/WriterELF.cpp b/lld/lib/ReaderWriter/ELF/WriterELF.cpp new file mode 100644 index 00000000000..fe445b6f08e --- /dev/null +++ b/lld/lib/ReaderWriter/ELF/WriterELF.cpp @@ -0,0 +1,35 @@ +//===- lib/ReaderWriter/ELF/WriterELF.cpp ---------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/ReaderWriter/WriterELF.h" + +#include "llvm/Support/Debug.h" + + +namespace lld { +namespace elf { + +// define ELF writer class here + + +} // namespace elf + +Writer* createWriterELF(const WriterOptionsELF &options) { + assert(0 && "ELF support not implemented yet"); + return nullptr; +} + +WriterOptionsELF::WriterOptionsELF() { +} + +WriterOptionsELF::~WriterOptionsELF() { +} + +} // namespace lld + diff --git a/lld/lib/ReaderWriter/MachO/CMakeLists.txt b/lld/lib/ReaderWriter/MachO/CMakeLists.txt new file mode 100644 index 00000000000..c6a1059802c --- /dev/null +++ b/lld/lib/ReaderWriter/MachO/CMakeLists.txt @@ -0,0 +1,4 @@ +add_lld_library(lldMachO + WriterMachO.cpp + ReferenceKinds.cpp + ) diff --git a/lld/lib/ReaderWriter/MachO/ExecutableAtoms.hpp b/lld/lib/ReaderWriter/MachO/ExecutableAtoms.hpp new file mode 100644 index 00000000000..ac80059624c --- /dev/null +++ b/lld/lib/ReaderWriter/MachO/ExecutableAtoms.hpp @@ -0,0 +1,50 @@ +//===- lib/ReaderWriter/MachO/ExecutableAtoms.hpp -------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READER_WRITER_MACHO_EXECUTABLE_ATOM_H_ +#define LLD_READER_WRITER_MACHO_EXECUTABLE_ATOM_H_ + + +#include "lld/Core/DefinedAtom.h" +#include "lld/Core/UndefinedAtom.h" +#include "lld/Core/File.h" +#include "lld/Core/Reference.h" + +#include "lld/ReaderWriter/WriterMachO.h" + +#include "SimpleAtoms.hpp" + +namespace lld { +namespace mach_o { + + +// +// CRuntimeFile adds an UndefinedAtom for "_main" so that the Resolving +// phase will fail if "_main" is undefined. +// +class CRuntimeFile : public SimpleFile { +public: + CRuntimeFile(const WriterOptionsMachO &options) + : SimpleFile("C runtime"), _undefMain(*this, "_main") { + // only main executables need _main + if ( options.outputKind() == WriterOptionsMachO::outputDynamicExecutable) + this->addAtom(_undefMain); + } + +private: + SimpleUndefinedAtom _undefMain; +}; + + + +} // namespace mach_o +} // namespace lld + + +#endif // LLD_READER_WRITER_MACHO_EXECUTABLE_ATOM_H_ diff --git a/lld/lib/ReaderWriter/MachO/GOTPass.hpp b/lld/lib/ReaderWriter/MachO/GOTPass.hpp new file mode 100644 index 00000000000..6a7c451e448 --- /dev/null +++ b/lld/lib/ReaderWriter/MachO/GOTPass.hpp @@ -0,0 +1,51 @@ +//===- lib/ReaderWriter/MachO/GOTPass.hpp ---------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READER_WRITER_MACHO_GOT_PASS_H_ +#define LLD_READER_WRITER_MACHO_GOT_PASS_H_ + +#include "lld/Core/DefinedAtom.h" +#include "lld/Core/SharedLibraryAtom.h" +#include "lld/Core/File.h" +#include "lld/Core/Reference.h" +#include "lld/Core/Pass.h" + +#include "ReferenceKinds.h" +#include "StubAtoms.hpp" + +namespace lld { +namespace mach_o { + + +class GOTPass : public lld::GOTPass { +public: + virtual bool noTextRelocs() { + return true; + } + + virtual bool isGOTAccess(Reference::Kind, bool& canBypassGOT) { + return false; + } + + virtual void updateReferenceToGOT(const Reference*, bool targetIsNowGOT) { + + } + + virtual const DefinedAtom* makeGOTEntry(const Atom&) { + return nullptr; + } + +}; + + +} // namespace mach_o +} // namespace lld + + +#endif // LLD_READER_WRITER_MACHO_GOT_PASS_H_ diff --git a/lld/lib/Platforms/Darwin/MachOFormat.hpp b/lld/lib/ReaderWriter/MachO/MachOFormat.hpp index 55340aa6145..e6a04e1dd74 100644 --- a/lld/lib/Platforms/Darwin/MachOFormat.hpp +++ b/lld/lib/ReaderWriter/MachO/MachOFormat.hpp @@ -1,4 +1,4 @@ -//===- Platforms/Darwin/MachOFormat.hpp -----------------------------------===// +//===- lib/ReaderWriter/MachO/MachOFormat.hpp -----------------------------===// // // The LLVM Linker // @@ -15,22 +15,22 @@ // #include "llvm/Support/DataTypes.h" -#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Memory.h" - -#ifndef LLD_PLATFORM_DARWIN_MACHO_FORMAT_H_ -#define LLD_PLATFORM_DARWIN_MACHO_FORMAT_H_ +#ifndef LLD_READER_WRITER_MACHO_FORMAT_H_ +#define LLD_READER_WRITER_MACHO_FORMAT_H_ namespace lld { -namespace darwin { +namespace mach_o { class load_command { public: uint32_t cmd; uint32_t cmdsize; - void write(raw_ostream& out) { - out.write((char*)&cmd, cmdsize); + void copyTo(uint8_t* to, bool swap=false) { + ::memcpy(to, (uint8_t*)&cmd, cmdsize); } }; @@ -50,9 +50,13 @@ enum { }; enum { - MH_EXECUTE = 0x2, - MH_DYLIB = 0x6, - MH_BUNDLE = 0x8 + MH_OBJECT = 0x1, + MH_EXECUTE = 0x2, + MH_DYLIB = 0x6, + MH_DYLINKER = 0x7, + MH_BUNDLE = 0x8, + MH_DYLIB_STUB = 0x9, + MH_KEXT_BUNDLE= 0xB }; @@ -65,14 +69,14 @@ public: uint32_t ncmds; uint32_t sizeofcmds; uint32_t flags; - uint32_t reserved; + uint32_t reserved; uint64_t size() { return (magic == 0xfeedfacf) ? 32 : 28; } - void write(raw_ostream& out) { - out.write((char*)&magic, this->size()); + void copyTo(uint8_t* to, bool swap=false) { + ::memcpy(to, (char*)&magic, this->size()); } void recordLoadCommand(const class load_command* lc) { @@ -140,7 +144,11 @@ public: // The segment_command_64 load commands has a nsect trailing // section_64 records appended to the end. static segment_command_64* make(unsigned sectCount) { - unsigned size = sizeof(segment_command_64) + sectCount* sizeof(section_64); + // Compute size in portable way. Can't use offsetof() in non-POD class. + // Can't use zero size sections[] array above. + // So, since sizeof() already includes one section_64, subtract it off. + unsigned size = sizeof(segment_command_64) + + ((int)sectCount -1) * sizeof(section_64); segment_command_64* result = reinterpret_cast<segment_command_64*> (::calloc(1, size)); result->cmd = LC_SEGMENT_64; @@ -194,8 +202,8 @@ public: uint16_t n_desc; uint64_t n_value; - void write(raw_ostream& out) { - out.write((char*)&n_strx, 16); + void copyTo(uint8_t* to, bool swap=false) { + ::memcpy(to, (uint8_t*)&n_strx, 16); } @@ -337,10 +345,10 @@ enum { -} // namespace darwin +} // namespace mach_o } // namespace lld -#endif // LLD_PLATFORM_DARWIN_MACHO_FORMAT_H_ +#endif // LLD_READER_WRITER_MACHO_FORMAT_H_ diff --git a/lld/lib/ReaderWriter/MachO/ReferenceKinds.cpp b/lld/lib/ReaderWriter/MachO/ReferenceKinds.cpp new file mode 100644 index 00000000000..a0b3dbfa5c6 --- /dev/null +++ b/lld/lib/ReaderWriter/MachO/ReferenceKinds.cpp @@ -0,0 +1,103 @@ +//===- lib/FileFormat/MachO/ReferenceKinds.cpp ----------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +#include "ReferenceKinds.h" + +#include "llvm/ADT/StringRef.h" + + +namespace lld { +namespace mach_o { + + +struct Mapping { + const char* string; + Reference::Kind value; + uint32_t flags; +}; + +enum { + flagsNone = 0x0000, + flagsIsCallSite = 0x0001, + flagsUsesGOT = 0x0002, + flagsisGOTLoad = 0x0006, + flags32RipRel = 0x1000, +}; + + +static const Mapping sKindMappingsx86_64[] = { + { "none", ReferenceKind::x86_64_none, flagsNone }, + { "call32", ReferenceKind::x86_64_call32, flagsIsCallSite | flags32RipRel }, + { "pcrel32", ReferenceKind::x86_64_pcRel32, flags32RipRel }, + { "gotLoad32", ReferenceKind::x86_64_gotLoad32, flagsisGOTLoad | flags32RipRel }, + { "gotUse32", ReferenceKind::x86_64_gotUse32, flagsUsesGOT | flags32RipRel }, + { "lea32wasGot", ReferenceKind::x86_64_lea32WasGot, flags32RipRel }, + { "lazyTarget", ReferenceKind::x86_64_lazyTarget, flagsNone }, + { "lazyImm", ReferenceKind::x86_64_lazyImm, flagsNone }, + { "gotTarget", ReferenceKind::x86_64_gotTarget, flagsNone }, + { "pointer64", ReferenceKind::x86_64_pointer64, flagsNone }, + { NULL, ReferenceKind::x86_64_none, flagsNone } +}; + + +Reference::Kind ReferenceKind::fromString(StringRef kindName) { + for (const Mapping* p = sKindMappingsx86_64; p->string != NULL; ++p) { + if ( kindName.equals(p->string) ) + return p->value; + } + assert(0 && "unknown darwin reference kind"); + return 0; +} + +StringRef ReferenceKind::toString(Reference::Kind kindValue) { + for (const Mapping* p = sKindMappingsx86_64; p->string != NULL; ++p) { + if ( kindValue == p->value) + return p->string; + } + return StringRef("???"); +} + +static const Mapping* mappingsForArch(WriterOptionsMachO::Architecture arch) { + switch ( arch ) { + case WriterOptionsMachO::arch_x86_64: + return sKindMappingsx86_64; + case WriterOptionsMachO::arch_x86: + case WriterOptionsMachO::arch_arm: + assert(0 && "references table not yet implemented for arch"); + return nullptr; + } +} + +bool ReferenceKind::isCallSite(WriterOptionsMachO::Architecture arch, + Reference::Kind kindValue) { + for (const Mapping* p = mappingsForArch(arch); p->string != NULL; ++p) { + if ( kindValue == p->value ) + return (p->flags & flagsIsCallSite); + } + return false; +} + +bool ReferenceKind::isRipRel32(Reference::Kind kindValue) { + for (const Mapping* p = sKindMappingsx86_64; p->string != NULL; ++p) { + if ( kindValue == p->value ) + return (p->flags & flags32RipRel); + } + return false; +} + + + + + +} // namespace mach_o +} // namespace lld + + + diff --git a/lld/lib/ReaderWriter/MachO/ReferenceKinds.h b/lld/lib/ReaderWriter/MachO/ReferenceKinds.h new file mode 100644 index 00000000000..8680b346c2d --- /dev/null +++ b/lld/lib/ReaderWriter/MachO/ReferenceKinds.h @@ -0,0 +1,77 @@ +//===- lib/FileFormat/MachO/ReferenceKinds.h ------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +#include "lld/Core/LLVM.h" +#include "lld/Core/Reference.h" +#include "lld/ReaderWriter/WriterMachO.h" + +#ifndef LLD_READER_WRITER_MACHO_REFERENCE_KINDS_H_ +#define LLD_READER_WRITER_MACHO_REFERENCE_KINDS_H_ + +namespace lld { +namespace mach_o { + + +class ReferenceKind { +public: + // x86_64 Reference Kinds + enum { + x86_64_none = 0, + x86_64_call32 = 1, + x86_64_pcRel32 = 2, + x86_64_gotLoad32 = 3, + x86_64_gotUse32 = 4, + x86_64_lea32WasGot = 5, + x86_64_lazyTarget = 6, + x86_64_lazyImm = 7, + x86_64_gotTarget = 8, + x86_64_pointer64 = 9, + }; + + // x86 Reference Kinds + enum { + x86_none = 0, + x86_call32 = 1, + x86_pointer32 = 2, + x86_lazyTarget = 3, + x86_lazyImm = 4, + // FIXME + }; + + // ARM Reference Kinds + enum { + arm_none = 0, + arm_br22 = 1, + arm_pointer32 = 2, + arm_lazyTarget = 3, + arm_lazyImm = 4, + // FIXME + }; + + static bool isCallSite(WriterOptionsMachO::Architecture arch, + Reference::Kind kindValue); + + static bool isRipRel32(Reference::Kind kindValue); + + + static Reference::Kind fromString(StringRef kindName); + static StringRef toString(Reference::Kind kindValue); + +}; + + + +} // namespace mach_o +} // namespace lld + + + +#endif // LLD_READER_WRITER_MACHO_REFERENCE_KINDS_H_ + diff --git a/lld/lib/Platforms/Darwin/SimpleAtoms.hpp b/lld/lib/ReaderWriter/MachO/SimpleAtoms.hpp index f9c7aa0130d..498793f4746 100644 --- a/lld/lib/Platforms/Darwin/SimpleAtoms.hpp +++ b/lld/lib/ReaderWriter/MachO/SimpleAtoms.hpp @@ -1,4 +1,4 @@ -//===- Platforms/Darwin/x86_64StubAtom.hpp --------------------------------===// +//===- lib/ReaderWriter/MachO/SimpleAtoms.hpp -----------------------------===// // // The LLVM Linker // @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLD_PLATFORM_DARWIN_SIMPLE_ATOM_H_ -#define LLD_PLATFORM_DARWIN_SIMPLE_ATOM_H_ +#ifndef LLD_READER_WRITER_MACHO_SIMPLE_ATOM_H_ +#define LLD_READER_WRITER_MACHO_SIMPLE_ATOM_H_ #include <vector> @@ -18,7 +18,7 @@ #include "lld/Core/Reference.h" namespace lld { -namespace darwin { +namespace mach_o { // @@ -240,8 +240,8 @@ private: -} // namespace darwin +} // namespace mach_o } // namespace lld -#endif // LLD_PLATFORM_DARWIN_SIMPLE_ATOM_H_ +#endif // LLD_READER_WRITER_MACHO_SIMPLE_ATOM_H_ diff --git a/lld/lib/Platforms/Darwin/StubAtoms.hpp b/lld/lib/ReaderWriter/MachO/StubAtoms.hpp index 1023d42010e..3e6bbe19737 100644 --- a/lld/lib/Platforms/Darwin/StubAtoms.hpp +++ b/lld/lib/ReaderWriter/MachO/StubAtoms.hpp @@ -1,4 +1,4 @@ -//===- Platforms/Darwin/x86_64StubAtom.hpp --------------------------------===// +//===- lib/ReaderWriter/MachO/StubAtoms.hpp -------------------------------===// // // The LLVM Linker // @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLD_PLATFORM_DARWIN_X86_64_STUB_ATOM_H_ -#define LLD_PLATFORM_DARWIN_X86_64_STUB_ATOM_H_ +#ifndef LLD_READER_WRITER_MACHO_STUB_ATOM_H_ +#define LLD_READER_WRITER_MACHO_STUB_ATOM_H_ #include "llvm/ADT/ArrayRef.h" @@ -17,11 +17,11 @@ #include "lld/Core/File.h" #include "lld/Core/Reference.h" -#include "DarwinReferenceKinds.h" +#include "ReferenceKinds.h" #include "SimpleAtoms.hpp" namespace lld { -namespace darwin { +namespace mach_o { // @@ -31,7 +31,7 @@ class X86_64StubAtom : public SimpleDefinedAtom { public: X86_64StubAtom(const File &file, const Atom &lazyPointer) : SimpleDefinedAtom(file) { - this->addReference(ReferenceKind::pcRel32, 2, &lazyPointer, 0); + this->addReference(ReferenceKind::x86_64_pcRel32, 2, &lazyPointer, 0); } virtual ContentType contentType() const { @@ -64,8 +64,8 @@ public: X86_64StubHelperCommonAtom(const File &file, const Atom &cache, const Atom &binder) : SimpleDefinedAtom(file) { - this->addReference(ReferenceKind::pcRel32, 3, &cache, 0); - this->addReference(ReferenceKind::pcRel32, 11, &binder, 0); + this->addReference(ReferenceKind::x86_64_pcRel32, 3, &cache, 0); + this->addReference(ReferenceKind::x86_64_pcRel32, 11, &binder, 0); } virtual ContentType contentType() const { @@ -101,8 +101,8 @@ class X86_64StubHelperAtom : public SimpleDefinedAtom { public: X86_64StubHelperAtom(const File &file, const Atom &helperCommon) : SimpleDefinedAtom(file) { - this->addReference(ReferenceKind::lazyImm, 1, nullptr, 0); - this->addReference(ReferenceKind::pcRel32, 6, &helperCommon, 0); + this->addReference(ReferenceKind::x86_64_lazyImm, 1, nullptr, 0); + this->addReference(ReferenceKind::x86_64_pcRel32, 6, &helperCommon, 0); } virtual ContentType contentType() const { @@ -136,8 +136,8 @@ public: X86_64LazyPointerAtom(const File &file, const Atom &helper, const Atom &shlib) : SimpleDefinedAtom(file) { - this->addReference(ReferenceKind::pointer64, 0, &helper, 0); - this->addReference(ReferenceKind::lazyTarget, 0, &shlib, 0); + this->addReference(ReferenceKind::x86_64_pointer64, 0, &helper, 0); + this->addReference(ReferenceKind::x86_64_lazyTarget, 0, &shlib, 0); } virtual ContentType contentType() const { @@ -172,7 +172,7 @@ public: X86_64NonLazyPointerAtom(const File &file, const Atom &shlib) : SimpleDefinedAtom(file) { - this->addReference(ReferenceKind::pointer64, 0, &shlib, 0); + this->addReference(ReferenceKind::x86_64_pointer64, 0, &shlib, 0); } virtual ContentType contentType() const { @@ -226,8 +226,8 @@ private: -} // namespace darwin +} // namespace mach_o } // namespace lld -#endif // LLD_PLATFORM_DARWIN_X86_64_STUB_ATOM_H_ +#endif // LLD_READER_WRITER_MACHO_STUB_ATOM_H_ diff --git a/lld/lib/ReaderWriter/MachO/StubsPass.hpp b/lld/lib/ReaderWriter/MachO/StubsPass.hpp new file mode 100644 index 00000000000..34beaa220a6 --- /dev/null +++ b/lld/lib/ReaderWriter/MachO/StubsPass.hpp @@ -0,0 +1,145 @@ +//===- lib/ReaderWriter/MachO/StubsPass.hpp -------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READER_WRITER_MACHO_STUBS_PASS_H_ +#define LLD_READER_WRITER_MACHO_STUBS_PASS_H_ + +#include "llvm/ADT/DenseMap.h" + +#include "lld/Core/DefinedAtom.h" +#include "lld/Core/SharedLibraryAtom.h" +#include "lld/Core/File.h" +#include "lld/Core/Reference.h" +#include "lld/Core/Pass.h" + +#include "ReferenceKinds.h" +#include "SimpleAtoms.hpp" +#include "StubAtoms.hpp" + +namespace lld { +namespace mach_o { + + +class StubsPass : public lld::StubsPass { +public: + StubsPass(const WriterOptionsMachO &options) : _options(options) { + } + + virtual bool noTextRelocs() { + return _options.noTextRelocations(); + } + + virtual bool isCallSite(Reference::Kind kind) { + return ReferenceKind::isCallSite(_options.architecture(), kind); + } + + virtual const DefinedAtom* getStub(const Atom& target) { + auto pos = _targetToStub.find(&target); + if ( pos != _targetToStub.end() ) { + // Reuse an existing stub. + assert(pos->second != nullptr); + return pos->second; + } + else { + // There is no existing stub, so create a new one. + return this->makeStub(target); + } + } + + const DefinedAtom* makeStub(const Atom& target) { + switch ( _options.architecture() ) { + case WriterOptionsMachO::arch_x86_64: + return makeStub_x86_64(target); + + case WriterOptionsMachO::arch_x86: + return makeStub_x86(target); + + case WriterOptionsMachO::arch_arm: + return makeStub_arm(target); + } + } + + const DefinedAtom* makeStub_x86_64(const Atom& target) { + if ( _helperCommonAtom == nullptr ) { + // Lazily create common helper code and data. + _helperCacheAtom = new X86_64NonLazyPointerAtom(_file); + _binderAtom = new StubBinderAtom(_file); + _helperBinderAtom = new X86_64NonLazyPointerAtom(_file, *_binderAtom); + _helperCommonAtom = new X86_64StubHelperCommonAtom(_file, + *_helperCacheAtom, *_helperBinderAtom); + } + const DefinedAtom* helper = new X86_64StubHelperAtom(_file, + *_helperCommonAtom); + _stubHelperAtoms.push_back(helper); + const DefinedAtom* lp = new X86_64LazyPointerAtom(_file, *helper, target); + assert(lp->contentType() == DefinedAtom::typeLazyPointer); + _lazyPointers.push_back(lp); + const DefinedAtom* stub = new X86_64StubAtom(_file, *lp); + assert(stub->contentType() == DefinedAtom::typeStub); + _targetToStub[&target] = stub; + return stub; + } + + const DefinedAtom* makeStub_x86(const Atom& target) { + assert(0 && "stubs not yet implemented for x86"); + return nullptr; + } + + const DefinedAtom* makeStub_arm(const Atom& target) { + assert(0 && "stubs not yet implemented for arm"); + return nullptr; + } + + + virtual void addStubAtoms(File &mergedFile) { + // Add all stubs to master file. + for (auto it : _targetToStub) { + mergedFile.addAtom(*it.second); + } + // Add helper code atoms. + mergedFile.addAtom(*_helperCommonAtom); + for (const DefinedAtom *lp : _stubHelperAtoms) { + mergedFile.addAtom(*lp); + } + // Add GOT slots used for lazy binding. + mergedFile.addAtom(*_helperBinderAtom); + mergedFile.addAtom(*_helperCacheAtom); + // Add all lazy pointers to master file. + for (const DefinedAtom *lp : _lazyPointers) { + mergedFile.addAtom(*lp); + } + // Add sharedlibrary atom + mergedFile.addAtom(*_binderAtom); + } + +private: + + class File : public SimpleFile { + public: + File() : SimpleFile("MachO Stubs pass") { + } + }; + + const WriterOptionsMachO &_options; + File _file; + llvm::DenseMap<const Atom*, const DefinedAtom*> _targetToStub; + std::vector<const DefinedAtom*> _lazyPointers; + std::vector<const DefinedAtom*> _stubHelperAtoms; + const SharedLibraryAtom *_binderAtom; + const DefinedAtom* _helperCommonAtom; + const DefinedAtom* _helperCacheAtom; + const DefinedAtom* _helperBinderAtom; +}; + + +} // namespace mach_o +} // namespace lld + + +#endif // LLD_READER_WRITER_MACHO_STUBS_PASS_H_ diff --git a/lld/lib/Platforms/Darwin/ExecutableWriter.cpp b/lld/lib/ReaderWriter/MachO/WriterMachO.cpp index 42c62a55f76..3d91a8a5040 100644 --- a/lld/lib/Platforms/Darwin/ExecutableWriter.cpp +++ b/lld/lib/ReaderWriter/MachO/WriterMachO.cpp @@ -1,4 +1,4 @@ -//===- Platforms/Darwin/ExecutableWriter.cpp ------------------------------===// +//===- lib/ReaderWriter/MachO/WriterMachO.cpp -----------------------------===// // // The LLVM Linker // @@ -7,33 +7,42 @@ // //===----------------------------------------------------------------------===// -#include "ExecutableWriter.h" -#include "MachOFormat.hpp" -#include "DarwinReferenceKinds.h" -#include "DarwinPlatform.h" - -#include <vector> -#include <map> - -#include <string.h> +#include "lld/ReaderWriter/WriterMachO.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +//#include "llvm/Support/FileOutputBuffer.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/system_error.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/SmallVector.h" #include "lld/Core/DefinedAtom.h" -#include "lld/Core/SharedLibraryAtom.h" #include "lld/Core/File.h" +#include "lld/Core/InputFiles.h" #include "lld/Core/Reference.h" +#include "lld/Core/SharedLibraryAtom.h" + +#include <vector> +#include <map> +#include <string.h> + +#include "MachOFormat.hpp" +#include "ReferenceKinds.h" +#include "ExecutableAtoms.hpp" +#include "GOTPass.hpp" +#include "StubsPass.hpp" namespace lld { -namespace darwin { +namespace mach_o { // // A mach-o file consists of some meta data (header and load commands), @@ -66,8 +75,7 @@ class Chunk { public: virtual StringRef segmentName() const = 0; virtual bool occupiesNoDiskSpace(); - virtual void write(raw_ostream &out) = 0; - static void writeZeros(uint64_t amount, raw_ostream &out); + virtual void write(uint8_t *fileBuffer) = 0; void assignFileOffset(uint64_t &curOff, uint64_t &curAddr); virtual const char* info() = 0; uint64_t size() const; @@ -95,11 +103,11 @@ protected: class SectionChunk : public Chunk { public: static SectionChunk* make(DefinedAtom::ContentType, - DarwinPlatform &platform, + const WriterOptionsMachO &options, class MachOWriter &writer); virtual StringRef segmentName() const; virtual bool occupiesNoDiskSpace(); - virtual void write(raw_ostream &out); + virtual void write(uint8_t *fileBuffer); virtual const char* info(); StringRef sectionName(); uint32_t flags() const; @@ -117,16 +125,20 @@ private: SectionChunk(StringRef seg, StringRef sect, uint32_t flags, - DarwinPlatform &platform, + const WriterOptionsMachO &options, class MachOWriter &writer); - StringRef _segmentName; - StringRef _sectionName; - DarwinPlatform &_platform; - class MachOWriter &_writer; - uint32_t _flags; - uint32_t _permissions; - std::vector<AtomInfo> _atoms; + void applyFixup(Reference::Kind kind, uint64_t addend, + uint8_t* location, uint64_t fixupAddress, + uint64_t targetAddress); + + StringRef _segmentName; + StringRef _sectionName; + const WriterOptionsMachO &_options; + class MachOWriter &_writer; + uint32_t _flags; + uint32_t _permissions; + std::vector<AtomInfo> _atoms; }; @@ -137,14 +149,17 @@ private: // class MachHeaderChunk : public Chunk { public: - MachHeaderChunk(DarwinPlatform &plat, const File &file); + MachHeaderChunk(const WriterOptionsMachO &options, + const File &file); virtual StringRef segmentName() const; - virtual void write(raw_ostream &out); + virtual void write(uint8_t *fileBuffer); virtual const char* info(); void recordLoadCommand(load_command*); uint64_t loadCommandsSize(); private: + uint32_t filetype(WriterOptionsMachO::OutputKind kind); + mach_header _mh; }; @@ -158,10 +173,10 @@ private: class LoadCommandsChunk : public Chunk { public: LoadCommandsChunk(MachHeaderChunk&, - DarwinPlatform&, + const WriterOptionsMachO &options, class MachOWriter&); virtual StringRef segmentName() const; - virtual void write(raw_ostream &out); + virtual void write(uint8_t *fileBuffer); virtual const char* info(); void computeSize(const lld::File &file); void addSection(SectionChunk*); @@ -183,7 +198,7 @@ private: }; MachHeaderChunk &_mh; - DarwinPlatform &_platform; + const WriterOptionsMachO &_options; class MachOWriter &_writer; segment_command_64 *_linkEditSegment; symtab_command *_symbolTableLoadCommand; @@ -204,7 +219,7 @@ class LoadCommandPaddingChunk : public Chunk { public: LoadCommandPaddingChunk(LoadCommandsChunk&); virtual StringRef segmentName() const; - virtual void write(raw_ostream &out); + virtual void write(uint8_t *fileBuffer); virtual const char* info(); void computeSize(); private: @@ -234,7 +249,7 @@ public: class DyldInfoChunk : public LinkEditChunk { public: DyldInfoChunk(class MachOWriter &); - virtual void write(raw_ostream &out); + virtual void write(uint8_t *fileBuffer); protected: void append_byte(uint8_t); @@ -283,7 +298,7 @@ private: class SymbolTableChunk : public LinkEditChunk { public: SymbolTableChunk(class SymbolStringsChunk&); - virtual void write(raw_ostream &out); + virtual void write(uint8_t *fileBuffer); virtual void computeSize(const lld::File &file, const std::vector<SectionChunk*>&); virtual const char* info(); @@ -307,7 +322,7 @@ private: class SymbolStringsChunk : public LinkEditChunk { public: SymbolStringsChunk(); - virtual void write(raw_ostream &out); + virtual void write(uint8_t *fileBuffer); virtual void computeSize(const lld::File &file, const std::vector<SectionChunk*>&); virtual const char* info(); @@ -321,14 +336,16 @@ private: // // A MachOWriter manages all the Chunks that comprise a mach-o executable. // -class MachOWriter { +class MachOWriter : public Writer { public: - MachOWriter(DarwinPlatform &platform); - void build(const lld::File &file); - void write(raw_ostream &out); + MachOWriter(const WriterOptionsMachO &options); + + virtual error_code writeFile(const lld::File &file, StringRef path); + virtual StubsPass *stubPass(); + virtual GOTPass *gotPass(); + virtual void addFiles(InputFiles&); uint64_t addressOfAtom(const Atom *atom); - void zeroFill(int64_t amount, raw_ostream &out); void findSegment(StringRef segmentName, uint32_t *segIndex, uint64_t *segStartAddr, uint64_t *segEndAddr); @@ -338,6 +355,7 @@ private: friend class LoadCommandsChunk; friend class LazyBindingInfoChunk; + void build(const lld::File &file); void createChunks(const lld::File &file); void buildAtomToAddressMap(); void assignFileOffsets(); @@ -349,7 +367,10 @@ private: typedef llvm::DenseMap<const Atom*, uint64_t> AtomToAddress; - DarwinPlatform &_platform; + const WriterOptionsMachO &_options; + StubsPass _stubsPass; + GOTPass _gotPass; + CRuntimeFile _cRuntimeFile; LoadCommandsChunk *_loadCommandsChunk; LoadCommandPaddingChunk *_paddingChunk; AtomToAddress _atomToAddress; @@ -360,6 +381,7 @@ private: LazyBindingInfoChunk *_lazyBindingInfo; SymbolTableChunk *_symbolTableChunk; SymbolStringsChunk *_stringsChunk; + const DefinedAtom *_mainAtom; uint64_t _linkEditStartOffset; uint64_t _linkEditStartAddress; }; @@ -394,12 +416,6 @@ uint64_t Chunk::fileOffset() const { return _fileOffset; } - -void Chunk::writeZeros(uint64_t amount, raw_ostream &out) { - for( int i=amount; i > 0; --i) - out.write('\0'); -} - uint64_t Chunk::alignTo(uint64_t value, uint8_t align2) { uint64_t align = 1 << align2; return ( (value + (align-1)) & (-align) ); @@ -420,11 +436,13 @@ void Chunk::assignFileOffset(uint64_t &curOffset, uint64_t &curAddress) { curOffset = _fileOffset + _size; curAddress = _address + _size; } - DEBUG(llvm::dbgs() << " fileOffset=0x"; - llvm::dbgs().write_hex(_fileOffset); - llvm::dbgs() << " address=0x"; - llvm::dbgs().write_hex(_address); - llvm::dbgs() << " info=" << this->info() << "\n"); + + DEBUG_WITH_TYPE("WriterMachO-layout", llvm::dbgs() + << " fileOffset=" + << llvm::format("0x%08X", _fileOffset) + << " address=" + << llvm::format("0x%016X", _address) + << " info=" << this->info() << "\n"); } @@ -434,46 +452,46 @@ void Chunk::assignFileOffset(uint64_t &curOffset, uint64_t &curAddress) { //===----------------------------------------------------------------------===// SectionChunk::SectionChunk(StringRef seg, StringRef sect, - uint32_t flags, DarwinPlatform &platform, + uint32_t flags, const WriterOptionsMachO &options, MachOWriter &writer) - : _segmentName(seg), _sectionName(sect), _platform(platform), + : _segmentName(seg), _sectionName(sect), _options(options), _writer(writer), _flags(flags), _permissions(0) { } SectionChunk* SectionChunk::make(DefinedAtom::ContentType type, - DarwinPlatform &platform, + const WriterOptionsMachO &options, MachOWriter &writer) { switch ( type ) { case DefinedAtom::typeCode: return new SectionChunk("__TEXT", "__text", S_REGULAR | S_ATTR_PURE_INSTRUCTIONS, - platform, writer); + options, writer); break; case DefinedAtom::typeCString: return new SectionChunk("__TEXT", "__cstring", S_CSTRING_LITERALS, - platform, writer); + options, writer); break; case DefinedAtom::typeStub: return new SectionChunk("__TEXT", "__stubs", S_SYMBOL_STUBS | S_ATTR_PURE_INSTRUCTIONS, - platform, writer); + options, writer); break; case DefinedAtom::typeStubHelper: return new SectionChunk("__TEXT", "__stub_helper", S_REGULAR | S_ATTR_PURE_INSTRUCTIONS, - platform, writer); + options, writer); break; case DefinedAtom::typeLazyPointer: return new SectionChunk("__DATA", "__la_symbol_ptr", S_LAZY_SYMBOL_POINTERS, - platform, writer); + options, writer); break; case DefinedAtom::typeGOT: return new SectionChunk("__DATA", "__got", S_NON_LAZY_SYMBOL_POINTERS, - platform, writer); + options, writer); break; default: assert(0 && "TO DO: add support for more sections"); @@ -542,46 +560,67 @@ void SectionChunk::appendAtom(const DefinedAtom *atom) { } -void SectionChunk::write(raw_ostream &out) { - assert( out.tell() == _fileOffset); - SmallVector<uint8_t, 1024> buffer; +void SectionChunk::write(uint8_t *chunkBuffer) { // Each section's content is just its atoms' content. for (const AtomInfo &atomInfo : _atoms ) { - uint64_t atomFileOffset = _fileOffset + atomInfo.offsetInSection; - if ( atomFileOffset != out.tell() ) { - // Need to add alignment padding before this atom starts. - assert(atomFileOffset > out.tell()); - this->writeZeros(atomFileOffset - out.tell(), out); - } - // Copy raw content of atom. + // Copy raw content of atom to file buffer. ArrayRef<uint8_t> content = atomInfo.atom->rawContent(); uint64_t contentSize = content.size(); - buffer.resize(contentSize); if ( contentSize == 0 ) continue; - ::memcpy(buffer.data(), content.data(), content.size()); + uint8_t* atomContent = chunkBuffer + atomInfo.offsetInSection; + ::memcpy(atomContent, content.data(), contentSize); + // Apply fixups to file buffer for (const Reference *ref : *atomInfo.atom) { uint32_t offset = ref->offsetInAtom(); uint64_t targetAddress = 0; if ( ref->target() != nullptr ) targetAddress = _writer.addressOfAtom(ref->target()); uint64_t fixupAddress = _writer.addressOfAtom(atomInfo.atom) + offset; - _platform.applyFixup(ref->kind(), ref->addend(), &buffer[offset], + this->applyFixup(ref->kind(), ref->addend(), &atomContent[offset], fixupAddress, targetAddress); } - for( uint8_t byte : buffer) { - out.write(byte); - } } } + + +void SectionChunk::applyFixup(Reference::Kind kind, uint64_t addend, + uint8_t* location, uint64_t fixupAddress, + uint64_t targetAddress) { + //fprintf(stderr, "applyFixup(kind=%s, addend=0x%0llX, " + // "fixupAddress=0x%0llX, targetAddress=0x%0llX\n", + // kindToString(kind).data(), addend, + // fixupAddress, targetAddress); + if ( ReferenceKind::isRipRel32(kind) ) { + // compute rip relative value and update. + int32_t* loc32 = reinterpret_cast<int32_t*>(location); + *loc32 = (targetAddress - (fixupAddress+4)) + addend; + } + else if ( kind == ReferenceKind::x86_64_pointer64 ) { + uint64_t* loc64 = reinterpret_cast<uint64_t*>(location); + *loc64 = targetAddress + addend; + } +} + + + //===----------------------------------------------------------------------===// // MachHeaderChunk //===----------------------------------------------------------------------===// -MachHeaderChunk::MachHeaderChunk(DarwinPlatform &platform, const File &file) { - // Let platform convert file info to mach-o cpu type and subtype. - platform.initializeMachHeader(file, _mh); +MachHeaderChunk::MachHeaderChunk(const WriterOptionsMachO &options, + const File &file) { + // Set up mach_header based on options + _mh.magic = MAGIC_64; + _mh.cputype = options.cpuType(); + _mh.cpusubtype = options.cpuSubtype(); + _mh.filetype = this->filetype(options.outputKind()); + _mh.ncmds = 0; + _mh.sizeofcmds = 0; + _mh.flags = 0; + _mh.reserved = 0; + _size = _mh.size(); } @@ -590,9 +629,8 @@ StringRef MachHeaderChunk::segmentName() const { return StringRef("__TEXT"); } -void MachHeaderChunk::write(raw_ostream &out) { - assert( out.tell() == _fileOffset); - _mh.write(out); +void MachHeaderChunk::write(uint8_t *chunkBuffer) { + _mh.copyTo(chunkBuffer); } const char* MachHeaderChunk::info() { @@ -607,6 +645,20 @@ uint64_t MachHeaderChunk::loadCommandsSize() { return _mh.sizeofcmds; } +uint32_t MachHeaderChunk::filetype(WriterOptionsMachO::OutputKind kind) { + switch ( kind ) { + case WriterOptionsMachO::outputDynamicExecutable: + return MH_EXECUTE; + case WriterOptionsMachO::outputDylib: + return MH_DYLIB; + case WriterOptionsMachO::outputBundle: + return MH_BUNDLE; + case WriterOptionsMachO::outputObjectFile: + return MH_OBJECT; + } + assert(0 && "file outputkind not supported"); +} + //===----------------------------------------------------------------------===// @@ -614,9 +666,9 @@ uint64_t MachHeaderChunk::loadCommandsSize() { //===----------------------------------------------------------------------===// LoadCommandsChunk::LoadCommandsChunk(MachHeaderChunk &mh, - DarwinPlatform& platform, + const WriterOptionsMachO &options, MachOWriter& writer) - : _mh(mh), _platform(platform), _writer(writer), + : _mh(mh), _options(options), _writer(writer), _linkEditSegment(nullptr), _symbolTableLoadCommand(nullptr), _entryPointLoadCommand(nullptr), _dyldInfoLoadCommand(nullptr) { } @@ -626,10 +678,12 @@ StringRef LoadCommandsChunk::segmentName() const { return StringRef("__TEXT"); } -void LoadCommandsChunk::write(raw_ostream &out) { - assert( out.tell() == _fileOffset); +void LoadCommandsChunk::write(uint8_t *chunkBuffer) { + uint8_t* p = chunkBuffer; for ( load_command* lc : _loadCmds ) { - lc->write(out); + assert( ((uintptr_t)p & 0x3) == 0); + lc->copyTo(p); + p += lc->cmdsize; } } @@ -660,7 +714,7 @@ uint32_t LoadCommandsChunk::permissionsFromSections( void LoadCommandsChunk::computeSize(const lld::File &file) { // Main executables have a __PAGEZERO segment. - uint64_t pageZeroSize = _platform.pageZeroSize(); + uint64_t pageZeroSize = _options.pageZeroSize(); if ( pageZeroSize != 0 ) { segment_command_64* pzSegCmd = segment_command_64::make(0); strcpy(pzSegCmd->segname, "__PAGEZERO"); @@ -741,10 +795,12 @@ void LoadCommandsChunk::computeSize(const lld::File &file) { _dyldInfoLoadCommand = dyld_info_command::make(); this->addLoadCommand(_dyldInfoLoadCommand); - // Add entry point load command - _entryPointLoadCommand = entry_point_command::make(); - this->addLoadCommand(_entryPointLoadCommand); - + // Add entry point load command to main executables + if (_options.outputKind() == WriterOptionsMachO::outputDynamicExecutable) { + _entryPointLoadCommand = entry_point_command::make(); + this->addLoadCommand(_entryPointLoadCommand); + } + // Compute total size. _size = _mh.loadCommandsSize(); } @@ -812,7 +868,7 @@ void LoadCommandsChunk::updateLoadCommandContent(const lld::File &file) { // Update entry point if ( _entryPointLoadCommand != nullptr ) { - const Atom *mainAtom = _platform.mainAtom(); + const Atom *mainAtom = _writer._mainAtom; assert(mainAtom != nullptr); uint32_t entryOffset = _writer.addressOfAtom(mainAtom) - _mh.address(); _entryPointLoadCommand->entryoff = entryOffset; @@ -844,10 +900,8 @@ StringRef LoadCommandPaddingChunk::segmentName() const { return StringRef("__TEXT"); } -void LoadCommandPaddingChunk::write(raw_ostream &out) { - assert( out.tell() == _fileOffset); +void LoadCommandPaddingChunk::write(uint8_t *chunkBuffer) { // Zero fill padding. - this->writeZeros(_size, out); } const char* LoadCommandPaddingChunk::info() { @@ -899,11 +953,8 @@ DyldInfoChunk::DyldInfoChunk(MachOWriter &writer) : _writer(writer) { } -void DyldInfoChunk::write(raw_ostream &out) { - assert( out.tell() == _fileOffset); - for ( uint8_t byte : _bytes ) { - out.write(byte); - } +void DyldInfoChunk::write(uint8_t *chunkBuffer) { + ::memcpy(chunkBuffer, &_bytes[0], _bytes.size()); } void DyldInfoChunk::append_byte(uint8_t b) { @@ -967,7 +1018,7 @@ void BindingInfoChunk::computeSize(const lld::File &file, const SharedLibraryAtom *shlTarget = dyn_cast<SharedLibraryAtom>(target); if ( shlTarget != nullptr ) { - assert(ref->kind() == ReferenceKind::pointer64); + assert(ref->kind() == ReferenceKind::x86_64_pointer64); targetName = shlTarget->name(); ordinal = 1; } @@ -1029,12 +1080,12 @@ const char* LazyBindingInfoChunk::info() { void LazyBindingInfoChunk::updateHelper(const DefinedAtom *lazyPointerAtom, uint32_t offset) { for (const Reference *ref : *lazyPointerAtom ) { - if ( ref->kind() != ReferenceKind::pointer64 ) + if ( ref->kind() != ReferenceKind::x86_64_pointer64 ) continue; const DefinedAtom *helperAtom = dyn_cast<DefinedAtom>(ref->target()); assert(helperAtom != nullptr); for (const Reference *href : *helperAtom ) { - if ( href->kind() == ReferenceKind::lazyImm ) { + if ( href->kind() == ReferenceKind::x86_64_lazyImm ) { (const_cast<Reference*>(href))->setAddend(offset); return; } @@ -1084,7 +1135,7 @@ void LazyBindingInfoChunk::computeSize(const lld::File &file, int flags = 0; StringRef name; for (const Reference *ref : *lazyPointerAtom ) { - if ( ref->kind() == ReferenceKind::lazyTarget ) { + if ( ref->kind() == ReferenceKind::x86_64_lazyTarget ) { const Atom *shlib = ref->target(); assert(shlib != nullptr); name = shlib->name(); @@ -1111,16 +1162,19 @@ SymbolTableChunk::SymbolTableChunk(SymbolStringsChunk& str) : _stringsChunk(str) { } -void SymbolTableChunk::write(raw_ostream &out) { - assert( out.tell() == _fileOffset); +void SymbolTableChunk::write(uint8_t *chunkBuffer) { + uint8_t *p = chunkBuffer; for ( nlist_64 &sym : _globalDefinedsymbols ) { - sym.write(out); + sym.copyTo(p); + p += sizeof(nlist_64); } for ( nlist_64 &sym : _localDefinedsymbols ) { - sym.write(out); + sym.copyTo(p); + p += sizeof(nlist_64); } for ( nlist_64 &sym : _undefinedsymbols ) { - sym.write(out); + sym.copyTo(p); + p += sizeof(nlist_64); } } @@ -1196,11 +1250,8 @@ SymbolStringsChunk::SymbolStringsChunk() { } -void SymbolStringsChunk::write(raw_ostream &out) { - assert( out.tell() == _fileOffset); - for ( char c : _strings ) { - out.write(c); - } +void SymbolStringsChunk::write(uint8_t *chunkBuffer) { + ::memcpy(chunkBuffer, &_strings[0], _strings.size()); } const char* SymbolStringsChunk::info() { @@ -1225,9 +1276,10 @@ uint32_t SymbolStringsChunk::stringIndex(StringRef str) { // MachOWriter //===----------------------------------------------------------------------===// -MachOWriter::MachOWriter(DarwinPlatform &platform) - : _platform(platform), _bindingInfo(nullptr), _lazyBindingInfo(nullptr), - _symbolTableChunk(nullptr), _stringsChunk(nullptr), +MachOWriter::MachOWriter(const WriterOptionsMachO &options) + : _options(options), _stubsPass(options), _cRuntimeFile(options), + _bindingInfo(nullptr), _lazyBindingInfo(nullptr), + _symbolTableChunk(nullptr), _stringsChunk(nullptr), _mainAtom(nullptr), _linkEditStartOffset(0), _linkEditStartAddress(0) { } @@ -1266,7 +1318,7 @@ void MachOWriter::createChunks(const lld::File &file) { DefinedAtom::ContentType type = atom->contentType(); auto pos = map.find(type); if ( pos == map.end() ) { - SectionChunk *chunk = SectionChunk::make(type, _platform, *this); + SectionChunk *chunk = SectionChunk::make(type, _options, *this); map[type] = chunk; chunk->appendAtom(atom); } @@ -1279,10 +1331,10 @@ void MachOWriter::createChunks(const lld::File &file) { // Make chunks in __TEXT for mach_header and load commands at start. - MachHeaderChunk *mhc = new MachHeaderChunk(_platform, file); + MachHeaderChunk *mhc = new MachHeaderChunk(_options, file); _chunks.push_back(mhc); - _loadCommandsChunk = new LoadCommandsChunk(*mhc, _platform, *this); + _loadCommandsChunk = new LoadCommandsChunk(*mhc, _options, *this); _chunks.push_back(_loadCommandsChunk); _paddingChunk = new LoadCommandPaddingChunk(*_loadCommandsChunk); @@ -1313,19 +1365,28 @@ void MachOWriter::addLinkEditChunk(LinkEditChunk *chunk) { void MachOWriter::buildAtomToAddressMap() { - DEBUG(llvm::dbgs() << "assign atom addresses:\n"); + DEBUG_WITH_TYPE("WriterMachO-layout", llvm::dbgs() + << "assign atom addresses:\n"); + const bool lookForMain = + (_options.outputKind() == WriterOptionsMachO::outputDynamicExecutable); for (SectionChunk *chunk : _sectionChunks ) { for (const SectionChunk::AtomInfo &info : chunk->atoms() ) { _atomToAddress[info.atom] = chunk->address() + info.offsetInSection; - DEBUG(llvm::dbgs() << " address=0x"; - llvm::dbgs().write_hex(_atomToAddress[info.atom]); - llvm::dbgs() << " atom=" << info.atom; - llvm::dbgs() << " name=" << info.atom->name() << "\n"); + if ( lookForMain + && (info.atom->contentType() == DefinedAtom::typeCode) + && (info.atom->size() != 0) + && info.atom->name().equals("_main") ) { + _mainAtom = info.atom; + } + DEBUG_WITH_TYPE("WriterMachO-layout", llvm::dbgs() + << " address=" + << llvm::format("0x%016X", _atomToAddress[info.atom]) + << " atom=" << info.atom + << " name=" << info.atom->name() << "\n"); } } } - //void MachOWriter::dump() { // for ( Chunk *chunk : _chunks ) { // fprintf(stderr, "size=0x%08llX, fileOffset=0x%08llX, address=0x%08llX %s\n", @@ -1334,9 +1395,10 @@ void MachOWriter::buildAtomToAddressMap() { //} void MachOWriter::assignFileOffsets() { - DEBUG(llvm::dbgs() << "assign file offsets:\n"); + DEBUG_WITH_TYPE("WriterMachO-layout", llvm::dbgs() + << "assign file offsets:\n"); uint64_t offset = 0; - uint64_t address = _platform.pageZeroSize(); + uint64_t address = _options.pageZeroSize(); for ( Chunk *chunk : _chunks ) { if ( chunk->segmentName().equals("__LINKEDIT") ) { _linkEditStartOffset = Chunk::alignTo(offset, 12); @@ -1348,7 +1410,8 @@ void MachOWriter::assignFileOffsets() { } void MachOWriter::assignLinkEditFileOffsets() { - DEBUG(llvm::dbgs() << "assign LINKEDIT file offsets:\n"); + DEBUG_WITH_TYPE("WriterMachO-layout", llvm::dbgs() + << "assign LINKEDIT file offsets:\n"); uint64_t offset = _linkEditStartOffset; uint64_t address = _linkEditStartAddress; for ( Chunk *chunk : _linkEditChunks ) { @@ -1373,7 +1436,7 @@ void MachOWriter::findSegment(StringRef segmentName, uint32_t *segIndex, const uint64_t kInvalidAddress = (uint64_t)(-1); StringRef lastSegName("__TEXT"); *segIndex = 0; - if ( _platform.pageZeroSize() != 0 ) { + if ( _options.pageZeroSize() != 0 ) { *segIndex = 1; } *segStartAddr = kInvalidAddress; @@ -1393,43 +1456,78 @@ void MachOWriter::findSegment(StringRef segmentName, uint32_t *segIndex, *segEndAddr = chunkEndAddr; } } - } } -void MachOWriter::zeroFill(int64_t amount, raw_ostream &out) { - for( int i=amount; i > 0; --i) - out.write('\0'); +// +// Creates a mach-o final linked image from the given atom graph and writes +// it to the supplied output stream. +// +error_code MachOWriter::writeFile(const lld::File &file, StringRef path) { + this->build(file); + +// FIXME: re-enable when FileOutputBuffer is in LLVMSupport.a +#if 0 + uint64_t totalSize = _chunks.back()->fileOffset() + _chunks.back()->size(); + + OwningPtr<llvm::FileOutputBuffer> buffer; + error_code ec = llvm::FileOutputBuffer::create(path, + totalSize, buffer, + llvm::FileOutputBuffer::F_executable); + if ( ec ) + return ec; + + DEBUG_WITH_TYPE("WriterMachO-layout", llvm::dbgs() << "writeFile:\n"); + for ( Chunk *chunk : _chunks ) { + DEBUG_WITH_TYPE("WriterMachO-layout", llvm::dbgs() + << " fileOffset=" + << llvm::format("0x%08X", chunk->fileOffset()) + << " chunk=" + << chunk->info() + << "\n"); + chunk->write(buffer->getBufferStart()+chunk->fileOffset()); + } + + return buffer->commit(); +#else + return error_code::success(); +#endif } -void MachOWriter::write(raw_ostream &out) { - for ( Chunk *chunk : _chunks ) { - if ( out.tell() != chunk->fileOffset() ) { - // Assume just alignment padding to start of next section. - assert( out.tell() < chunk->fileOffset() ); - uint64_t padding = chunk->fileOffset() - out.tell(); - chunk->writeZeros(padding, out); - } - chunk->write(out); - } +StubsPass *MachOWriter::stubPass() { + return &_stubsPass; +} + +GOTPass *MachOWriter::gotPass() { + return &_gotPass; } +void MachOWriter::addFiles(InputFiles &inputFiles) { + inputFiles.prependFile(_cRuntimeFile); +} -// -// Creates a mach-o final linked image from the given atom graph and writes -// it to the supplied output stream. -// -void writeExecutable(const lld::File &file, DarwinPlatform &platform, - raw_ostream &out) { - MachOWriter writer(platform); - writer.build(file); - writer.write(out); + +} // namespace mach_o + +Writer* createWriterMachO(const WriterOptionsMachO &options) { + return new lld::mach_o::MachOWriter(options); +} + +WriterOptionsMachO::WriterOptionsMachO() + : _outputkind(outputDynamicExecutable), + _archName("x86_64"), + _architecture(arch_x86_64), + _pageZeroSize(0x10000000), + _cpuType(mach_o::CPU_TYPE_X86_64), + _cpuSubtype(mach_o::CPU_SUBTYPE_X86_64_ALL), + _noTextRelocations(true) { } +WriterOptionsMachO::~WriterOptionsMachO() { +} -} // namespace darwin } // namespace lld diff --git a/lld/lib/ReaderWriter/Native/CMakeLists.txt b/lld/lib/ReaderWriter/Native/CMakeLists.txt new file mode 100644 index 00000000000..8862750aea0 --- /dev/null +++ b/lld/lib/ReaderWriter/Native/CMakeLists.txt @@ -0,0 +1,4 @@ +add_lld_library(lldNative + ReaderNative.cpp + WriterNative.cpp + ) diff --git a/lld/lib/Core/NativeFileFormat.h b/lld/lib/ReaderWriter/Native/NativeFileFormat.h index f4e495246a5..43731f18a60 100644 --- a/lld/lib/Core/NativeFileFormat.h +++ b/lld/lib/ReaderWriter/Native/NativeFileFormat.h @@ -1,4 +1,4 @@ -//===- Core/NativeFileFormat.h - Describes native object file -------------===// +//===- lib/ReaderWriter/Native/NativeFileFormat.h -------------------------===// // // The LLVM Linker // @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLD_CORE_NATIVE_FILE_FORMAT_H_ -#define LLD_CORE_NATIVE_FILE_FORMAT_H_ +#ifndef LLD_READER_WRITER_NATIVE_FILE_FORMAT_H_ +#define LLD_READER_WRITER_NATIVE_FILE_FORMAT_H_ #include "llvm/Support/DataTypes.h" @@ -240,4 +240,4 @@ struct NativeReferenceIvarsV2 { } // namespace lld -#endif // LLD_CORE_NATIVE_FILE_FORMAT_H_ +#endif // LLD_READER_WRITER_NATIVE_FILE_FORMAT_H_ diff --git a/lld/lib/Core/NativeReader.cpp b/lld/lib/ReaderWriter/Native/ReaderNative.cpp index 29086148ebc..b617a4fb9ae 100644 --- a/lld/lib/Core/NativeReader.cpp +++ b/lld/lib/ReaderWriter/Native/ReaderNative.cpp @@ -1,4 +1,4 @@ -//===- Core/NativeReader.cpp - reads native object file ------------------===// +//===- lib/ReaderWriter/Native/ReaderNative.cpp ---------------------------===// // // The LLVM Linker // @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "NativeFileFormat.h" +#include "lld/ReaderWriter/ReaderNative.h" #include "lld/Core/Atom.h" #include "lld/Core/Error.h" @@ -16,16 +16,22 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" + +#include "NativeFileFormat.h" #include <vector> #include <memory> namespace lld { +namespace native { // forward reference -class NativeFile; +class File; // // An object of this class is instantied for each NativeDefinedAtomIvarsV1 @@ -33,11 +39,11 @@ class NativeFile; // class NativeDefinedAtomV1 : public DefinedAtom { public: - NativeDefinedAtomV1(const NativeFile& f, + NativeDefinedAtomV1(const File& f, const NativeDefinedAtomIvarsV1* ivarData) : _file(&f), _ivarData(ivarData) { } - virtual const class File& file() const; + virtual const class lld::File& file() const; virtual uint64_t ordinal() const; @@ -103,8 +109,8 @@ public: private: const NativeAtomAttributesV1& attributes() const; - const NativeFile* _file; - const NativeDefinedAtomIvarsV1* _ivarData; + const File *_file; + const NativeDefinedAtomIvarsV1 *_ivarData; }; @@ -115,11 +121,11 @@ private: // class NativeUndefinedAtomV1 : public UndefinedAtom { public: - NativeUndefinedAtomV1(const NativeFile& f, + NativeUndefinedAtomV1(const File& f, const NativeUndefinedAtomIvarsV1* ivarData) : _file(&f), _ivarData(ivarData) { } - virtual const File& file() const; + virtual const lld::File& file() const; virtual StringRef name() const; virtual CanBeNull canBeNull() const { @@ -128,8 +134,8 @@ public: private: - const NativeFile* _file; - const NativeUndefinedAtomIvarsV1* _ivarData; + const File *_file; + const NativeUndefinedAtomIvarsV1 *_ivarData; }; @@ -139,11 +145,11 @@ private: // class NativeSharedLibraryAtomV1 : public SharedLibraryAtom { public: - NativeSharedLibraryAtomV1(const NativeFile& f, + NativeSharedLibraryAtomV1(const File& f, const NativeSharedLibraryAtomIvarsV1* ivarData) : _file(&f), _ivarData(ivarData) { } - virtual const File& file() const; + virtual const lld::File& file() const; virtual StringRef name() const; virtual StringRef loadName() const; @@ -152,8 +158,8 @@ public: } private: - const NativeFile* _file; - const NativeSharedLibraryAtomIvarsV1* _ivarData; + const File *_file; + const NativeSharedLibraryAtomIvarsV1 *_ivarData; }; @@ -163,11 +169,11 @@ private: // class NativeAbsoluteAtomV1 : public AbsoluteAtom { public: - NativeAbsoluteAtomV1(const NativeFile& f, + NativeAbsoluteAtomV1(const File& f, const NativeAbsoluteAtomIvarsV1* ivarData) : _file(&f), _ivarData(ivarData) { } - virtual const File& file() const; + virtual const lld::File& file() const; virtual StringRef name() const; virtual uint64_t value() const { @@ -175,8 +181,8 @@ public: } private: - const NativeFile* _file; - const NativeAbsoluteAtomIvarsV1* _ivarData; + const File *_file; + const NativeAbsoluteAtomIvarsV1 *_ivarData; }; @@ -187,7 +193,7 @@ private: // class NativeReferenceV1 : public Reference { public: - NativeReferenceV1(const NativeFile& f, + NativeReferenceV1(const File& f, const NativeReferenceIvarsV1* ivarData) : _file(&f), _ivarData(ivarData) { } @@ -216,8 +222,8 @@ private: memcpy(niv, _ivarData, sizeof(NativeReferenceIvarsV1)); } - const NativeFile* _file; - const NativeReferenceIvarsV1* _ivarData; + const File *_file; + const NativeReferenceIvarsV1 *_ivarData; }; @@ -225,14 +231,14 @@ private: // // lld::File object for native llvm object file // -class NativeFile : public File { +class File : public lld::File { public: /// Instantiates a File object from a native object file. Ownership /// of the MemoryBuffer is transfered to the resulting File object. - static error_code make(std::unique_ptr<llvm::MemoryBuffer> mb, + static error_code make(std::unique_ptr<llvm::MemoryBuffer> &mb, StringRef path, - std::unique_ptr<File> &result) { + std::vector<std::unique_ptr<lld::File>> &result) { const uint8_t* const base = reinterpret_cast<const uint8_t*>(mb->getBufferStart()); const NativeFileHeader* const header = @@ -248,8 +254,14 @@ public: if ( header->fileSize > fileSize ) return make_error_code(native_reader_error::file_too_short); + DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs() + << " Native File Header:" + << " fileSize=" << header->fileSize + << " chunkCount=" << header->chunkCount + << "\n"); + // instantiate NativeFile object and add values to it as found - std::unique_ptr<NativeFile> file(new NativeFile(std::move(mb), path)); + std::unique_ptr<File> file(new File(std::move(mb), path)); // process each chunk for(uint32_t i=0; i < header->chunkCount; ++i) { @@ -298,14 +310,32 @@ public: if ( ec ) { return ec; } - // TO DO: validate enough chunks were used + } + // TO DO: validate enough chunks were used + + DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs() + << " ReaderNative DefinedAtoms:\n"); + for (const DefinedAtom *a : file->defined() ) { + DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs() + << llvm::format(" 0x%09lX", a) + << ", name=" << a->name() + << ", size=" << a->size() + << "\n"); + for (const Reference *r : *a ) { + DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs() + << " offset=" + << llvm::format("0x%03X", r->offsetInAtom()) + << ", kind=" << r->kind() + << ", target=" << r->target() + << "\n"); + } } - result.reset(file.release()); + result.push_back(std::move(file)); return make_error_code(native_reader_error::success); } - virtual ~NativeFile() { + virtual ~File() { // _buffer is automatically deleted because of OwningPtr<> // All other ivar pointers are pointers into the MemoryBuffer, except @@ -371,14 +401,26 @@ private: this->_definedAtoms._arrayEnd = atomsEnd; this->_definedAtoms._elementSize = atomSize; this->_definedAtoms._elementCount = chunk->elementCount; + DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs() + << " chunk DefinedAtomsV1: " + << " count=" << chunk->elementCount + << " chunkSize=" << chunk->fileSize + << "\n"); return make_error_code(native_reader_error::success); } + + // set up pointers to attributes array error_code processAttributesV1(const uint8_t *base, const NativeChunk *chunk) { this->_attributes = base + chunk->fileOffset; this->_attributesMaxOffset = chunk->fileSize; + DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs() + << " chunk AttributesV1: " + << " count=" << chunk->elementCount + << " chunkSize=" << chunk->fileSize + << "\n"); return make_error_code(native_reader_error::success); } @@ -409,6 +451,11 @@ private: this->_undefinedAtoms._arrayEnd = atomsEnd; this->_undefinedAtoms._elementSize = atomSize; this->_undefinedAtoms._elementCount = chunk->elementCount; + DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs() + << " chunk UndefinedAtomsV1:" + << " count=" << chunk->elementCount + << " chunkSize=" << chunk->fileSize + << "\n"); return make_error_code(native_reader_error::success); } @@ -440,6 +487,11 @@ private: this->_sharedLibraryAtoms._arrayEnd = atomsEnd; this->_sharedLibraryAtoms._elementSize = atomSize; this->_sharedLibraryAtoms._elementCount = chunk->elementCount; + DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs() + << " chunk SharedLibraryAtomsV1:" + << " count=" << chunk->elementCount + << " chunkSize=" << chunk->fileSize + << "\n"); return make_error_code(native_reader_error::success); } @@ -471,6 +523,11 @@ private: this->_absoluteAtoms._arrayEnd = atomsEnd; this->_absoluteAtoms._elementSize = atomSize; this->_absoluteAtoms._elementCount = chunk->elementCount; + DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs() + << " chunk AbsoluteAtomsV1: " + << " count=" << chunk->elementCount + << " chunkSize=" << chunk->fileSize + << "\n"); return make_error_code(native_reader_error::success); } @@ -506,6 +563,11 @@ private: this->_references.arrayEnd = refsEnd; this->_references.elementSize = refSize; this->_references.elementCount = chunk->elementCount; + DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs() + << " chunk ReferencesV1: " + << " count=" << chunk->elementCount + << " chunkSize=" << chunk->fileSize + << "\n"); return make_error_code(native_reader_error::success); } @@ -550,6 +612,11 @@ private: } return make_error_code(native_reader_error::file_malformed); } + DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs() + << " chunk Targets Table: " + << " count=" << chunk->elementCount + << " chunkSize=" << chunk->fileSize + << "\n"); return make_error_code(native_reader_error::success); } @@ -560,6 +627,11 @@ private: this->_addends = reinterpret_cast<const Reference::Addend*> (base + chunk->fileOffset); this->_addendsMaxIndex = chunk->elementCount; + DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs() + << " chunk Addends: " + << " count=" << chunk->elementCount + << " chunkSize=" << chunk->fileSize + << "\n"); return make_error_code(native_reader_error::success); } @@ -568,6 +640,10 @@ private: const NativeChunk *chunk) { this->_strings = reinterpret_cast<const char*>(base + chunk->fileOffset); this->_stringsMaxOffset = chunk->fileSize; + DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs() + << " chunk Strings: " + << " chunkSize=" << chunk->fileSize + << "\n"); return make_error_code(native_reader_error::success); } @@ -576,6 +652,10 @@ private: const NativeChunk *chunk) { this->_contentStart = base + chunk->fileOffset; this->_contentEnd = base + chunk->fileOffset + chunk->fileSize; + DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs() + << " chunk content: " + << " chunkSize=" << chunk->fileSize + << "\n"); return make_error_code(native_reader_error::success); } @@ -624,9 +704,9 @@ private: // private constructor, only called by make() - NativeFile(std::unique_ptr<llvm::MemoryBuffer> mb, StringRef path) : - File(path), - _buffer(std::move(mb)), // NativeFile now takes ownership of buffer + File(std::unique_ptr<llvm::MemoryBuffer> mb, StringRef path) : + lld::File(path), + _buffer(std::move(mb)), // Reader now takes ownership of buffer _header(nullptr), _targetsTable(nullptr), _targetsTableCount(0), @@ -701,7 +781,7 @@ private: }; -inline const class File& NativeDefinedAtomV1::file() const { +inline const class lld::File& NativeDefinedAtomV1::file() const { return *_file; } @@ -754,7 +834,7 @@ void NativeDefinedAtomV1::incrementIterator(const void*& it) const { it = reinterpret_cast<const void*>(index); } -inline const class File& NativeUndefinedAtomV1::file() const { +inline const class lld::File& NativeUndefinedAtomV1::file() const { return *_file; } @@ -765,7 +845,7 @@ inline StringRef NativeUndefinedAtomV1::name() const { -inline const class File& NativeSharedLibraryAtomV1::file() const { +inline const class lld::File& NativeSharedLibraryAtomV1::file() const { return *_file; } @@ -779,7 +859,7 @@ inline StringRef NativeSharedLibraryAtomV1::loadName() const { -inline const class File& NativeAbsoluteAtomV1::file() const { +inline const class lld::File& NativeAbsoluteAtomV1::file() const { return *_file; } @@ -806,34 +886,44 @@ inline void NativeReferenceV1::setTarget(const Atom* newAtom) { } inline void NativeReferenceV1::setAddend(Addend a) { + // Do nothing if addend value is not being changed. + if ( this->addend() == a ) + return; assert(0 && "setAddend() not supported"); } -// -// Instantiate an lld::File from the given native object file buffer -// -error_code parseNativeObjectFile(std::unique_ptr<llvm::MemoryBuffer> mb, - StringRef path, - std::unique_ptr<File> &result) { - return NativeFile::make(std::move(mb), path, result); -} +class Reader : public lld::Reader { +public: + Reader(const ReaderOptionsNative &options) : _options(options) { + } + + virtual error_code parseFile(std::unique_ptr<MemoryBuffer> mb, + std::vector<std::unique_ptr<lld::File>> &result) { + return File::make(mb, mb->getBufferIdentifier(), result); + } +private: + const ReaderOptionsNative &_options; +}; -// -// Instantiate an lld::File from the given native object file path -// -error_code parseNativeObjectFileOrSTDIN(StringRef path, - std::unique_ptr<File>& result) { - OwningPtr<llvm::MemoryBuffer> mb; - error_code ec = llvm::MemoryBuffer::getFileOrSTDIN(path, mb); - if ( ec ) - return ec; - - return parseNativeObjectFile( std::unique_ptr<llvm::MemoryBuffer>(mb.take()) - , path - , result); + +} // namespace native + +Reader* createReaderNative(const ReaderOptionsNative &options) { + return new lld::native::Reader(options); +} + +ReaderOptionsNative::ReaderOptionsNative() { } +ReaderOptionsNative::~ReaderOptionsNative() { +} + + } // namespace lld + + + + diff --git a/lld/lib/Core/NativeWriter.cpp b/lld/lib/ReaderWriter/Native/WriterNative.cpp index 5c7fc05d03e..e3dc04351de 100644 --- a/lld/lib/Core/NativeWriter.cpp +++ b/lld/lib/ReaderWriter/Native/WriterNative.cpp @@ -1,4 +1,4 @@ -//===- Core/NativeWriter.cpp - Creates a native object file ---------------===// +//===- lib/ReaderWriter/Native/WriterNative.cpp ---------------------------===// // // The LLVM Linker // @@ -7,26 +7,31 @@ // //===----------------------------------------------------------------------===// -#include "lld/Core/NativeWriter.h" -#include "NativeFileFormat.h" +#include "lld/ReaderWriter/WriterNative.h" #include "lld/Core/File.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/system_error.h" + +#include "NativeFileFormat.h" #include <vector> namespace lld { - +namespace native { /// /// Class for writing native object files. /// -class NativeWriter { +class Writer : public lld::Writer { public: - /// construct writer for an lld::File object - NativeWriter(const lld::File& file) : _file(file) { + Writer(const WriterOptionsNative &options) : _options(options) { + } + + virtual error_code writeFile(const lld::File &file, StringRef outPath) { // reserve first byte for unnamed atoms _stringPool.push_back('\0'); // visit all atoms @@ -43,12 +48,25 @@ public: this->addIVarsForAbsoluteAtom(*absAtom); } - - // construct file header based on atom information accumulated - makeHeader(); + this->makeHeader(); + + std::string errorInfo; + llvm::raw_fd_ostream out(outPath.data(), errorInfo, + llvm::raw_fd_ostream::F_Binary); + if (!errorInfo.empty()) + return error_code::success(); // FIXME + + this->write(out); + + return error_code::success(); + } + + virtual ~Writer() { } +private: + // write the lld::File in native format to the specified stream void write(raw_ostream &out) { assert( out.tell() == 0 ); @@ -113,8 +131,6 @@ public: } } -private: - void addIVarsForDefinedAtom(const DefinedAtom& atom) { _definedAtomIndex[&atom] = _definedAtomIvars.size(); NativeDefinedAtomIvarsV1 ivar; @@ -426,7 +442,7 @@ private: if ( pos != _targetsTableIndex.end() ) { return pos->second; } - uint32_t result = _targetsTableIndex.size(); + uint32_t result = _targetsTableIndex.size(); _targetsTableIndex[target] = result; return result; } @@ -507,7 +523,7 @@ private: typedef llvm::DenseMap<const Atom*, uint32_t> TargetToIndex; typedef llvm::DenseMap<Reference::Addend, uint32_t> AddendToIndex; - const lld::File& _file; + const WriterOptionsNative &_options; NativeFileHeader* _headerBuffer; size_t _headerBufferSize; std::vector<char> _stringPool; @@ -529,27 +545,19 @@ private: }; +} // namespace native +Writer* createWriterNative(const WriterOptionsNative &options) { + return new lld::native::Writer(options); +} - -/// writeNativeObjectFile - writes the lld::File object in native object -/// file format to the specified stream. -int writeNativeObjectFile(const File &file, raw_ostream &out) { - NativeWriter writer(file); - writer.write(out); - return 0; +WriterOptionsNative::WriterOptionsNative() { } -/// writeNativeObjectFile - writes the lld::File object in native object -/// file format to the specified file path. -int writeNativeObjectFile(const File &file, StringRef path) { - std::string errorInfo; - llvm::raw_fd_ostream out( path.data() - , errorInfo - , llvm::raw_fd_ostream::F_Binary); - if (!errorInfo.empty()) - return -1; - return writeNativeObjectFile(file, out); +WriterOptionsNative::~WriterOptionsNative() { } + } // namespace lld + + diff --git a/lld/lib/ReaderWriter/PECOFF/CMakeLists.txt b/lld/lib/ReaderWriter/PECOFF/CMakeLists.txt new file mode 100644 index 00000000000..a08b5ec4bfb --- /dev/null +++ b/lld/lib/ReaderWriter/PECOFF/CMakeLists.txt @@ -0,0 +1,4 @@ +add_lld_library(lldPECOFF + ReaderCOFF.cpp + WriterPECOFF.cpp + ) diff --git a/lld/lib/Reader/COFFReader.cpp b/lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp index 3df6f73f2a9..a43c8380c28 100644 --- a/lld/lib/Reader/COFFReader.cpp +++ b/lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp @@ -1,4 +1,4 @@ -//===- COFFReader.h - PECOFF Object File Reader ---------------------------===// +//===- lib/ReaderWriter/PECOFF/ReaderCOFF.cpp -----------------------------===// // // The LLVM Linker // @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "lld/Reader/Reader.h" +#include "lld/ReaderWriter/ReaderPECOFF.h" #include "lld/Core/File.h" #include "llvm/ADT/ArrayRef.h" @@ -199,9 +199,9 @@ private: llvm::ArrayRef<uint8_t> Data; }; -class COFFReader : public File { +class FileCOFF : public File { public: - COFFReader(std::unique_ptr<llvm::MemoryBuffer> MB, llvm::error_code &EC) + FileCOFF(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); @@ -331,15 +331,15 @@ public: 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; } @@ -353,12 +353,32 @@ private: 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; + + +class ReaderCOFF : public Reader { +public: + ReaderCOFF(const ReaderOptionsPECOFF &options) : _options(options) { + } + + error_code parseFile(std::unique_ptr<MemoryBuffer> mb, + std::vector<std::unique_ptr<File>> &result) { + llvm::error_code ec; + std::unique_ptr<File> f(new FileCOFF(std::move(mb), ec)); + if (ec) { + return ec; + } + + result.push_back(std::move(f)); + return error_code::success(); + } +private: + const ReaderOptionsPECOFF &_options; +}; + + + +Reader* createReaderPECOFF(const ReaderOptionsPECOFF &options) { + return new ReaderCOFF(options); } + + diff --git a/lld/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp b/lld/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp new file mode 100644 index 00000000000..8fec44e777b --- /dev/null +++ b/lld/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp @@ -0,0 +1,35 @@ +//===- lib/ReaderWriter/PECOFF/WriterPECOFF.cpp ---------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/ReaderWriter/WriterPECOFF.h" + +#include "llvm/Support/Debug.h" + + +namespace lld { +namespace pe_coff { + +// define PE/COFF writer class here + + +} // namespace pe_coff + +Writer* createWriterPECOFF(const WriterOptionsPECOFF &options) { + assert(0 && "PE/COFF support not implemented yet"); + return nullptr; +} + +WriterOptionsPECOFF::WriterOptionsPECOFF() { +} + +WriterOptionsPECOFF::~WriterOptionsPECOFF() { +} + +} // namespace lld + diff --git a/lld/lib/ReaderWriter/Reader.cpp b/lld/lib/ReaderWriter/Reader.cpp new file mode 100644 index 00000000000..f4395e8ff38 --- /dev/null +++ b/lld/lib/ReaderWriter/Reader.cpp @@ -0,0 +1,42 @@ +//===- lib/ReaderWriter/Reader.cpp ----------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/ReaderWriter/Reader.h" + +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/system_error.h" + + +namespace lld { + +Reader::Reader() { +} + +Reader::~Reader() { +} + +error_code Reader::readFile(StringRef path, + std::vector<std::unique_ptr<File>> &result) { + OwningPtr<llvm::MemoryBuffer> opmb; + if ( error_code ec = llvm::MemoryBuffer::getFileOrSTDIN(path, opmb) ) + return ec; + + std::unique_ptr<MemoryBuffer> mb(opmb.take()); + return this->parseFile(std::move(mb), result); +} + + + +ReaderOptions::ReaderOptions() { +} + +} // namespace lld + diff --git a/lld/lib/Core/Platform.cpp b/lld/lib/ReaderWriter/Writer.cpp index 430668d1200..93dbcf5f967 100644 --- a/lld/lib/Core/Platform.cpp +++ b/lld/lib/ReaderWriter/Writer.cpp @@ -1,4 +1,4 @@ -//===- Core/Platform.cpp - Base class ------------------------------------===// +//===- lib/ReaderWriter/Writer.cpp ----------------------------------------===// // // The LLVM Linker // @@ -7,13 +7,19 @@ // //===----------------------------------------------------------------------===// -#include "lld/Core/Platform.h" +#include "lld/ReaderWriter/Writer.h" -namespace lld { -Platform::Platform() {} +namespace lld { -Platform::~Platform() {} +Writer::Writer() { +} +Writer::~Writer() { +} +WriterOptions::WriterOptions() { } + +} // namespace lld + diff --git a/lld/lib/ReaderWriter/YAML/CMakeLists.txt b/lld/lib/ReaderWriter/YAML/CMakeLists.txt new file mode 100644 index 00000000000..ecd07030cb4 --- /dev/null +++ b/lld/lib/ReaderWriter/YAML/CMakeLists.txt @@ -0,0 +1,5 @@ +add_lld_library(lldYAML + YamlKeyValues.cpp + ReaderYAML.cpp + WriterYAML.cpp + ) diff --git a/lld/lib/Core/YamlReader.cpp b/lld/lib/ReaderWriter/YAML/ReaderYAML.cpp index 87f1e142355..8da77713698 100644 --- a/lld/lib/Core/YamlReader.cpp +++ b/lld/lib/ReaderWriter/YAML/ReaderYAML.cpp @@ -1,4 +1,4 @@ -//===- Core/YamlReader.cpp - Reads YAML encode object files ---------------===// +//===- lib/ReaderWriter/YAML/ReaderYAML.cpp - Reads YAML object files -----===// // // The LLVM Linker // @@ -7,15 +7,14 @@ // //===----------------------------------------------------------------------===// -#include "lld/Core/YamlReader.h" -#include "YamlKeyValues.h" -#include "lld/Core/Atom.h" +#include "lld/ReaderWriter/ReaderYAML.h" + #include "lld/Core/AbsoluteAtom.h" +#include "lld/Core/ArchiveLibraryFile.h" +#include "lld/Core/Atom.h" #include "lld/Core/Error.h" #include "lld/Core/File.h" -#include "lld/Core/ArchiveLibraryFile.h" #include "lld/Core/LLVM.h" -#include "lld/Core/Platform.h" #include "lld/Core/Reference.h" #include "lld/Core/SharedLibraryAtom.h" #include "lld/Core/UndefinedAtom.h" @@ -26,17 +25,19 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/DataTypes.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/system_error.h" #include "llvm/Support/YAMLParser.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/Debug.h" #include <cstring> #include <vector> +#include "YamlKeyValues.h" + namespace lld { namespace yaml { @@ -536,7 +537,7 @@ const File *YAMLFile::find(StringRef name, bool dataSymbolOnly) const { /// class YAMLState { public: - YAMLState(Platform &platform, llvm::yaml::Stream *s, YAMLFile *f); + YAMLState(const ReaderOptionsYAML &opts, llvm::yaml::Stream *s, YAMLFile *f); void parse(llvm::yaml::Node *node, StringRef keyword, llvm::yaml::Node *keywordNode=nullptr); @@ -605,7 +606,7 @@ private: static const Transistion _s_transistions[]; - Platform &_platform; + const ReaderOptionsYAML &_options; error_code _error; llvm::yaml::Stream *_stream; YAMLFile *_file; @@ -685,8 +686,9 @@ const YAMLState::Transistion YAMLState::_s_transistions[] = { -YAMLState::YAMLState(Platform &platform, Stream *stream, YAMLFile *file) - : _platform(platform) +YAMLState::YAMLState(const ReaderOptionsYAML &opts, Stream *stream, + YAMLFile *file) + : _options(opts) , _error(make_error_code(yaml_reader_error::success)) , _stream(stream) , _file(file) @@ -870,7 +872,7 @@ const char* YAMLState::stateName(State s) { void YAMLState::moveToState(State newState) { if ( newState == _state ) return; - DEBUG(llvm::dbgs() << "moveToState(" << stateName(newState) + DEBUG_WITH_TYPE("objtxt", llvm::dbgs() << "moveToState(" << stateName(newState) << "), _state=" << stateName(_state) << "\n"); if ( newState == inArch ) { @@ -896,7 +898,8 @@ void YAMLState::moveToState(State newState) { void YAMLState::returnToState(State prevState, Node *node) { if ( prevState == _state ) return; - DEBUG(llvm::dbgs() << "returnToState(" << stateName(prevState) + DEBUG_WITH_TYPE("objtxt", llvm::dbgs() + << "returnToState(" << stateName(prevState) << "), _state=" << stateName(_state) << "\n"); // If done with an atom, instantiate an object for it. if ( (_state == inAtom) && (prevState == inAtoms) ) @@ -913,9 +916,9 @@ void YAMLState::returnToState(State prevState, Node *node) { StringRef YAMLState::extractString(ScalarNode *node) { llvm::SmallString<32> storage; StringRef str = node->getValue(storage); - if ( str.data() == storage.begin() ) { + //if ( str.data() == storage.begin() ) { str = _file->copyString(str); - } + //} return str; } @@ -1056,7 +1059,7 @@ void YAMLState::parseFixUpOffset(ScalarNode *node) { void YAMLState::parseFixUpKind(ScalarNode *node) { llvm::SmallString<32> storage; - _ref._kind = _platform.kindFromString(node->getValue(storage)); + _ref._kind = _options.kindFromString(node->getValue(storage)); _hasDefinedAtomAttributes = true; } @@ -1116,7 +1119,7 @@ void YAMLState::parseAtomValue(ScalarNode *node) { // void YAMLState::parse(Node *node, StringRef keyword, Node *keywordNode) { using namespace llvm::yaml; - DEBUG(llvm::dbgs() << "parse(" << keyword << "), _state=" + DEBUG_WITH_TYPE("objtxt", llvm::dbgs() << "parse(" << keyword << "), _state=" << stateName(_state) << "\n"); if ( _error ) return; @@ -1196,17 +1199,17 @@ void YAMLState::parse(Node *node, StringRef keyword, Node *keywordNode) { /// parseObjectText - Parse the specified YAML formatted MemoryBuffer /// into lld::File object(s) and append each to the specified vector<File*>. -error_code parseObjectText( llvm::MemoryBuffer *mb - , Platform& platform - , std::vector<std::unique_ptr<const File>> &result) { +error_code parseFile(std::unique_ptr<MemoryBuffer> &mb, + const ReaderOptionsYAML &options, + std::vector<std::unique_ptr<File>> &result) { llvm::SourceMgr srcMgr; llvm::yaml::Stream stream(mb->getBuffer(), srcMgr); for (llvm::yaml::Document &d : stream) { - std::unique_ptr<YAMLFile> curFile(new YAMLFile); + std::unique_ptr<yaml::YAMLFile> curFile(new yaml::YAMLFile); if (llvm::isa<llvm::yaml::NullNode>(d.getRoot())) continue; // Empty files are allowed. - YAMLState yamlState(platform, &stream, curFile.get()); + yaml::YAMLState yamlState(options, &stream, curFile.get()); yamlState.parse(d.getRoot(), StringRef("<root>")); if ( stream.failed() ) @@ -1225,19 +1228,37 @@ error_code parseObjectText( llvm::MemoryBuffer *mb -// -// Fill in vector<File*> from path to input text file. -// -error_code -parseObjectTextFileOrSTDIN( StringRef path - , Platform& platform - , std::vector<std::unique_ptr<const File>>& result) { - OwningPtr<llvm::MemoryBuffer> mb; - if (error_code ec = llvm::MemoryBuffer::getFileOrSTDIN(path, mb)) - return ec; - - return parseObjectText(mb.take(), platform, result); +} // namespace yaml + + + +class ReaderYAML: public Reader { +public: + ReaderYAML(const ReaderOptionsYAML &options) : _options(options) { + } + + error_code parseFile(std::unique_ptr<MemoryBuffer> mb, + std::vector<std::unique_ptr<File>> &result) { + return lld::yaml::parseFile(mb, _options, result); + } + +private: + const ReaderOptionsYAML &_options; +}; + + + +Reader* createReaderYAML(const ReaderOptionsYAML &options) { + return new ReaderYAML(options); } -} // namespace yaml +ReaderOptionsYAML::ReaderOptionsYAML() { +} + +ReaderOptionsYAML::~ReaderOptionsYAML() { +} + + + + } // namespace lld diff --git a/lld/lib/Core/YamlWriter.cpp b/lld/lib/ReaderWriter/YAML/WriterYAML.cpp index f3b348282b8..7b69f7822f4 100644 --- a/lld/lib/Core/YamlWriter.cpp +++ b/lld/lib/ReaderWriter/YAML/WriterYAML.cpp @@ -1,4 +1,4 @@ -//===- Core/YamlWriter.cpp - Writes YAML ----------------------------------===// +//===- lib/ReaderWriter/YAML/WriterYAML.cpp - Writes YAML object files ----===// // // The LLVM Linker // @@ -7,11 +7,10 @@ // //===----------------------------------------------------------------------===// -#include "lld/Core/YamlWriter.h" -#include "YamlKeyValues.h" +#include "lld/ReaderWriter/WriterYAML.h" + #include "lld/Core/Atom.h" #include "lld/Core/File.h" -#include "lld/Core/Platform.h" #include "lld/Core/Reference.h" #include "llvm/ADT/ArrayRef.h" @@ -25,12 +24,13 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" +#include "YamlKeyValues.h" + #include <vector> namespace lld { namespace yaml { -namespace { /// /// In most cases, atoms names are unambiguous, so references can just /// use the atom name as the target (e.g. target: foo). But in a few @@ -125,8 +125,9 @@ private: /// class AtomWriter { public: - AtomWriter(const File& file, Platform& platform, RefNameBuilder& rnb) - : _file(file), _platform(platform), _rnb(rnb), _firstAtom(true) { } + AtomWriter(const File& file, const WriterOptionsYAML &options, + RefNameBuilder& rnb) + : _file(file), _options(options), _rnb(rnb), _firstAtom(true) { } void write(raw_ostream &out) { @@ -295,7 +296,7 @@ public: out << " " << "kind:" << spacePadding(strlen("kind")) - << _platform.kindToString(ref->kind()) + << _options.kindToString(ref->kind()) << "\n"; const Atom* target = ref->target(); if (target != nullptr) { @@ -436,28 +437,62 @@ private: return 'A' + nibble - 0x0A; } - const File& _file; - Platform& _platform; - RefNameBuilder& _rnb; - bool _firstAtom; + const File &_file; + const WriterOptionsYAML &_options; + RefNameBuilder &_rnb; + bool _firstAtom; }; -} // anonymous namespace -/// -/// writeObjectText - writes the lld::File object as in YAML -/// format to the specified stream. -/// -void writeObjectText(const File &file, Platform &platform, raw_ostream &out) { - // Figure what ref-name labels are needed - RefNameBuilder rnb(file); +class Writer : public lld::Writer { +public: + Writer(const WriterOptionsYAML &options) : _options(options) { + } + + virtual error_code writeFile(const lld::File &file, StringRef path) { + // Create stream to path. + std::string errorInfo; + llvm::raw_fd_ostream out(path.data(), errorInfo); + if (!errorInfo.empty()) + return llvm::make_error_code(llvm::errc::no_such_file_or_directory); + + // Figure what ref-name labels are needed. + RefNameBuilder rnb(file); + + // Write out all atoms. + AtomWriter writer(file, _options, rnb); + writer.write(out); + return error_code::success(); + } + + virtual StubsPass *stubPass() { + return _options.stubPass(); + } + + virtual GOTPass *gotPass() { + return _options.gotPass(); + } + + +private: + const WriterOptionsYAML &_options; +}; - // Write out all atoms - AtomWriter writer(file, platform, rnb); - writer.write(out); -} } // namespace yaml + + +Writer* createWriterYAML(const WriterOptionsYAML &options) { + return new lld::yaml::Writer(options); +} + +WriterOptionsYAML::WriterOptionsYAML() { +} + +WriterOptionsYAML::~WriterOptionsYAML() { +} + + } // namespace lld diff --git a/lld/lib/Core/YamlKeyValues.cpp b/lld/lib/ReaderWriter/YAML/YamlKeyValues.cpp index 3eab4e6d9c5..46120ad6716 100644 --- a/lld/lib/Core/YamlKeyValues.cpp +++ b/lld/lib/ReaderWriter/YAML/YamlKeyValues.cpp @@ -1,4 +1,4 @@ -//===- Core/YamlKeyValues.cpp - Reads YAML --------------------------------===// +//===- lib/ReaderWriter/YAML/YamlKeyValues.cpp ----------------------------===// // // The LLVM Linker // diff --git a/lld/lib/Core/YamlKeyValues.h b/lld/lib/ReaderWriter/YAML/YamlKeyValues.h index ecb3d2e239a..9f0e964cba5 100644 --- a/lld/lib/Core/YamlKeyValues.h +++ b/lld/lib/ReaderWriter/YAML/YamlKeyValues.h @@ -1,4 +1,4 @@ -//===- Core/YamlKeyValues.h - Reads YAML ----------------------------------===// +//===- lib/ReaderWriter/YAML/YamlKeyValues.h ------------------------------===// // // The LLVM Linker // diff --git a/lld/tools/lld-core/CMakeLists.txt b/lld/tools/lld-core/CMakeLists.txt index bd645094d59..4f4a43bbbc6 100644 --- a/lld/tools/lld-core/CMakeLists.txt +++ b/lld/tools/lld-core/CMakeLists.txt @@ -1,9 +1,13 @@ set(LLVM_USED_LIBS lldCore - lldReader lldPasses - lldDarwinPlatform - ) + lldMachO + lldPECOFF + lldELF + lldNative + lldYAML + lldReaderWriter + ) set(LLVM_LINK_COMPONENTS support diff --git a/lld/tools/lld-core/TestingHelpers.hpp b/lld/tools/lld-core/TestingHelpers.hpp new file mode 100644 index 00000000000..20f4d570aeb --- /dev/null +++ b/lld/tools/lld-core/TestingHelpers.hpp @@ -0,0 +1,403 @@ +//===- tools/lld/TestingWriter.hpp - Linker Core Test Support -------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_TOOLS_TESTING_HELPERS_H_ +#define LLD_TOOLS_TESTING_HELPERS_H_ + +#include "lld/Core/Atom.h" +#include "lld/Core/LLVM.h" +#include "lld/Core/Pass.h" +#include "lld/Core/Resolver.h" +#include "lld/ReaderWriter/WriterYAML.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/system_error.h" + +#include <vector> + +using namespace lld; + +// +// 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; +}; + + + +class TestingPassFile : public File { +public: + TestingPassFile() : File("Testing pass") { + } + + virtual void addAtom(const Atom &atom) { + if (const DefinedAtom* defAtom = dyn_cast<DefinedAtom>(&atom)) { + _definedAtoms._atoms.push_back(defAtom); + } + else { + assert(0 && "atom has unknown definition kind"); + } + } + + 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: + atom_collection_vector<DefinedAtom> _definedAtoms; + atom_collection_vector<UndefinedAtom> _undefinedAtoms; + atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms; + atom_collection_vector<AbsoluteAtom> _absoluteAtoms; +}; + + + +struct TestingKindMapping { + const char* string; + Reference::Kind value; + bool isBranch; + bool isGotLoad; + bool isGotUse; +}; + +// +// Table of fixup kinds in YAML documents used for testing +// +const TestingKindMapping sKinds[] = { + { "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 } + }; + + + +class TestingStubsPass : public StubsPass { +public: + virtual bool noTextRelocs() { + return true; + } + + virtual bool isCallSite(Reference::Kind kind) { + for (const TestingKindMapping* p = sKinds; p->string != nullptr; ++p) { + if ( kind == p->value ) + return p->isBranch; + } + return false; + } + + virtual const DefinedAtom* getStub(const Atom& target) { + const DefinedAtom *result = new TestingStubAtom(_file, target); + _file.addAtom(*result); + return result; + } + + + virtual void addStubAtoms(File &mergedFile) { + for (const DefinedAtom *stub : _file.defined() ) { + mergedFile.addAtom(*stub); + } + } + +private: + TestingPassFile _file; +}; + + + +class TestingGOTPass : public GOTPass { +public: + virtual bool noTextRelocs() { + return true; + } + + virtual bool isGOTAccess(Reference::Kind kind, bool &canBypassGOT) { + for (const TestingKindMapping* p = sKinds; p->string != nullptr; ++p) { + if ( kind == p->value ) { + canBypassGOT = p->isGotLoad; + return (p->isGotUse || p->isGotLoad); + } + } + return false; + } + + virtual void updateReferenceToGOT(const Reference *ref, bool targetIsNowGOT) { + if ( targetIsNowGOT ) + (const_cast<Reference*>(ref))->setKind(2); // pcrel32 + else + (const_cast<Reference*>(ref))->setKind(5); // lea32wasGot + } + + virtual const DefinedAtom* makeGOTEntry(const Atom &target) { + return new TestingGOTAtom(_file, target); + } + +private: + TestingPassFile _file; +}; + + +class TestingWriterOptionsYAML : public lld::WriterOptionsYAML { +public: + TestingWriterOptionsYAML(bool stubs, bool got) + : _doStubs(stubs), _doGOT(got) { + } + + virtual StubsPass *stubPass() const { + if ( _doStubs ) + return const_cast<TestingStubsPass*>(&_stubsPass); + else + return nullptr; + } + + virtual GOTPass *gotPass() const { + if ( _doGOT ) + return const_cast<TestingGOTPass*>(&_gotPass); + else + return nullptr; + } + + virtual StringRef kindToString(Reference::Kind value) const { + for (const TestingKindMapping* p = sKinds; p->string != nullptr; ++p) { + if ( value == p->value) + return p->string; + } + return StringRef("???"); + } +private: + bool _doStubs; + bool _doGOT; + TestingStubsPass _stubsPass; + TestingGOTPass _gotPass; +}; + + +class TestingReaderOptionsYAML : public lld::ReaderOptionsYAML { + virtual Reference::Kind kindFromString(StringRef kindName) const { + for (const TestingKindMapping* p = sKinds; p->string != nullptr; ++p) { + if ( kindName.equals(p->string) ) + return p->value; + } + int k; + if (kindName.getAsInteger(0, k)) + k = 0; + return k; + } +}; + + + +#endif // LLD_TOOLS_TESTING_HELPERS_H_ 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; } |

