summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/include/lld/Core/Atom.h2
-rw-r--r--lld/include/lld/Core/DefinedAtom.h2
-rw-r--r--lld/include/lld/Core/File.h2
-rw-r--r--lld/include/lld/Core/NativeReader.h39
-rw-r--r--lld/include/lld/Core/NativeWriter.h34
-rw-r--r--lld/include/lld/Core/YamlWriter.h7
-rw-r--r--lld/lib/Core/CMakeLists.txt4
-rw-r--r--lld/lib/Core/NativeFileFormat.h161
-rw-r--r--lld/lib/Core/NativeReader.cpp415
-rw-r--r--lld/lib/Core/NativeWriter.cpp219
-rw-r--r--lld/lib/Core/YamlWriter.cpp2
-rw-r--r--lld/tools/lld-core/lld-core.cpp29
12 files changed, 908 insertions, 8 deletions
diff --git a/lld/include/lld/Core/Atom.h b/lld/include/lld/Core/Atom.h
index df5efeedbd8..101eb5221bc 100644
--- a/lld/include/lld/Core/Atom.h
+++ b/lld/include/lld/Core/Atom.h
@@ -1,4 +1,4 @@
-//===- Core/Atom.h - The Fundimental Unit of Linking ----------------------===//
+//===- Core/Atom.h - A node in linking graph ------------------------------===//
//
// The LLVM Linker
//
diff --git a/lld/include/lld/Core/DefinedAtom.h b/lld/include/lld/Core/DefinedAtom.h
index c151325cdcf..8db0728875d 100644
--- a/lld/include/lld/Core/DefinedAtom.h
+++ b/lld/include/lld/Core/DefinedAtom.h
@@ -1,4 +1,4 @@
-//===- Core/DefinedAtom.h - The Fundimental Unit of Linking ---------------===//
+//===- Core/DefinedAtom.h - The Fundamental Unit of Linking ---------------===//
//
// The LLVM Linker
//
diff --git a/lld/include/lld/Core/File.h b/lld/include/lld/Core/File.h
index b2f360149b4..c6b0e0fec57 100644
--- a/lld/include/lld/Core/File.h
+++ b/lld/include/lld/Core/File.h
@@ -20,7 +20,7 @@ namespace lld {
class File {
public:
File(llvm::StringRef p) : _path(p) {}
- ~File();
+ virtual ~File();
class AtomHandler {
public:
diff --git a/lld/include/lld/Core/NativeReader.h b/lld/include/lld/Core/NativeReader.h
new file mode 100644
index 00000000000..023dc2ecfac
--- /dev/null
+++ b/lld/include/lld/Core/NativeReader.h
@@ -0,0 +1,39 @@
+//===- 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 <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.
+ llvm::error_code parseNativeObjectFileOrSTDIN(llvm::StringRef path
+ , File*&);
+
+
+ /// parseNativeObjectFile - Parse the specified native object file
+ /// (in a buffer) and instantiate into an lld::File object.
+ llvm::error_code parseNativeObjectFile(llvm::MemoryBuffer* mb,
+ llvm::StringRef path, 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
new file mode 100644
index 00000000000..24bf671da10
--- /dev/null
+++ b/lld/include/lld/Core/NativeWriter.h
@@ -0,0 +1,34 @@
+//===- 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 &, llvm::StringRef path);
+
+ /// writeNativeObjectFile - writes the lld::File object in native object
+ /// file format to the specified stream.
+ int writeNativeObjectFile(const lld::File &, llvm::raw_ostream &);
+
+} // namespace lld
+
+#endif // LLD_CORE_NATIVE_WRITER_H_
diff --git a/lld/include/lld/Core/YamlWriter.h b/lld/include/lld/Core/YamlWriter.h
index b533b98575f..b4c02473133 100644
--- a/lld/include/lld/Core/YamlWriter.h
+++ b/lld/include/lld/Core/YamlWriter.h
@@ -1,4 +1,4 @@
-//===- Core/YamlWriter.h - Writes YAML ------------------------------------===//
+//===- Core/YamlWriter.h - Writes YAML formatted object files -------------===//
//
// The LLVM Linker
//
@@ -11,13 +11,14 @@
#define LLD_CORE_YAML_WRITER_H_
#include "lld/Core/File.h"
-
#include "llvm/Support/raw_ostream.h"
namespace lld {
namespace yaml {
-void writeObjectText(lld::File &, llvm::raw_ostream &);
+ /// writeObjectText - writes the lld::File object as in YAML
+ /// format to the specified stream.
+ void writeObjectText(const lld::File &, llvm::raw_ostream &);
} // namespace yaml
} // namespace lld
diff --git a/lld/lib/Core/CMakeLists.txt b/lld/lib/Core/CMakeLists.txt
index eca024cf231..c994d8f3f72 100644
--- a/lld/lib/Core/CMakeLists.txt
+++ b/lld/lib/Core/CMakeLists.txt
@@ -1,8 +1,12 @@
add_lld_library(lldCore
File.cpp
+ NativeFileFormat.h
+ NativeReader.cpp
+ NativeWriter.cpp
Resolver.cpp
SymbolTable.cpp
YamlKeyValues.cpp
+ YamlKeyValues.h
YamlReader.cpp
YamlWriter.cpp
)
diff --git a/lld/lib/Core/NativeFileFormat.h b/lld/lib/Core/NativeFileFormat.h
new file mode 100644
index 00000000000..aa8687a2fd5
--- /dev/null
+++ b/lld/lib/Core/NativeFileFormat.h
@@ -0,0 +1,161 @@
+//===- Core/NativeFileFormat.h - Describes 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_FILE_FORMAT_H_
+#define LLD_CORE_NATIVE_FILE_FORMAT_H_
+
+#include <stdint.h>
+
+namespace lld {
+
+
+//
+// Overview:
+//
+// The number one design goal of this file format is enable the linker to
+// read object files into in-memory Atom objects extremely quickly.
+// The second design goal is to enable future modifications to the
+// Atom attribute model.
+//
+// The llvm native object file format is not like traditional object file
+// formats (e.g. ELF, COFF, mach-o). There is no symbol table and no
+// sections. Instead the file is essentially an array of archived Atoms.
+// It is *not* serialized Atoms which would require deserialization into
+// in memory objects. Instead it is an array of read-only info about each
+// Atom. The NativeReader bulk creates in-memory Atoms which just have
+// an ivar which points to the read-only info for that Atom. No additional
+// processing is done to construct the in-memory Atoms. All Atom attribute
+// getter methods are virtual calls which dig up the info they need from the
+// ivar data.
+//
+// To support the gradual evolution of Atom attributes, the Atom read-only
+// data is versioned. The NativeReader chooses which in-memory Atom class
+// to use based on the version. What this means is that if new attributes
+// are added (or changed) in the Atom model, a new native atom class and
+// read-only atom info struct needs to be defined. Then, all the existing
+// native reader atom classes need to be modified to do their best effort
+// to map their old style read-only data to the new Atom model. At some point
+// some classes to support old versions may be dropped.
+//
+//
+// Details:
+//
+// The native object file format consists of a header that specifies the
+// endianness of the file and the architecture along with a list of "chunks"
+// in the file. A Chunk is simply a tagged range of the file. There is
+// one chunk for the array of atom infos. There is another chunk for the
+// string pool, and another for the content pool.
+//
+// It turns out there most atoms have very similar sets of attributes, only
+// the name and content attribute vary. To exploit this fact to reduce the file
+// size, the atom read-only info contains just the name and content info plus
+// a reference to which attribute set it uses. The attribute sets are stored
+// in another chunk.
+//
+
+
+//
+// An entry in the NativeFileHeader that describes one chunk of the file.
+//
+struct NativeChunk {
+ uint32_t signature;
+ uint32_t fileOffset;
+ uint32_t fileSize;
+ uint32_t elementCount;
+};
+
+
+//
+// The header in a native object file
+//
+struct NativeFileHeader {
+ uint8_t magic[16];
+ uint32_t endian;
+ uint32_t architecture;
+ uint32_t fileSize;
+ uint32_t chunkCount;
+ NativeChunk chunks[];
+};
+
+//
+// Possible values for NativeChunk.signature field
+//
+enum NativeChunkSignatures {
+ NCS_DefinedAtomsV1 = 1,
+ NCS_AttributesArrayV1 = 2,
+ NCS_Content = 3,
+ NCS_Strings = 4,
+ NCS_ReferencesArray = 5,
+};
+
+//
+// The 16-bytes at the start of a native object file
+//
+#define NATIVE_FILE_HEADER_MAGIC "llvm nat obj v1 "
+
+//
+// Possible values for the NativeFileHeader.endian field
+//
+enum {
+ NFH_BigEndian = 0x42696745,
+ NFH_LittleEndian = 0x4574696c
+};
+
+
+//
+// Possible values for the NativeFileHeader.architecture field
+//
+enum {
+ NFA_x86 = 1,
+ NFA_x86_64 = 2,
+ NFA_armv6 = 3,
+ NFA_armv7 = 4,
+};
+
+
+//
+// The NCS_DefinedAtomsV1 chunk contains an array of these structs
+//
+struct NativeDefinedAtomIvarsV1 {
+ uint32_t nameOffset;
+ uint32_t attributesOffset;
+ uint32_t contentOffset;
+ uint32_t contentSize;
+};
+
+
+//
+// The NCS_AttributesArrayV1 chunk contains an array of these structs
+//
+struct NativeAtomAttributesV1 {
+ uint32_t sectionNameOffset;
+ uint16_t align2;
+ uint16_t alignModulus;
+ uint8_t internalName;
+ uint8_t scope;
+ uint8_t interposable;
+ uint8_t merge;
+ uint8_t contentType;
+ uint8_t sectionChoice;
+ uint8_t deadStrip;
+ uint8_t permissions;
+ uint8_t thumb;
+ uint8_t alias;
+ uint8_t pad1;
+ uint8_t pad2;
+};
+
+
+
+
+
+
+} // namespace lld
+
+#endif // LLD_CORE_NATIVE_FILE_FORMAT_H_
diff --git a/lld/lib/Core/NativeReader.cpp b/lld/lib/Core/NativeReader.cpp
new file mode 100644
index 00000000000..cb42a31fa74
--- /dev/null
+++ b/lld/lib/Core/NativeReader.cpp
@@ -0,0 +1,415 @@
+//===- Core/NativeReader.cpp - reads native object file ------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <vector>
+
+#include <assert.h>
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/system_error.h"
+
+#include "lld/Core/File.h"
+#include "lld/Core/Atom.h"
+
+#include "NativeFileFormat.h"
+
+namespace lld {
+
+// forward reference
+class NativeFile;
+
+
+enum native_reader_errors {
+ success = 0,
+ unknown_file_format,
+ file_too_short,
+ file_malformed,
+ unknown_chunk_type,
+ memory_error,
+};
+
+class reader_error_category : public llvm::_do_message {
+public:
+ virtual const char* name() const {
+ return "lld.native.reader";
+ }
+ virtual std::string message(int ev) const;
+};
+
+const reader_error_category reader_error_category_singleton;
+
+std::string reader_error_category::message(int ev) const {
+ switch (ev) {
+ case success:
+ return "Success";
+ case unknown_file_format:
+ return "Unknown file foramt";
+ case file_too_short:
+ return "file truncated";
+ case file_malformed:
+ return "file malformed";
+ case memory_error:
+ return "out of memory";
+ case unknown_chunk_type:
+ return "unknown chunk type";
+ default:
+ llvm_unreachable("An enumerator of native_reader_errors does not have a "
+ "message defined.");
+ }
+}
+
+inline llvm::error_code make_error_code(native_reader_errors e) {
+ return llvm::error_code(static_cast<int>(e), reader_error_category_singleton);
+}
+
+
+
+
+//
+// An object of this class is instantied for each NativeDefinedAtomIvarsV1
+// struct in the NCS_DefinedAtomsV1 chunk.
+//
+class NativeDefinedAtomV1 : public DefinedAtom {
+public:
+ NativeDefinedAtomV1(const NativeFile& f,
+ const NativeDefinedAtomIvarsV1* ivarData)
+ : _file(&f), _ivarData(ivarData) { }
+
+ virtual const class File& file() const;
+
+ virtual uint64_t ordinal() const;
+
+ virtual llvm::StringRef name() const;
+
+ virtual bool internalName() const {
+ return attributes().internalName;
+ }
+
+ virtual uint64_t size() const {
+ return _ivarData->contentSize;
+ }
+
+ virtual DefinedAtom::Scope scope() const {
+ return (DefinedAtom::Scope)(attributes().scope);
+ }
+
+ virtual DefinedAtom::Interposable interposable() const {
+ return (DefinedAtom::Interposable)(attributes().interposable);
+ }
+
+ virtual DefinedAtom::Merge merge() const {
+ return (DefinedAtom::Merge)(attributes().merge);
+ }
+
+ virtual DefinedAtom::ContentType contentType() const {
+ return (DefinedAtom::ContentType)(attributes().contentType);
+ }
+
+ virtual DefinedAtom::Alignment alignment() const {
+ return DefinedAtom::Alignment(attributes().align2, attributes().alignModulus);
+ }
+
+ virtual DefinedAtom::SectionChoice sectionChoice() const {
+ return (DefinedAtom::SectionChoice)(attributes().sectionChoice);
+ }
+
+ virtual llvm::StringRef customSectionName() const;
+
+ virtual DefinedAtom::DeadStripKind deadStrip() const {
+ return (DefinedAtom::DeadStripKind)(attributes().deadStrip);
+ }
+
+ virtual DefinedAtom::ContentPermissions permissions() const {
+ return (DefinedAtom::ContentPermissions)(attributes().permissions);
+ }
+
+ virtual bool isThumb() const {
+ return (attributes().thumb != 0);
+ }
+
+ virtual bool isAlias() const {
+ return (attributes().alias != 0);
+ }
+
+ llvm::ArrayRef<uint8_t> rawContent() const;
+
+ virtual Reference::iterator referencesBegin() const {
+ return 0;
+ }
+
+ virtual Reference::iterator referencesEnd() const {
+ return 0;
+ }
+
+private:
+ const NativeAtomAttributesV1& attributes() const;
+
+ const NativeFile* _file;
+ const NativeDefinedAtomIvarsV1* _ivarData;
+};
+
+
+
+
+//
+// lld::File object for native llvm object file
+//
+class NativeFile : public File {
+public:
+
+ /// Instantiates a File object from a native object file. Ownership
+ /// of the MemoryBuffer is transfered to the resulting File object.
+ static llvm::error_code make(llvm::MemoryBuffer* mb, llvm::StringRef path,
+ File*& result) {
+ const uint8_t* const base =
+ reinterpret_cast<const uint8_t*>(mb->getBufferStart());
+ const NativeFileHeader* const header =
+ reinterpret_cast<const NativeFileHeader*>(base);
+ // make sure magic matches
+ if ( memcmp(header->magic, NATIVE_FILE_HEADER_MAGIC, 16) != 0 )
+ return make_error_code(unknown_file_format);
+
+ // make sure mapped file contains all needed data
+ const size_t fileSize = mb->getBufferSize();
+ if ( header->fileSize > fileSize )
+ return make_error_code(file_too_short);
+
+ // instantiate NativeFile object and add values to it as found
+ NativeFile* file = new NativeFile(mb, path);
+
+ // process each chunk
+ for(uint32_t i=0; i < header->chunkCount; ++i) {
+ llvm::error_code ec;
+ const NativeChunk* chunk = &header->chunks[i];
+ // sanity check chunk is within file
+ if ( chunk->fileOffset > fileSize )
+ return make_error_code(file_malformed);
+ if ( (chunk->fileOffset + chunk->fileSize) > fileSize)
+ return make_error_code(file_malformed);
+ // process chunk, based on signature
+ switch ( chunk->signature ) {
+ case NCS_DefinedAtomsV1:
+ ec = file->processDefinedAtomsV1(base, chunk);
+ break;
+ case NCS_AttributesArrayV1:
+ ec = file->processAttributesV1(base, chunk);
+ break;
+ case NCS_Content:
+ ec = file->processContent(base, chunk);
+ break;
+ case NCS_Strings:
+ ec = file->processStrings(base, chunk);
+ break;
+ default:
+ return make_error_code(unknown_chunk_type);
+ }
+ if ( ec ) {
+ delete file;
+ return ec;
+ }
+
+ // TO DO: validate enough chunks were used
+
+ result = file;
+ }
+
+
+ return make_error_code(success);
+ }
+
+ virtual ~NativeFile() {
+ // The NativeFile owns the MemoryBuffer and must not delete it.
+ delete _buffer;
+ // All other ivar pointers are pointers into the MemoryBuffer, except
+ // the _definedAtoms array which was allocated to contain an array
+ // of Atom objects. The atoms have empty destructors, so it is ok
+ // to just delete the memory.
+ delete _definedAtoms.arrayStart;
+ }
+
+ // visits each atom in the file
+ virtual bool forEachAtom(AtomHandler& handler) const {
+ for(const uint8_t* p=_definedAtoms.arrayStart; p != _definedAtoms.arrayEnd;
+ p += _definedAtoms.elementSize) {
+ const DefinedAtom* atom = reinterpret_cast<const DefinedAtom*>(p);
+ handler.doDefinedAtom(*atom);
+ }
+ return (_definedAtoms.arrayStart != _definedAtoms.arrayEnd);
+ }
+
+ // not used
+ virtual bool justInTimeforEachAtom(llvm::StringRef name,
+ AtomHandler &) const {
+ return false;
+ }
+
+private:
+ friend class NativeDefinedAtomV1;
+
+ // instantiate array of DefinedAtoms from v1 ivar data in file
+ llvm::error_code processDefinedAtomsV1(const uint8_t* base,
+ const NativeChunk* chunk) {
+ const size_t atomSize = sizeof(NativeDefinedAtomV1);
+ size_t atomsArraySize = chunk->elementCount * atomSize;
+ uint8_t* atomsStart = reinterpret_cast<uint8_t*>
+ (operator new(atomsArraySize, std::nothrow));
+ if (atomsStart == NULL )
+ return make_error_code(memory_error);
+ const size_t ivarElementSize = chunk->fileSize
+ / chunk->elementCount;
+ if ( ivarElementSize != sizeof(NativeDefinedAtomIvarsV1) )
+ return make_error_code(file_malformed);
+ uint8_t* atomsEnd = atomsStart + atomsArraySize;
+ const NativeDefinedAtomIvarsV1* ivarData =
+ reinterpret_cast<const NativeDefinedAtomIvarsV1*>
+ (base + chunk->fileOffset);
+ for(uint8_t* s = atomsStart; s != atomsEnd; s += atomSize) {
+ NativeDefinedAtomV1* atomAllocSpace =
+ reinterpret_cast<NativeDefinedAtomV1*>(s);
+ new (atomAllocSpace) NativeDefinedAtomV1(*this, ivarData);
+ ++ivarData;
+ }
+ this->_definedAtoms.arrayStart = atomsStart;
+ this->_definedAtoms.arrayEnd = atomsEnd;
+ this->_definedAtoms.elementSize = atomSize;
+ return make_error_code(success);
+ }
+
+ // set up pointers to attributes array
+ llvm::error_code processAttributesV1(const uint8_t* base, const NativeChunk* chunk) {
+ this->_attributes = base + chunk->fileOffset;
+ this->_attributesMaxOffset = chunk->fileSize;
+ return make_error_code(success);
+ }
+
+ // set up pointers to string pool in file
+ llvm::error_code processStrings(const uint8_t* base,
+ const NativeChunk* chunk) {
+ this->_strings = reinterpret_cast<const char*>(base + chunk->fileOffset);
+ this->_stringsMaxOffset = chunk->fileSize;
+ return make_error_code(success);
+ }
+
+ // set up pointers to content area in file
+ llvm::error_code processContent(const uint8_t* base,
+ const NativeChunk* chunk) {
+ this->_contentStart = base + chunk->fileOffset;
+ this->_contentEnd = base + chunk->fileOffset + chunk->fileSize;
+ return make_error_code(success);
+ }
+
+ llvm::StringRef string(uint32_t offset) const {
+ assert(offset < _stringsMaxOffset);
+ return llvm::StringRef(&_strings[offset]);
+ }
+
+ const NativeAtomAttributesV1& attribute(uint32_t offset) const {
+ assert(offset < _attributesMaxOffset);
+ return *reinterpret_cast<const NativeAtomAttributesV1*>(_attributes + offset);
+ }
+
+ const uint8_t* content(uint32_t offset, uint32_t size) const {
+ const uint8_t* result = _contentStart + offset;
+ assert((result+size) <= _contentEnd);
+ return result;
+ }
+
+
+ // private constructor, only called by make()
+ NativeFile(llvm::MemoryBuffer* mb, llvm::StringRef path) :
+ lld::File(path), _buffer(mb), _header(NULL),
+ _strings(NULL), _stringsMaxOffset(0),
+ _contentStart(NULL), _contentEnd(NULL)
+ {
+ _header = reinterpret_cast<const NativeFileHeader*>(mb->getBufferStart());
+ }
+
+ struct AtomArray {
+ AtomArray() : arrayStart(NULL), arrayEnd(NULL),
+ elementSize(0) { }
+ const uint8_t* arrayStart;
+ const uint8_t* arrayEnd;
+ uint32_t elementSize;
+ };
+
+ llvm::MemoryBuffer* _buffer;
+ const NativeFileHeader* _header;
+ AtomArray _definedAtoms;
+ const uint8_t* _attributes;
+ uint32_t _attributesMaxOffset;
+ const char* _strings;
+ uint32_t _stringsMaxOffset;
+ const uint8_t* _contentStart;
+ const uint8_t* _contentEnd;
+};
+
+
+
+inline const class File& NativeDefinedAtomV1::file() const {
+ return *_file;
+}
+
+inline uint64_t NativeDefinedAtomV1:: ordinal() const {
+ const uint8_t* p = reinterpret_cast<const uint8_t*>(_ivarData);
+ return p - _file->_definedAtoms.arrayStart;
+}
+
+inline llvm::StringRef NativeDefinedAtomV1::name() const {
+ return _file->string(_ivarData->nameOffset);
+}
+
+inline const NativeAtomAttributesV1& NativeDefinedAtomV1::attributes() const {
+ return _file->attribute(_ivarData->attributesOffset);
+}
+
+inline llvm::ArrayRef<uint8_t> NativeDefinedAtomV1::rawContent() const {
+ if ( this->contentType() == DefinedAtom::typeZeroFill )
+ return llvm::ArrayRef<uint8_t>();
+ const uint8_t* p = _file->content(_ivarData->contentOffset,
+ _ivarData->contentSize);
+ return llvm::ArrayRef<uint8_t>(p, _ivarData->contentSize);
+}
+
+inline llvm::StringRef NativeDefinedAtomV1::customSectionName() const {
+ uint32_t offset = attributes().sectionNameOffset;
+ return _file->string(offset);
+}
+
+
+
+//
+// Instantiate an lld::File from the given native object file buffer
+//
+llvm::error_code parseNativeObjectFile(llvm::MemoryBuffer* mb,
+ llvm::StringRef path, File*& result) {
+ return NativeFile::make(mb, path, result);
+}
+
+
+
+//
+// Instantiate an lld::File from the given native object file path
+//
+llvm::error_code parseNativeObjectFileOrSTDIN(llvm::StringRef path,
+ File*& result) {
+ llvm::OwningPtr<llvm::MemoryBuffer> mb;
+ llvm::error_code ec = llvm::MemoryBuffer::getFileOrSTDIN(path, mb);
+ if ( ec )
+ return ec;
+
+ return parseNativeObjectFile(mb.get(), path, result);
+}
+
+
+
+} // namespace lld
diff --git a/lld/lib/Core/NativeWriter.cpp b/lld/lib/Core/NativeWriter.cpp
new file mode 100644
index 00000000000..9769cd60eb4
--- /dev/null
+++ b/lld/lib/Core/NativeWriter.cpp
@@ -0,0 +1,219 @@
+//===- Core/NativeWriter.cpp - Creates a native object file ---------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <vector>
+#include <map>
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/ArrayRef.h"
+
+#include "lld/Core/File.h"
+#include "lld/Core/NativeWriter.h"
+
+#include "NativeFileFormat.h"
+
+
+namespace lld {
+
+
+///
+/// Class for writing native object files.
+///
+class NativeWriter : public File::AtomHandler {
+public:
+ /// construct writer for an lld::File object
+ NativeWriter(const lld::File& file) : _file(file) {
+ // visit all atoms
+ _file.forEachAtom(*this);
+ // construct file header based on atom information accumulated
+ makeHeader();
+ }
+
+ // write the lld::File in native format to the specified stream
+ void write(llvm::raw_ostream& out) {
+ out.write((char*)_headerBuffer, _headerBufferSize);
+ out.write((char*)&_definedAtomIvars[0],
+ _definedAtomIvars.size()*sizeof(NativeDefinedAtomIvarsV1));
+ out.write((char*)&_attributes[0],
+ _attributes.size()*sizeof(NativeAtomAttributesV1));
+ out.write((char*)&_contentPool[0], _contentPool.size());
+ out.write(&_stringPool[0], _stringPool.size());
+ }
+
+private:
+
+ // visitor routine called by forEachAtom()
+ virtual void doDefinedAtom(const class DefinedAtom& atom) {
+ NativeDefinedAtomIvarsV1 ivar;
+ ivar.nameOffset = getNameOffset(atom);
+ ivar.attributesOffset = getAttributeOffset(atom);
+ ivar.contentOffset = getContentOffset(atom);
+ ivar.contentSize = atom.size();
+ _definedAtomIvars.push_back(ivar);
+ }
+
+ // visitor routine called by forEachAtom()
+ virtual void doUndefinedAtom(const class UndefinedAtom& atom) {
+ }
+
+ // visitor routine called by forEachAtom()
+ virtual void doFile(const class File &) {
+ }
+
+ // fill out native file header and chunk directory
+ void makeHeader() {
+ _headerBufferSize = sizeof(NativeFileHeader) + 4*sizeof(NativeChunk);
+ _headerBuffer = reinterpret_cast<NativeFileHeader*>
+ (operator new(_headerBufferSize, std::nothrow));
+ memcpy(_headerBuffer->magic, NATIVE_FILE_HEADER_MAGIC, 16);
+ _headerBuffer->endian = NFH_LittleEndian;
+ _headerBuffer->architecture = 0;
+ _headerBuffer->fileSize = 0;
+ _headerBuffer->chunkCount = 4;
+
+ // create chunk for atom ivar array
+ NativeChunk& ch0 = _headerBuffer->chunks[0];
+ ch0.signature = NCS_DefinedAtomsV1;
+ ch0.fileOffset = _headerBufferSize;
+ ch0.fileSize = _definedAtomIvars.size()*sizeof(NativeDefinedAtomIvarsV1);
+ ch0.elementCount = _definedAtomIvars.size();
+ // create chunk for attributes
+ NativeChunk& ch1 = _headerBuffer->chunks[1];
+ ch1.signature = NCS_AttributesArrayV1;
+ ch1.fileOffset = ch0.fileOffset + ch0.fileSize;
+ ch1.fileSize = _attributes.size()*sizeof(NativeAtomAttributesV1);
+ ch1.elementCount = _attributes.size();
+ // create chunk for content
+ NativeChunk& ch2 = _headerBuffer->chunks[2];
+ ch2.signature = NCS_Content;
+ ch2.fileOffset = ch1.fileOffset + ch1.fileSize;
+ ch2.fileSize = _contentPool.size();
+ ch2.elementCount = _contentPool.size();
+ // create chunk for symbol strings
+ NativeChunk& ch3 = _headerBuffer->chunks[3];
+ ch3.signature = NCS_Strings;
+ ch3.fileOffset = ch2.fileOffset + ch2.fileSize;
+ ch3.fileSize = _stringPool.size();
+ ch3.elementCount = _stringPool.size();
+
+ _headerBuffer->fileSize = ch3.fileOffset + ch3.fileSize;
+ }
+
+
+ // append atom name to string pool and return offset
+ uint32_t getNameOffset(const class DefinedAtom& atom) {
+ return this->getNameOffset(atom.name());
+ }
+
+ // append atom name to string pool and return offset
+ uint32_t getNameOffset(llvm::StringRef name) {
+ uint32_t result = _stringPool.size();
+ _stringPool.insert(_stringPool.end(), name.size()+1, 0);
+ strcpy(&_stringPool[result], name.data());
+ return result;
+ }
+
+ // append atom cotent to content pool and return offset
+ uint32_t getContentOffset(const class DefinedAtom& atom) {
+ if ( atom.contentType() == DefinedAtom::typeZeroFill )
+ return 0;
+ uint32_t result = _contentPool.size();
+ llvm::ArrayRef<uint8_t> cont = atom.rawContent();
+ _contentPool.insert(_contentPool.end(), cont.size(), 0);
+ memcpy(&_contentPool[result], cont.data(), cont.size());
+ return result;
+ }
+
+ // reuse existing attributes entry or create a new one and return offet
+ uint32_t getAttributeOffset(const class DefinedAtom& atom) {
+ NativeAtomAttributesV1 attrs;
+ computeAttributesV1(atom, attrs);
+ for(unsigned int i=0; i < _attributes.size(); ++i) {
+ if ( !memcmp(&_attributes[i], &attrs, sizeof(NativeAtomAttributesV1)) ) {
+ // found that this set of attributes already used, so re-use
+ return i * sizeof(NativeAtomAttributesV1);
+ }
+ }
+ // append new attribute set to end
+ uint32_t result = _attributes.size() * sizeof(NativeAtomAttributesV1);
+ _attributes.push_back(attrs);
+ return result;
+ }
+
+ uint32_t sectionNameOffset(const class DefinedAtom& atom) {
+ // if section based on content, then no custom section name available
+ if ( atom.sectionChoice() == DefinedAtom::sectionBasedOnContent )
+ return 0;
+ llvm::StringRef name = atom.customSectionName();
+ assert( ! name.empty() );
+ // look to see if this section name was used by another atom
+ for(NameToOffsetVector::iterator it=_sectionNames.begin();
+ it != _sectionNames.end(); ++it) {
+ if ( name.equals(it->first) )
+ return it->second;
+ }
+ // first use of this section name
+ uint32_t result = this->getNameOffset(name);
+ _sectionNames.push_back(
+ std::make_pair<llvm::StringRef, uint32_t>(name, result));
+ return result;
+ }
+
+ void computeAttributesV1(const class DefinedAtom& atom,
+ NativeAtomAttributesV1& attrs) {
+ attrs.sectionNameOffset = sectionNameOffset(atom);
+ attrs.align2 = atom.alignment().powerOf2;
+ attrs.alignModulus = atom.alignment().modulus;
+ attrs.internalName = atom.internalName();
+ attrs.scope = atom.scope();
+ attrs.interposable = atom.interposable();
+ attrs.merge = atom.merge();
+ attrs.contentType = atom.contentType();
+ attrs.sectionChoice = atom.sectionChoice();
+ attrs.deadStrip = atom.deadStrip();
+ attrs.permissions = atom.permissions();
+ attrs.thumb = atom.isThumb();
+ attrs.alias = atom.isAlias();
+ }
+
+ typedef std::vector<std::pair<llvm::StringRef, uint32_t> > NameToOffsetVector;
+
+ const lld::File& _file;
+ NativeFileHeader* _headerBuffer;
+ size_t _headerBufferSize;
+ std::vector<char> _stringPool;
+ std::vector<uint8_t> _contentPool;
+ std::vector<NativeDefinedAtomIvarsV1> _definedAtomIvars;
+ std::vector<NativeAtomAttributesV1> _attributes;
+ NameToOffsetVector _sectionNames;
+};
+
+
+
+
+
+/// writeNativeObjectFile - writes the lld::File object in native object
+/// file format to the specified stream.
+int writeNativeObjectFile(const lld::File &file, llvm::raw_ostream &out) {
+ NativeWriter writer(file);
+ writer.write(out);
+ return 0;
+}
+
+/// writeNativeObjectFile - writes the lld::File object in native object
+/// file format to the specified file path.
+int writeNativeObjectFile(const lld::File& file, llvm::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);
+}
+
+} // namespace lld
diff --git a/lld/lib/Core/YamlWriter.cpp b/lld/lib/Core/YamlWriter.cpp
index 3e30c0a4260..e5f0b1c44c3 100644
--- a/lld/lib/Core/YamlWriter.cpp
+++ b/lld/lib/Core/YamlWriter.cpp
@@ -195,7 +195,7 @@ private:
bool _firstAtom;
};
-void writeObjectText(File &file, llvm::raw_ostream &out) {
+void writeObjectText(const File &file, llvm::raw_ostream &out) {
Handler h(out);
out << "---\n";
out << "atoms:\n";
diff --git a/lld/tools/lld-core/lld-core.cpp b/lld/tools/lld-core/lld-core.cpp
index 3bd35c2538f..77b67495781 100644
--- a/lld/tools/lld-core/lld-core.cpp
+++ b/lld/tools/lld-core/lld-core.cpp
@@ -14,15 +14,20 @@
#include "lld/Core/Resolver.h"
#include "lld/Core/YamlReader.h"
#include "lld/Core/YamlWriter.h"
+#include "lld/Core/NativeReader.h"
+#include "lld/Core/NativeWriter.h"
#include "lld/Platform/Platform.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
#include <vector>
@@ -207,6 +212,28 @@ int main(int argc, const char *argv[]) {
// write new atom graph out as YAML doc
std::string errorInfo;
llvm::raw_fd_ostream out("-", errorInfo);
- yaml::writeObjectText(outFile, out);
+// yaml::writeObjectText(outFile, out);
+
+ // make unique temp .o file to put generated object file
+ int fd;
+ llvm::SmallString<128> tempPath;
+ llvm::sys::fs::unique_file("temp%%%%%.o", fd, tempPath);
+ llvm::raw_fd_ostream binaryOut(fd, /*shouldClose=*/true);
+
+ // write native file
+ writeNativeObjectFile(outFile, binaryOut);
+ binaryOut.close(); // manually close so that file can be read next
+
+ // read native file
+ lld::File* natFile;
+ parseNativeObjectFileOrSTDIN(tempPath, natFile);
+
+ // delete temp .o file
+ bool existed;
+ llvm::sys::fs::remove(tempPath.str(), existed);
+
+ // write new atom graph out as YAML doc
+ yaml::writeObjectText(*natFile, out);
+
return 0;
}
OpenPOWER on IntegriCloud