summaryrefslogtreecommitdiff
path: root/lib/ReaderWriter/Native
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ReaderWriter/Native')
-rw-r--r--lib/ReaderWriter/Native/CMakeLists.txt7
-rw-r--r--lib/ReaderWriter/Native/Makefile14
-rw-r--r--lib/ReaderWriter/Native/NativeFileFormat.h258
-rw-r--r--lib/ReaderWriter/Native/ReaderNative.cpp1013
-rw-r--r--lib/ReaderWriter/Native/WriterNative.cpp566
5 files changed, 1858 insertions, 0 deletions
diff --git a/lib/ReaderWriter/Native/CMakeLists.txt b/lib/ReaderWriter/Native/CMakeLists.txt
new file mode 100644
index 000000000000..e15f3d60e89c
--- /dev/null
+++ b/lib/ReaderWriter/Native/CMakeLists.txt
@@ -0,0 +1,7 @@
+add_llvm_library(lldNative
+ ReaderNative.cpp
+ WriterNative.cpp
+ LINK_LIBS
+ lldCore
+ LLVMSupport
+ )
diff --git a/lib/ReaderWriter/Native/Makefile b/lib/ReaderWriter/Native/Makefile
new file mode 100644
index 000000000000..6aba37868900
--- /dev/null
+++ b/lib/ReaderWriter/Native/Makefile
@@ -0,0 +1,14 @@
+##===- lld/lib/ReaderWriter/Native/Makefile --------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLD_LEVEL := ../../..
+LIBRARYNAME := lldNative
+USEDLIBS = lldCore.a
+
+include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/Native/NativeFileFormat.h b/lib/ReaderWriter/Native/NativeFileFormat.h
new file mode 100644
index 000000000000..535072fe2314
--- /dev/null
+++ b/lib/ReaderWriter/Native/NativeFileFormat.h
@@ -0,0 +1,258 @@
+//===- lib/ReaderWriter/Native/NativeFileFormat.h -------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_NATIVE_NATIVE_FILE_FORMAT_H
+#define LLD_READER_WRITER_NATIVE_NATIVE_FILE_FORMAT_H
+
+#include "llvm/Support/DataTypes.h"
+#include <cstdint>
+
+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_AbsoluteAttributesV1 = 12,
+ NCS_UndefinedAtomsV1 = 3,
+ NCS_SharedLibraryAtomsV1 = 4,
+ NCS_AbsoluteAtomsV1 = 5,
+ NCS_Strings = 6,
+ NCS_ReferencesArrayV1 = 7,
+ NCS_ReferencesArrayV2 = 8,
+ NCS_TargetsTable = 9,
+ NCS_AddendsTable = 10,
+ NCS_Content = 11,
+};
+
+//
+// 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 referencesStartIndex;
+ uint32_t referencesCount;
+ uint32_t contentOffset;
+ uint32_t contentSize;
+ uint64_t sectionSize;
+};
+
+
+//
+// The NCS_AttributesArrayV1 chunk contains an array of these structs
+//
+struct NativeAtomAttributesV1 {
+ uint32_t sectionNameOffset;
+ uint16_t align2;
+ uint16_t alignModulus;
+ uint8_t scope;
+ uint8_t interposable;
+ uint8_t merge;
+ uint8_t contentType;
+ uint8_t sectionChoice;
+ uint8_t deadStrip;
+ uint8_t dynamicExport;
+ uint8_t permissions;
+ uint8_t alias;
+ uint8_t codeModel;
+};
+
+
+
+//
+// The NCS_UndefinedAtomsV1 chunk contains an array of these structs
+//
+struct NativeUndefinedAtomIvarsV1 {
+ uint32_t nameOffset;
+ uint32_t flags;
+ uint32_t fallbackNameOffset;
+};
+
+
+//
+// The NCS_SharedLibraryAtomsV1 chunk contains an array of these structs
+//
+struct NativeSharedLibraryAtomIvarsV1 {
+ uint64_t size;
+ uint32_t nameOffset;
+ uint32_t loadNameOffset;
+ uint32_t type;
+ uint32_t flags;
+};
+
+
+
+//
+// The NCS_AbsoluteAtomsV1 chunk contains an array of these structs
+//
+struct NativeAbsoluteAtomIvarsV1 {
+ uint32_t nameOffset;
+ uint32_t attributesOffset;
+ uint32_t reserved;
+ uint64_t value;
+};
+
+
+
+//
+// The NCS_ReferencesArrayV1 chunk contains an array of these structs
+//
+struct NativeReferenceIvarsV1 {
+ enum {
+ noTarget = UINT16_MAX
+ };
+ uint32_t offsetInAtom;
+ uint16_t kindValue;
+ uint8_t kindNamespace;
+ uint8_t kindArch;
+ uint16_t targetIndex;
+ uint16_t addendIndex;
+};
+
+
+//
+// The NCS_ReferencesArrayV2 chunk contains an array of these structs
+//
+struct NativeReferenceIvarsV2 {
+ enum : unsigned {
+ noTarget = UINT32_MAX
+ };
+ uint64_t offsetInAtom;
+ int64_t addend;
+ uint16_t kindValue;
+ uint8_t kindNamespace;
+ uint8_t kindArch;
+ uint32_t targetIndex;
+ uint32_t tag;
+};
+
+
+//
+// The NCS_TargetsTable chunk contains an array of uint32_t entries.
+// The C++ class Reference has a target() method that returns a
+// pointer to another Atom. We can't have pointers in object files,
+// so instead NativeReferenceIvarsV1 contains an index to the target.
+// The index is into this NCS_TargetsTable of uint32_t entries.
+// The values in this table are the index of the (target) atom in this file.
+// For DefinedAtoms the value is from 0 to NCS_DefinedAtomsV1.elementCount.
+// For UndefinedAtoms the value is from NCS_DefinedAtomsV1.elementCount to
+// NCS_DefinedAtomsV1.elementCount+NCS_UndefinedAtomsV1.elementCount.
+//
+
+
+//
+// The NCS_AddendsTable chunk contains an array of int64_t entries.
+// If we allocated space for addends directly in NativeReferenceIvarsV1
+// it would double the size of that struct. But since addends are rare,
+// we instead just keep a pool of addends and have NativeReferenceIvarsV1
+// (if it needs an addend) just store the index (into the pool) of the
+// addend it needs.
+//
+
+
+
+} // namespace lld
+
+#endif // LLD_READER_WRITER_NATIVE_NATIVE_FILE_FORMAT_H
diff --git a/lib/ReaderWriter/Native/ReaderNative.cpp b/lib/ReaderWriter/Native/ReaderNative.cpp
new file mode 100644
index 000000000000..84cdb4b997e8
--- /dev/null
+++ b/lib/ReaderWriter/Native/ReaderNative.cpp
@@ -0,0 +1,1013 @@
+//===- lib/ReaderWriter/Native/ReaderNative.cpp ---------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeFileFormat.h"
+#include "lld/Core/Atom.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Reader.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/ArrayRef.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 <memory>
+#include <vector>
+
+namespace lld {
+namespace native {
+
+// forward reference
+class File;
+
+//
+// An object of this class is instantied for each NativeDefinedAtomIvarsV1
+// struct in the NCS_DefinedAtomsV1 chunk.
+//
+class NativeDefinedAtomV1 : public DefinedAtom {
+public:
+ NativeDefinedAtomV1(const File& f,
+ const NativeDefinedAtomIvarsV1* ivarData)
+ : _file(&f), _ivarData(ivarData) { }
+
+ const lld::File& file() const override;
+
+ uint64_t ordinal() const override;
+
+ StringRef name() const override;
+
+ uint64_t size() const override { return _ivarData->contentSize; }
+
+ uint64_t sectionSize() const override { return _ivarData->sectionSize; }
+
+ DefinedAtom::Scope scope() const override {
+ return (DefinedAtom::Scope)(attributes().scope);
+ }
+
+ DefinedAtom::Interposable interposable() const override {
+ return (DefinedAtom::Interposable)(attributes().interposable);
+ }
+
+ DefinedAtom::Merge merge() const override {
+ return (DefinedAtom::Merge)(attributes().merge);
+ }
+
+ DefinedAtom::ContentType contentType() const override {
+ const NativeAtomAttributesV1& attr = attributes();
+ return (DefinedAtom::ContentType)(attr.contentType);
+ }
+
+ DefinedAtom::Alignment alignment() const override {
+ return DefinedAtom::Alignment(attributes().align2, attributes().alignModulus);
+ }
+
+ DefinedAtom::SectionChoice sectionChoice() const override {
+ return (DefinedAtom::SectionChoice)(attributes().sectionChoice);
+ }
+
+ StringRef customSectionName() const override;
+
+ DefinedAtom::DeadStripKind deadStrip() const override {
+ return (DefinedAtom::DeadStripKind)(attributes().deadStrip);
+ }
+
+ DynamicExport dynamicExport() const override {
+ return (DynamicExport)attributes().dynamicExport;
+ }
+
+ DefinedAtom::CodeModel codeModel() const override {
+ return DefinedAtom::CodeModel(attributes().codeModel);
+ }
+
+ DefinedAtom::ContentPermissions permissions() const override {
+ return (DefinedAtom::ContentPermissions)(attributes().permissions);
+ }
+
+ ArrayRef<uint8_t> rawContent() const override;
+
+ reference_iterator begin() const override;
+
+ reference_iterator end() const override;
+
+ const Reference* derefIterator(const void*) const override;
+
+ void incrementIterator(const void*& it) const override;
+
+private:
+ const NativeAtomAttributesV1& attributes() const;
+
+ const File *_file;
+ const NativeDefinedAtomIvarsV1 *_ivarData;
+};
+
+
+
+//
+// An object of this class is instantied for each NativeUndefinedAtomIvarsV1
+// struct in the NCS_UndefinedAtomsV1 chunk.
+//
+class NativeUndefinedAtomV1 : public UndefinedAtom {
+public:
+ NativeUndefinedAtomV1(const File& f,
+ const NativeUndefinedAtomIvarsV1* ivarData)
+ : _file(&f), _ivarData(ivarData) { }
+
+ const lld::File& file() const override;
+ StringRef name() const override;
+
+ CanBeNull canBeNull() const override {
+ return (CanBeNull)(_ivarData->flags & 0x3);
+ }
+
+ const UndefinedAtom *fallback() const override;
+
+private:
+ const File *_file;
+ const NativeUndefinedAtomIvarsV1 *_ivarData;
+ mutable std::unique_ptr<const SimpleUndefinedAtom> _fallback;
+};
+
+
+//
+// An object of this class is instantied for each NativeUndefinedAtomIvarsV1
+// struct in the NCS_SharedLibraryAtomsV1 chunk.
+//
+class NativeSharedLibraryAtomV1 : public SharedLibraryAtom {
+public:
+ NativeSharedLibraryAtomV1(const File& f,
+ const NativeSharedLibraryAtomIvarsV1* ivarData)
+ : _file(&f), _ivarData(ivarData) { }
+
+ const lld::File& file() const override;
+ StringRef name() const override;
+ StringRef loadName() const override;
+
+ bool canBeNullAtRuntime() const override {
+ return (_ivarData->flags & 0x1);
+ }
+
+ Type type() const override {
+ return (Type)_ivarData->type;
+ }
+
+ uint64_t size() const override {
+ return _ivarData->size;
+ }
+
+private:
+ const File *_file;
+ const NativeSharedLibraryAtomIvarsV1 *_ivarData;
+};
+
+
+//
+// An object of this class is instantied for each NativeAbsoluteAtomIvarsV1
+// struct in the NCS_AbsoluteAtomsV1 chunk.
+//
+class NativeAbsoluteAtomV1 : public AbsoluteAtom {
+public:
+ NativeAbsoluteAtomV1(const File& f,
+ const NativeAbsoluteAtomIvarsV1* ivarData)
+ : _file(&f), _ivarData(ivarData) { }
+
+ const lld::File& file() const override;
+ StringRef name() const override;
+ Scope scope() const override {
+ const NativeAtomAttributesV1& attr = absAttributes();
+ return (Scope)(attr.scope);
+ }
+ uint64_t value() const override {
+ return _ivarData->value;
+ }
+
+private:
+ const NativeAtomAttributesV1& absAttributes() const;
+ const File *_file;
+ const NativeAbsoluteAtomIvarsV1 *_ivarData;
+};
+
+
+//
+// An object of this class is instantied for each NativeReferenceIvarsV1
+// struct in the NCS_ReferencesArrayV1 chunk.
+//
+class NativeReferenceV1 : public Reference {
+public:
+ NativeReferenceV1(const File &f, const NativeReferenceIvarsV1 *ivarData)
+ : Reference((KindNamespace)ivarData->kindNamespace,
+ (KindArch)ivarData->kindArch, ivarData->kindValue),
+ _file(&f), _ivarData(ivarData) {}
+
+ uint64_t offsetInAtom() const override {
+ return _ivarData->offsetInAtom;
+ }
+
+ const Atom* target() const override;
+ Addend addend() const override;
+ void setTarget(const Atom* newAtom) override;
+ void setAddend(Addend a) override;
+
+private:
+ const File *_file;
+ const NativeReferenceIvarsV1 *_ivarData;
+};
+
+
+//
+// An object of this class is instantied for each NativeReferenceIvarsV1
+// struct in the NCS_ReferencesArrayV1 chunk.
+//
+class NativeReferenceV2 : public Reference {
+public:
+ NativeReferenceV2(const File &f, const NativeReferenceIvarsV2 *ivarData)
+ : Reference((KindNamespace)ivarData->kindNamespace,
+ (KindArch)ivarData->kindArch, ivarData->kindValue),
+ _file(&f), _ivarData(ivarData) {}
+
+ uint64_t offsetInAtom() const override {
+ return _ivarData->offsetInAtom;
+ }
+
+ const Atom* target() const override;
+ Addend addend() const override;
+ void setTarget(const Atom* newAtom) override;
+ void setAddend(Addend a) override;
+ uint32_t tag() const override;
+
+private:
+ const File *_file;
+ const NativeReferenceIvarsV2 *_ivarData;
+};
+
+
+//
+// lld::File object for native llvm object file
+//
+class File : public lld::File {
+public:
+ File(std::unique_ptr<MemoryBuffer> mb)
+ : lld::File(mb->getBufferIdentifier(), kindObject),
+ _mb(std::move(mb)), // Reader now takes ownership of buffer
+ _header(nullptr), _targetsTable(nullptr), _targetsTableCount(0),
+ _strings(nullptr), _stringsMaxOffset(0), _addends(nullptr),
+ _addendsMaxIndex(0), _contentStart(nullptr), _contentEnd(nullptr) {
+ _header =
+ reinterpret_cast<const NativeFileHeader *>(_mb->getBufferStart());
+ }
+
+ /// Parses a File object from a native object file.
+ std::error_code doParse() override {
+ const uint8_t *const base =
+ reinterpret_cast<const uint8_t *>(_mb->getBufferStart());
+ StringRef path(_mb->getBufferIdentifier());
+ const NativeFileHeader *const header =
+ reinterpret_cast<const NativeFileHeader *>(base);
+ const NativeChunk *const chunks =
+ reinterpret_cast<const NativeChunk *>(base + sizeof(NativeFileHeader));
+ // make sure magic matches
+ if (memcmp(header->magic, NATIVE_FILE_HEADER_MAGIC,
+ sizeof(header->magic)) != 0)
+ return make_error_code(NativeReaderError::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(NativeReaderError::file_too_short);
+
+ DEBUG_WITH_TYPE("ReaderNative",
+ llvm::dbgs() << " Native File Header:" << " fileSize="
+ << header->fileSize << " chunkCount="
+ << header->chunkCount << "\n");
+
+ // process each chunk
+ for (uint32_t i = 0; i < header->chunkCount; ++i) {
+ std::error_code ec;
+ const NativeChunk* chunk = &chunks[i];
+ // sanity check chunk is within file
+ if ( chunk->fileOffset > fileSize )
+ return make_error_code(NativeReaderError::file_malformed);
+ if ( (chunk->fileOffset + chunk->fileSize) > fileSize)
+ return make_error_code(NativeReaderError::file_malformed);
+ // process chunk, based on signature
+ switch ( chunk->signature ) {
+ case NCS_DefinedAtomsV1:
+ ec = processDefinedAtomsV1(base, chunk);
+ break;
+ case NCS_AttributesArrayV1:
+ ec = processAttributesV1(base, chunk);
+ break;
+ case NCS_UndefinedAtomsV1:
+ ec = processUndefinedAtomsV1(base, chunk);
+ break;
+ case NCS_SharedLibraryAtomsV1:
+ ec = processSharedLibraryAtomsV1(base, chunk);
+ break;
+ case NCS_AbsoluteAtomsV1:
+ ec = processAbsoluteAtomsV1(base, chunk);
+ break;
+ case NCS_AbsoluteAttributesV1:
+ ec = processAbsoluteAttributesV1(base, chunk);
+ break;
+ case NCS_ReferencesArrayV1:
+ ec = processReferencesV1(base, chunk);
+ break;
+ case NCS_ReferencesArrayV2:
+ ec = processReferencesV2(base, chunk);
+ break;
+ case NCS_TargetsTable:
+ ec = processTargetsTable(base, chunk);
+ break;
+ case NCS_AddendsTable:
+ ec = processAddendsTable(base, chunk);
+ break;
+ case NCS_Content:
+ ec = processContent(base, chunk);
+ break;
+ case NCS_Strings:
+ ec = processStrings(base, chunk);
+ break;
+ default:
+ return make_error_code(NativeReaderError::unknown_chunk_type);
+ }
+ if ( ec ) {
+ return ec;
+ }
+ }
+ // TO DO: validate enough chunks were used
+
+ DEBUG_WITH_TYPE("ReaderNative", {
+ llvm::dbgs() << " ReaderNative DefinedAtoms:\n";
+ for (const DefinedAtom *a : defined()) {
+ llvm::dbgs() << llvm::format(" 0x%09lX", a)
+ << ", name=" << a->name()
+ << ", size=" << a->size() << "\n";
+ for (const Reference *r : *a) {
+ llvm::dbgs() << " offset="
+ << llvm::format("0x%03X", r->offsetInAtom())
+ << ", kind=" << r->kindValue()
+ << ", target=" << r->target() << "\n";
+ }
+ }
+ });
+ return make_error_code(NativeReaderError::success);
+ }
+
+ virtual ~File() {
+ // _mb is automatically deleted because of std::unique_ptr<>
+
+ // 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;
+ delete _undefinedAtoms._arrayStart;
+ delete _sharedLibraryAtoms._arrayStart;
+ delete _absoluteAtoms._arrayStart;
+ delete _referencesV1.arrayStart;
+ delete _referencesV2.arrayStart;
+ delete [] _targetsTable;
+ }
+
+ const atom_collection<DefinedAtom>& defined() const override {
+ return _definedAtoms;
+ }
+ const atom_collection<UndefinedAtom>& undefined() const override {
+ return _undefinedAtoms;
+ }
+ const atom_collection<SharedLibraryAtom>& sharedLibrary() const override {
+ return _sharedLibraryAtoms;
+ }
+ const atom_collection<AbsoluteAtom> &absolute() const override {
+ return _absoluteAtoms;
+ }
+
+private:
+ friend NativeDefinedAtomV1;
+ friend NativeUndefinedAtomV1;
+ friend NativeSharedLibraryAtomV1;
+ friend NativeAbsoluteAtomV1;
+ friend NativeReferenceV1;
+ friend NativeReferenceV2;
+
+ // instantiate array of DefinedAtoms from v1 ivar data in file
+ std::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 == nullptr)
+ return make_error_code(NativeReaderError::memory_error);
+ const size_t ivarElementSize = chunk->fileSize
+ / chunk->elementCount;
+ if ( ivarElementSize != sizeof(NativeDefinedAtomIvarsV1) )
+ return make_error_code(NativeReaderError::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;
+ this->_definedAtoms._elementCount = chunk->elementCount;
+ DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
+ << " chunk DefinedAtomsV1: "
+ << " count=" << chunk->elementCount
+ << " chunkSize=" << chunk->fileSize
+ << "\n");
+ return make_error_code(NativeReaderError::success);
+ }
+
+
+
+ // set up pointers to attributes array
+ std::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(NativeReaderError::success);
+ }
+
+ // set up pointers to attributes array
+ std::error_code processAbsoluteAttributesV1(const uint8_t *base,
+ const NativeChunk *chunk) {
+ this->_absAttributes = base + chunk->fileOffset;
+ this->_absAbsoluteMaxOffset = chunk->fileSize;
+ DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
+ << " chunk AbsoluteAttributesV1: "
+ << " count=" << chunk->elementCount
+ << " chunkSize=" << chunk->fileSize
+ << "\n");
+ return make_error_code(NativeReaderError::success);
+ }
+
+ // instantiate array of UndefinedAtoms from v1 ivar data in file
+ std::error_code processUndefinedAtomsV1(const uint8_t *base,
+ const NativeChunk *chunk) {
+ const size_t atomSize = sizeof(NativeUndefinedAtomV1);
+ size_t atomsArraySize = chunk->elementCount * atomSize;
+ uint8_t* atomsStart = reinterpret_cast<uint8_t*>
+ (operator new(atomsArraySize, std::nothrow));
+ if (atomsStart == nullptr)
+ return make_error_code(NativeReaderError::memory_error);
+ const size_t ivarElementSize = chunk->fileSize
+ / chunk->elementCount;
+ if ( ivarElementSize != sizeof(NativeUndefinedAtomIvarsV1) )
+ return make_error_code(NativeReaderError::file_malformed);
+ uint8_t* atomsEnd = atomsStart + atomsArraySize;
+ const NativeUndefinedAtomIvarsV1* ivarData =
+ reinterpret_cast<const NativeUndefinedAtomIvarsV1*>
+ (base + chunk->fileOffset);
+ for(uint8_t* s = atomsStart; s != atomsEnd; s += atomSize) {
+ NativeUndefinedAtomV1* atomAllocSpace =
+ reinterpret_cast<NativeUndefinedAtomV1*>(s);
+ new (atomAllocSpace) NativeUndefinedAtomV1(*this, ivarData);
+ ++ivarData;
+ }
+ this->_undefinedAtoms._arrayStart = atomsStart;
+ 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(NativeReaderError::success);
+ }
+
+
+ // instantiate array of ShareLibraryAtoms from v1 ivar data in file
+ std::error_code processSharedLibraryAtomsV1(const uint8_t *base,
+ const NativeChunk *chunk) {
+ const size_t atomSize = sizeof(NativeSharedLibraryAtomV1);
+ size_t atomsArraySize = chunk->elementCount * atomSize;
+ uint8_t* atomsStart = reinterpret_cast<uint8_t*>
+ (operator new(atomsArraySize, std::nothrow));
+ if (atomsStart == nullptr)
+ return make_error_code(NativeReaderError::memory_error);
+ const size_t ivarElementSize = chunk->fileSize
+ / chunk->elementCount;
+ if ( ivarElementSize != sizeof(NativeSharedLibraryAtomIvarsV1) )
+ return make_error_code(NativeReaderError::file_malformed);
+ uint8_t* atomsEnd = atomsStart + atomsArraySize;
+ const NativeSharedLibraryAtomIvarsV1* ivarData =
+ reinterpret_cast<const NativeSharedLibraryAtomIvarsV1*>
+ (base + chunk->fileOffset);
+ for(uint8_t* s = atomsStart; s != atomsEnd; s += atomSize) {
+ NativeSharedLibraryAtomV1* atomAllocSpace =
+ reinterpret_cast<NativeSharedLibraryAtomV1*>(s);
+ new (atomAllocSpace) NativeSharedLibraryAtomV1(*this, ivarData);
+ ++ivarData;
+ }
+ this->_sharedLibraryAtoms._arrayStart = atomsStart;
+ 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(NativeReaderError::success);
+ }
+
+
+ // instantiate array of AbsoluteAtoms from v1 ivar data in file
+ std::error_code processAbsoluteAtomsV1(const uint8_t *base,
+ const NativeChunk *chunk) {
+ const size_t atomSize = sizeof(NativeAbsoluteAtomV1);
+ size_t atomsArraySize = chunk->elementCount * atomSize;
+ uint8_t* atomsStart = reinterpret_cast<uint8_t*>
+ (operator new(atomsArraySize, std::nothrow));
+ if (atomsStart == nullptr)
+ return make_error_code(NativeReaderError::memory_error);
+ const size_t ivarElementSize = chunk->fileSize
+ / chunk->elementCount;
+ if ( ivarElementSize != sizeof(NativeAbsoluteAtomIvarsV1) )
+ return make_error_code(NativeReaderError::file_malformed);
+ uint8_t* atomsEnd = atomsStart + atomsArraySize;
+ const NativeAbsoluteAtomIvarsV1* ivarData =
+ reinterpret_cast<const NativeAbsoluteAtomIvarsV1*>
+ (base + chunk->fileOffset);
+ for(uint8_t* s = atomsStart; s != atomsEnd; s += atomSize) {
+ NativeAbsoluteAtomV1* atomAllocSpace =
+ reinterpret_cast<NativeAbsoluteAtomV1*>(s);
+ new (atomAllocSpace) NativeAbsoluteAtomV1(*this, ivarData);
+ ++ivarData;
+ }
+ this->_absoluteAtoms._arrayStart = atomsStart;
+ 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(NativeReaderError::success);
+ }
+
+ template <class T, class U>
+ std::error_code
+ processReferences(const uint8_t *base, const NativeChunk *chunk,
+ uint8_t *&refsStart, uint8_t *&refsEnd) const {
+ if (chunk->elementCount == 0)
+ return make_error_code(NativeReaderError::success);
+ size_t refsArraySize = chunk->elementCount * sizeof(T);
+ refsStart = reinterpret_cast<uint8_t *>(
+ operator new(refsArraySize, std::nothrow));
+ if (refsStart == nullptr)
+ return make_error_code(NativeReaderError::memory_error);
+ const size_t ivarElementSize = chunk->fileSize / chunk->elementCount;
+ if (ivarElementSize != sizeof(U))
+ return make_error_code(NativeReaderError::file_malformed);
+ refsEnd = refsStart + refsArraySize;
+ const U* ivarData = reinterpret_cast<const U *>(base + chunk->fileOffset);
+ for (uint8_t *s = refsStart; s != refsEnd; s += sizeof(T), ++ivarData) {
+ T *atomAllocSpace = reinterpret_cast<T *>(s);
+ new (atomAllocSpace) T(*this, ivarData);
+ }
+ return make_error_code(NativeReaderError::success);
+ }
+
+ // instantiate array of References from v1 ivar data in file
+ std::error_code processReferencesV1(const uint8_t *base,
+ const NativeChunk *chunk) {
+ uint8_t *refsStart, *refsEnd;
+ if (std::error_code ec =
+ processReferences<NativeReferenceV1, NativeReferenceIvarsV1>(
+ base, chunk, refsStart, refsEnd))
+ return ec;
+ this->_referencesV1.arrayStart = refsStart;
+ this->_referencesV1.arrayEnd = refsEnd;
+ this->_referencesV1.elementSize = sizeof(NativeReferenceV1);
+ this->_referencesV1.elementCount = chunk->elementCount;
+ DEBUG_WITH_TYPE("ReaderNative", {
+ llvm::dbgs() << " chunk ReferencesV1: "
+ << " count=" << chunk->elementCount
+ << " chunkSize=" << chunk->fileSize << "\n";
+ });
+ return make_error_code(NativeReaderError::success);
+ }
+
+ // instantiate array of References from v2 ivar data in file
+ std::error_code processReferencesV2(const uint8_t *base,
+ const NativeChunk *chunk) {
+ uint8_t *refsStart, *refsEnd;
+ if (std::error_code ec =
+ processReferences<NativeReferenceV2, NativeReferenceIvarsV2>(
+ base, chunk, refsStart, refsEnd))
+ return ec;
+ this->_referencesV2.arrayStart = refsStart;
+ this->_referencesV2.arrayEnd = refsEnd;
+ this->_referencesV2.elementSize = sizeof(NativeReferenceV2);
+ this->_referencesV2.elementCount = chunk->elementCount;
+ DEBUG_WITH_TYPE("ReaderNative", {
+ llvm::dbgs() << " chunk ReferencesV2: "
+ << " count=" << chunk->elementCount
+ << " chunkSize=" << chunk->fileSize << "\n";
+ });
+ return make_error_code(NativeReaderError::success);
+ }
+
+ // set up pointers to target table
+ std::error_code processTargetsTable(const uint8_t *base,
+ const NativeChunk *chunk) {
+ const uint32_t* targetIndexes = reinterpret_cast<const uint32_t*>
+ (base + chunk->fileOffset);
+ this->_targetsTableCount = chunk->elementCount;
+ this->_targetsTable = new const Atom*[chunk->elementCount];
+ for (uint32_t i=0; i < chunk->elementCount; ++i) {
+ const uint32_t index = targetIndexes[i];
+ if ( index < _definedAtoms._elementCount ) {
+ const uint8_t* p = _definedAtoms._arrayStart
+ + index * _definedAtoms._elementSize;
+ this->_targetsTable[i] = reinterpret_cast<const DefinedAtom*>(p);
+ continue;
+ }
+ const uint32_t undefIndex = index - _definedAtoms._elementCount;
+ if ( undefIndex < _undefinedAtoms._elementCount ) {
+ const uint8_t* p = _undefinedAtoms._arrayStart
+ + undefIndex * _undefinedAtoms._elementSize;
+ this->_targetsTable[i] = reinterpret_cast<const UndefinedAtom*>(p);
+ continue;
+ }
+ const uint32_t slIndex = index - _definedAtoms._elementCount
+ - _undefinedAtoms._elementCount;
+ if ( slIndex < _sharedLibraryAtoms._elementCount ) {
+ const uint8_t* p = _sharedLibraryAtoms._arrayStart
+ + slIndex * _sharedLibraryAtoms._elementSize;
+ this->_targetsTable[i] = reinterpret_cast<const SharedLibraryAtom*>(p);
+ continue;
+ }
+ const uint32_t abIndex = index - _definedAtoms._elementCount
+ - _undefinedAtoms._elementCount
+ - _sharedLibraryAtoms._elementCount;
+ if ( abIndex < _absoluteAtoms._elementCount ) {
+ const uint8_t* p = _absoluteAtoms._arrayStart
+ + abIndex * _absoluteAtoms._elementSize;
+ this->_targetsTable[i] = reinterpret_cast<const AbsoluteAtom*>(p);
+ continue;
+ }
+ return make_error_code(NativeReaderError::file_malformed);
+ }
+ DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
+ << " chunk Targets Table: "
+ << " count=" << chunk->elementCount
+ << " chunkSize=" << chunk->fileSize
+ << "\n");
+ return make_error_code(NativeReaderError::success);
+ }
+
+
+ // set up pointers to addend pool in file
+ std::error_code processAddendsTable(const uint8_t *base,
+ const NativeChunk *chunk) {
+ 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(NativeReaderError::success);
+ }
+
+ // set up pointers to string pool in file
+ std::error_code processStrings(const uint8_t *base,
+ 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(NativeReaderError::success);
+ }
+
+ // set up pointers to content area in file
+ std::error_code processContent(const uint8_t *base,
+ 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(NativeReaderError::success);
+ }
+
+ StringRef string(uint32_t offset) const {
+ assert(offset < _stringsMaxOffset);
+ return StringRef(&_strings[offset]);
+ }
+
+ Reference::Addend addend(uint32_t index) const {
+ if ( index == 0 )
+ return 0; // addend index zero is used to mean "no addend"
+ assert(index <= _addendsMaxIndex);
+ return _addends[index-1]; // one-based indexing
+ }
+
+ const NativeAtomAttributesV1& attribute(uint32_t off) const {
+ assert(off < _attributesMaxOffset);
+ return *reinterpret_cast<const NativeAtomAttributesV1*>(_attributes + off);
+ }
+
+ const NativeAtomAttributesV1& absAttribute(uint32_t off) const {
+ assert(off < _absAbsoluteMaxOffset);
+ return *reinterpret_cast<const NativeAtomAttributesV1*>(_absAttributes + off);
+ }
+
+ const uint8_t* content(uint32_t offset, uint32_t size) const {
+ const uint8_t* result = _contentStart + offset;
+ assert((result+size) <= _contentEnd);
+ return result;
+ }
+
+ const Reference* referenceByIndex(uintptr_t index) const {
+ if (index < _referencesV1.elementCount) {
+ return reinterpret_cast<const NativeReferenceV1*>(
+ _referencesV1.arrayStart + index * _referencesV1.elementSize);
+ }
+ assert(index < _referencesV2.elementCount);
+ return reinterpret_cast<const NativeReferenceV2*>(
+ _referencesV2.arrayStart + index * _referencesV2.elementSize);
+ }
+
+ const Atom* targetV1(uint16_t index) const {
+ if ( index == NativeReferenceIvarsV1::noTarget )
+ return nullptr;
+ assert(index < _targetsTableCount);
+ return _targetsTable[index];
+ }
+
+ void setTargetV1(uint16_t index, const Atom* newAtom) const {
+ assert(index != NativeReferenceIvarsV1::noTarget);
+ assert(index > _targetsTableCount);
+ _targetsTable[index] = newAtom;
+ }
+
+ const Atom* targetV2(uint32_t index) const {
+ if (index == NativeReferenceIvarsV2::noTarget)
+ return nullptr;
+ assert(index < _targetsTableCount);
+ return _targetsTable[index];
+ }
+
+ void setTargetV2(uint32_t index, const Atom* newAtom) const {
+ assert(index != NativeReferenceIvarsV2::noTarget);
+ assert(index > _targetsTableCount);
+ _targetsTable[index] = newAtom;
+ }
+
+ template <typename T>
+ class AtomArray : public File::atom_collection<T> {
+ public:
+ AtomArray() : _arrayStart(nullptr), _arrayEnd(nullptr),
+ _elementSize(0), _elementCount(0) { }
+
+ virtual atom_iterator<T> begin() const {
+ return atom_iterator<T>(*this, reinterpret_cast<const void*>(_arrayStart));
+ }
+ virtual atom_iterator<T> end() const{
+ return atom_iterator<T>(*this, reinterpret_cast<const void*>(_arrayEnd));
+ }
+ virtual const T* deref(const void* it) const {
+ return reinterpret_cast<const T*>(it);
+ }
+ virtual void next(const void*& it) const {
+ const uint8_t* p = reinterpret_cast<const uint8_t*>(it);
+ p += _elementSize;
+ it = reinterpret_cast<const void*>(p);
+ }
+ virtual uint64_t size() const { return _elementCount; }
+ const uint8_t *_arrayStart;
+ const uint8_t *_arrayEnd;
+ uint32_t _elementSize;
+ uint32_t _elementCount;
+ };
+
+ struct IvarArray {
+ IvarArray() :
+ arrayStart(nullptr),
+ arrayEnd(nullptr),
+ elementSize(0),
+ elementCount(0) { }
+
+ const uint8_t* arrayStart;
+ const uint8_t* arrayEnd;
+ uint32_t elementSize;
+ uint32_t elementCount;
+ };
+
+ std::unique_ptr<MemoryBuffer> _mb;
+ const NativeFileHeader* _header;
+ AtomArray<DefinedAtom> _definedAtoms;
+ AtomArray<UndefinedAtom> _undefinedAtoms;
+ AtomArray<SharedLibraryAtom> _sharedLibraryAtoms;
+ AtomArray<AbsoluteAtom> _absoluteAtoms;
+ const uint8_t* _absAttributes;
+ uint32_t _absAbsoluteMaxOffset;
+ const uint8_t* _attributes;
+ uint32_t _attributesMaxOffset;
+ IvarArray _referencesV1;
+ IvarArray _referencesV2;
+ const Atom** _targetsTable;
+ uint32_t _targetsTableCount;
+ const char* _strings;
+ uint32_t _stringsMaxOffset;
+ const Reference::Addend* _addends;
+ uint32_t _addendsMaxIndex;
+ const uint8_t *_contentStart;
+ const uint8_t *_contentEnd;
+};
+
+inline const lld::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 StringRef NativeDefinedAtomV1::name() const {
+ return _file->string(_ivarData->nameOffset);
+}
+
+inline const NativeAtomAttributesV1& NativeDefinedAtomV1::attributes() const {
+ return _file->attribute(_ivarData->attributesOffset);
+}
+
+inline ArrayRef<uint8_t> NativeDefinedAtomV1::rawContent() const {
+ if (!occupiesDiskSpace())
+ return ArrayRef<uint8_t>();
+ const uint8_t* p = _file->content(_ivarData->contentOffset,
+ _ivarData->contentSize);
+ return ArrayRef<uint8_t>(p, _ivarData->contentSize);
+}
+
+inline StringRef NativeDefinedAtomV1::customSectionName() const {
+ uint32_t offset = attributes().sectionNameOffset;
+ return _file->string(offset);
+}
+
+DefinedAtom::reference_iterator NativeDefinedAtomV1::begin() const {
+ uintptr_t index = _ivarData->referencesStartIndex;
+ const void* it = reinterpret_cast<const void*>(index);
+ return reference_iterator(*this, it);
+}
+
+DefinedAtom::reference_iterator NativeDefinedAtomV1::end() const {
+ uintptr_t index = _ivarData->referencesStartIndex+_ivarData->referencesCount;
+ const void* it = reinterpret_cast<const void*>(index);
+ return reference_iterator(*this, it);
+}
+
+const Reference* NativeDefinedAtomV1::derefIterator(const void* it) const {
+ uintptr_t index = reinterpret_cast<uintptr_t>(it);
+ return _file->referenceByIndex(index);
+}
+
+void NativeDefinedAtomV1::incrementIterator(const void*& it) const {
+ uintptr_t index = reinterpret_cast<uintptr_t>(it);
+ ++index;
+ it = reinterpret_cast<const void*>(index);
+}
+
+inline const lld::File& NativeUndefinedAtomV1::file() const {
+ return *_file;
+}
+
+inline StringRef NativeUndefinedAtomV1::name() const {
+ return _file->string(_ivarData->nameOffset);
+}
+
+inline const UndefinedAtom *NativeUndefinedAtomV1::fallback() const {
+ if (!_ivarData->fallbackNameOffset)
+ return nullptr;
+ if (!_fallback)
+ _fallback.reset(new SimpleUndefinedAtom(
+ *_file, _file->string(_ivarData->fallbackNameOffset)));
+ return _fallback.get();
+}
+
+inline const lld::File& NativeSharedLibraryAtomV1::file() const {
+ return *_file;
+}
+
+inline StringRef NativeSharedLibraryAtomV1::name() const {
+ return _file->string(_ivarData->nameOffset);
+}
+
+inline StringRef NativeSharedLibraryAtomV1::loadName() const {
+ return _file->string(_ivarData->loadNameOffset);
+}
+
+
+
+inline const lld::File& NativeAbsoluteAtomV1::file() const {
+ return *_file;
+}
+
+inline StringRef NativeAbsoluteAtomV1::name() const {
+ return _file->string(_ivarData->nameOffset);
+}
+
+inline const NativeAtomAttributesV1& NativeAbsoluteAtomV1::absAttributes() const {
+ return _file->absAttribute(_ivarData->attributesOffset);
+}
+
+inline const Atom* NativeReferenceV1::target() const {
+ return _file->targetV1(_ivarData->targetIndex);
+}
+
+inline Reference::Addend NativeReferenceV1::addend() const {
+ return _file->addend(_ivarData->addendIndex);
+}
+
+inline void NativeReferenceV1::setTarget(const Atom* newAtom) {
+ return _file->setTargetV1(_ivarData->targetIndex, newAtom);
+}
+
+inline void NativeReferenceV1::setAddend(Addend a) {
+ // Do nothing if addend value is not being changed.
+ if (addend() == a)
+ return;
+ llvm_unreachable("setAddend() not supported");
+}
+
+inline const Atom* NativeReferenceV2::target() const {
+ return _file->targetV2(_ivarData->targetIndex);
+}
+
+inline Reference::Addend NativeReferenceV2::addend() const {
+ return _ivarData->addend;
+}
+
+inline void NativeReferenceV2::setTarget(const Atom* newAtom) {
+ return _file->setTargetV2(_ivarData->targetIndex, newAtom);
+}
+
+inline void NativeReferenceV2::setAddend(Addend a) {
+ // Do nothing if addend value is not being changed.
+ if (addend() == a)
+ return;
+ llvm_unreachable("setAddend() not supported");
+}
+
+uint32_t NativeReferenceV2::tag() const { return _ivarData->tag; }
+
+} // end namespace native
+
+namespace {
+
+class NativeReader : public Reader {
+public:
+ virtual bool canParse(file_magic magic, StringRef,
+ const MemoryBuffer &mb) const override {
+ const NativeFileHeader *const header =
+ reinterpret_cast<const NativeFileHeader *>(mb.getBufferStart());
+ return (memcmp(header->magic, NATIVE_FILE_HEADER_MAGIC,
+ sizeof(header->magic)) == 0);
+ }
+
+ virtual std::error_code
+ loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
+ std::vector<std::unique_ptr<File>> &result) const override {
+ auto *file = new lld::native::File(std::move(mb));
+ result.push_back(std::unique_ptr<File>(file));
+ return std::error_code();
+ }
+};
+
+}
+
+void Registry::addSupportNativeObjects() {
+ add(std::unique_ptr<Reader>(new NativeReader()));
+}
+
+} // end namespace lld
diff --git a/lib/ReaderWriter/Native/WriterNative.cpp b/lib/ReaderWriter/Native/WriterNative.cpp
new file mode 100644
index 000000000000..5e01a6ce1c7c
--- /dev/null
+++ b/lib/ReaderWriter/Native/WriterNative.cpp
@@ -0,0 +1,566 @@
+//===- lib/ReaderWriter/Native/WriterNative.cpp ---------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeFileFormat.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/Writer.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdint>
+#include <set>
+#include <system_error>
+#include <vector>
+
+namespace lld {
+namespace native {
+
+///
+/// Class for writing native object files.
+///
+class Writer : public lld::Writer {
+public:
+ std::error_code writeFile(const lld::File &file, StringRef outPath) override {
+ // reserve first byte for unnamed atoms
+ _stringPool.push_back('\0');
+ // visit all atoms
+ for ( const DefinedAtom *defAtom : file.defined() ) {
+ this->addIVarsForDefinedAtom(*defAtom);
+ // We are trying to process all atoms, but the defined() iterator does not
+ // return group children. So, when a group parent is found, we need to
+ // handle each child atom.
+ if (defAtom->isGroupParent()) {
+ for (const Reference *r : *defAtom) {
+ if (r->kindNamespace() != lld::Reference::KindNamespace::all)
+ continue;
+ if (r->kindValue() == lld::Reference::kindGroupChild) {
+ const DefinedAtom *target = dyn_cast<DefinedAtom>(r->target());
+ assert(target && "Internal Error: kindGroupChild references need "
+ "to be associated with Defined Atoms only");
+ this->addIVarsForDefinedAtom(*target);
+ }
+ }
+ }
+ }
+ for ( const UndefinedAtom *undefAtom : file.undefined() ) {
+ this->addIVarsForUndefinedAtom(*undefAtom);
+ }
+ for ( const SharedLibraryAtom *shlibAtom : file.sharedLibrary() ) {
+ this->addIVarsForSharedLibraryAtom(*shlibAtom);
+ }
+ for ( const AbsoluteAtom *absAtom : file.absolute() ) {
+ this->addIVarsForAbsoluteAtom(*absAtom);
+ }
+
+ maybeConvertReferencesToV1();
+
+ // construct file header based on atom information accumulated
+ this->makeHeader();
+
+ std::error_code ec;
+ llvm::raw_fd_ostream out(outPath, ec, llvm::sys::fs::F_None);
+ if (ec)
+ return ec;
+
+ this->write(out);
+
+ return std::error_code();
+ }
+
+ virtual ~Writer() {
+ }
+
+private:
+
+ // write the lld::File in native format to the specified stream
+ void write(raw_ostream &out) {
+ assert(out.tell() == 0);
+ out.write((char*)_headerBuffer, _headerBufferSize);
+
+ writeChunk(out, _definedAtomIvars, NCS_DefinedAtomsV1);
+ writeChunk(out, _attributes, NCS_AttributesArrayV1);
+ writeChunk(out, _undefinedAtomIvars, NCS_UndefinedAtomsV1);
+ writeChunk(out, _sharedLibraryAtomIvars, NCS_SharedLibraryAtomsV1);
+ writeChunk(out, _absoluteAtomIvars, NCS_AbsoluteAtomsV1);
+ writeChunk(out, _absAttributes, NCS_AbsoluteAttributesV1);
+ writeChunk(out, _stringPool, NCS_Strings);
+ writeChunk(out, _referencesV1, NCS_ReferencesArrayV1);
+ writeChunk(out, _referencesV2, NCS_ReferencesArrayV2);
+
+ if (!_targetsTableIndex.empty()) {
+ assert(out.tell() == findChunk(NCS_TargetsTable).fileOffset);
+ writeTargetTable(out);
+ }
+
+ if (!_addendsTableIndex.empty()) {
+ assert(out.tell() == findChunk(NCS_AddendsTable).fileOffset);
+ writeAddendTable(out);
+ }
+
+ writeChunk(out, _contentPool, NCS_Content);
+ }
+
+ template<class T>
+ void writeChunk(raw_ostream &out, std::vector<T> &vector, uint32_t signature) {
+ if (vector.empty())
+ return;
+ assert(out.tell() == findChunk(signature).fileOffset);
+ out.write((char*)&vector[0], vector.size() * sizeof(T));
+ }
+
+ void addIVarsForDefinedAtom(const DefinedAtom& atom) {
+ _definedAtomIndex[&atom] = _definedAtomIvars.size();
+ NativeDefinedAtomIvarsV1 ivar;
+ unsigned refsCount;
+ ivar.nameOffset = getNameOffset(atom);
+ ivar.attributesOffset = getAttributeOffset(atom);
+ ivar.referencesStartIndex = getReferencesIndex(atom, refsCount);
+ ivar.referencesCount = refsCount;
+ ivar.contentOffset = getContentOffset(atom);
+ ivar.contentSize = atom.size();
+ ivar.sectionSize = atom.sectionSize();
+ _definedAtomIvars.push_back(ivar);
+ }
+
+ void addIVarsForUndefinedAtom(const UndefinedAtom& atom) {
+ _undefinedAtomIndex[&atom] = _undefinedAtomIvars.size();
+ NativeUndefinedAtomIvarsV1 ivar;
+ ivar.nameOffset = getNameOffset(atom);
+ ivar.flags = (atom.canBeNull() & 0x03);
+ ivar.fallbackNameOffset = 0;
+ if (atom.fallback())
+ ivar.fallbackNameOffset = getNameOffset(*atom.fallback());
+ _undefinedAtomIvars.push_back(ivar);
+ }
+
+ void addIVarsForSharedLibraryAtom(const SharedLibraryAtom& atom) {
+ _sharedLibraryAtomIndex[&atom] = _sharedLibraryAtomIvars.size();
+ NativeSharedLibraryAtomIvarsV1 ivar;
+ ivar.size = atom.size();
+ ivar.nameOffset = getNameOffset(atom);
+ ivar.loadNameOffset = getSharedLibraryNameOffset(atom.loadName());
+ ivar.type = (uint32_t)atom.type();
+ ivar.flags = atom.canBeNullAtRuntime();
+ _sharedLibraryAtomIvars.push_back(ivar);
+ }
+
+ void addIVarsForAbsoluteAtom(const AbsoluteAtom& atom) {
+ _absoluteAtomIndex[&atom] = _absoluteAtomIvars.size();
+ NativeAbsoluteAtomIvarsV1 ivar;
+ ivar.nameOffset = getNameOffset(atom);
+ ivar.attributesOffset = getAttributeOffset(atom);
+ ivar.reserved = 0;
+ ivar.value = atom.value();
+ _absoluteAtomIvars.push_back(ivar);
+ }
+
+ void convertReferencesToV1() {
+ for (const NativeReferenceIvarsV2 &v2 : _referencesV2) {
+ NativeReferenceIvarsV1 v1;
+ v1.offsetInAtom = v2.offsetInAtom;
+ v1.kindNamespace = v2.kindNamespace;
+ v1.kindArch = v2.kindArch;
+ v1.kindValue = v2.kindValue;
+ v1.targetIndex = (v2.targetIndex == NativeReferenceIvarsV2::noTarget) ?
+ (uint16_t)NativeReferenceIvarsV1::noTarget : v2.targetIndex;
+ v1.addendIndex = this->getAddendIndex(v2.addend);
+ _referencesV1.push_back(v1);
+ }
+ _referencesV2.clear();
+ }
+
+ bool canConvertReferenceToV1(const NativeReferenceIvarsV2 &ref) {
+ bool validOffset = (ref.offsetInAtom == NativeReferenceIvarsV2::noTarget) ||
+ ref.offsetInAtom < NativeReferenceIvarsV1::noTarget;
+ return validOffset && ref.targetIndex < UINT16_MAX;
+ }
+
+ // Convert vector of NativeReferenceIvarsV2 to NativeReferenceIvarsV1 if
+ // possible.
+ void maybeConvertReferencesToV1() {
+ std::set<int64_t> addends;
+ for (const NativeReferenceIvarsV2 &ref : _referencesV2) {
+ if (!canConvertReferenceToV1(ref))
+ return;
+ addends.insert(ref.addend);
+ if (addends.size() >= UINT16_MAX)
+ return;
+ }
+ convertReferencesToV1();
+ }
+
+ // fill out native file header and chunk directory
+ void makeHeader() {
+ const bool hasDefines = !_definedAtomIvars.empty();
+ const bool hasUndefines = !_undefinedAtomIvars.empty();
+ const bool hasSharedLibraries = !_sharedLibraryAtomIvars.empty();
+ const bool hasAbsolutes = !_absoluteAtomIvars.empty();
+ const bool hasReferencesV1 = !_referencesV1.empty();
+ const bool hasReferencesV2 = !_referencesV2.empty();
+ const bool hasTargetsTable = !_targetsTableIndex.empty();
+ const bool hasAddendTable = !_addendsTableIndex.empty();
+ const bool hasContent = !_contentPool.empty();
+
+ int chunkCount = 1; // always have string pool chunk
+ if ( hasDefines ) chunkCount += 2;
+ if ( hasUndefines ) ++chunkCount;
+ if ( hasSharedLibraries ) ++chunkCount;
+ if ( hasAbsolutes ) chunkCount += 2;
+ if ( hasReferencesV1 ) ++chunkCount;
+ if ( hasReferencesV2 ) ++chunkCount;
+ if ( hasTargetsTable ) ++chunkCount;
+ if ( hasAddendTable ) ++chunkCount;
+ if ( hasContent ) ++chunkCount;
+
+ _headerBufferSize = sizeof(NativeFileHeader)
+ + chunkCount*sizeof(NativeChunk);
+ _headerBuffer = reinterpret_cast<NativeFileHeader*>
+ (operator new(_headerBufferSize, std::nothrow));
+ NativeChunk *chunks =
+ reinterpret_cast<NativeChunk*>(reinterpret_cast<char*>(_headerBuffer)
+ + sizeof(NativeFileHeader));
+ memcpy(_headerBuffer->magic, NATIVE_FILE_HEADER_MAGIC,
+ sizeof(_headerBuffer->magic));
+ _headerBuffer->endian = NFH_LittleEndian;
+ _headerBuffer->architecture = 0;
+ _headerBuffer->fileSize = 0;
+ _headerBuffer->chunkCount = chunkCount;
+
+ // create chunk for defined atom ivar array
+ int nextIndex = 0;
+ uint32_t nextFileOffset = _headerBufferSize;
+ if (hasDefines) {
+ fillChunkHeader(chunks[nextIndex++], nextFileOffset, _definedAtomIvars,
+ NCS_DefinedAtomsV1);
+
+ // create chunk for attributes
+ fillChunkHeader(chunks[nextIndex++], nextFileOffset, _attributes,
+ NCS_AttributesArrayV1);
+ }
+
+ // create chunk for undefined atom array
+ if (hasUndefines)
+ fillChunkHeader(chunks[nextIndex++], nextFileOffset, _undefinedAtomIvars,
+ NCS_UndefinedAtomsV1);
+
+ // create chunk for shared library atom array
+ if (hasSharedLibraries)
+ fillChunkHeader(chunks[nextIndex++], nextFileOffset,
+ _sharedLibraryAtomIvars, NCS_SharedLibraryAtomsV1);
+
+ // create chunk for shared library atom array
+ if (hasAbsolutes) {
+ fillChunkHeader(chunks[nextIndex++], nextFileOffset, _absoluteAtomIvars,
+ NCS_AbsoluteAtomsV1);
+
+ // create chunk for attributes
+ fillChunkHeader(chunks[nextIndex++], nextFileOffset, _absAttributes,
+ NCS_AbsoluteAttributesV1);
+ }
+
+ // create chunk for symbol strings
+ // pad end of string pool to 4-bytes
+ while ((_stringPool.size() % 4) != 0)
+ _stringPool.push_back('\0');
+ fillChunkHeader(chunks[nextIndex++], nextFileOffset, _stringPool,
+ NCS_Strings);
+
+ // create chunk for referencesV2
+ if (hasReferencesV1)
+ fillChunkHeader(chunks[nextIndex++], nextFileOffset, _referencesV1,
+ NCS_ReferencesArrayV1);
+
+ // create chunk for referencesV2
+ if (hasReferencesV2)
+ fillChunkHeader(chunks[nextIndex++], nextFileOffset, _referencesV2,
+ NCS_ReferencesArrayV2);
+
+ // create chunk for target table
+ if (hasTargetsTable) {
+ NativeChunk& cht = chunks[nextIndex++];
+ cht.signature = NCS_TargetsTable;
+ cht.fileOffset = nextFileOffset;
+ cht.fileSize = _targetsTableIndex.size() * sizeof(uint32_t);
+ cht.elementCount = _targetsTableIndex.size();
+ nextFileOffset = cht.fileOffset + cht.fileSize;
+ }
+
+ // create chunk for addend table
+ if (hasAddendTable) {
+ NativeChunk& chad = chunks[nextIndex++];
+ chad.signature = NCS_AddendsTable;
+ chad.fileOffset = nextFileOffset;
+ chad.fileSize = _addendsTableIndex.size() * sizeof(Reference::Addend);
+ chad.elementCount = _addendsTableIndex.size();
+ nextFileOffset = chad.fileOffset + chad.fileSize;
+ }
+
+ // create chunk for content
+ if (hasContent)
+ fillChunkHeader(chunks[nextIndex++], nextFileOffset, _contentPool,
+ NCS_Content);
+
+ _headerBuffer->fileSize = nextFileOffset;
+ }
+
+ template<class T>
+ void fillChunkHeader(NativeChunk &chunk, uint32_t &nextFileOffset,
+ const std::vector<T> &data, uint32_t signature) {
+ chunk.signature = signature;
+ chunk.fileOffset = nextFileOffset;
+ chunk.fileSize = data.size() * sizeof(T);
+ chunk.elementCount = data.size();
+ nextFileOffset = chunk.fileOffset + chunk.fileSize;
+ }
+
+ // scan header to find particular chunk
+ NativeChunk& findChunk(uint32_t signature) {
+ const uint32_t chunkCount = _headerBuffer->chunkCount;
+ NativeChunk* chunks =
+ reinterpret_cast<NativeChunk*>(reinterpret_cast<char*>(_headerBuffer)
+ + sizeof(NativeFileHeader));
+ for (uint32_t i=0; i < chunkCount; ++i) {
+ if ( chunks[i].signature == signature )
+ return chunks[i];
+ }
+ llvm_unreachable("findChunk() signature not found");
+ }
+
+ // append atom name to string pool and return offset
+ uint32_t getNameOffset(const Atom& atom) {
+ return this->getNameOffset(atom.name());
+ }
+
+ // check if name is already in pool or append and return offset
+ uint32_t getSharedLibraryNameOffset(StringRef name) {
+ assert(!name.empty());
+ // look to see if this library name was used by another atom
+ for (auto &it : _sharedLibraryNames)
+ if (name.equals(it.first))
+ return it.second;
+ // first use of this library name
+ uint32_t result = this->getNameOffset(name);
+ _sharedLibraryNames.push_back(std::make_pair(name, result));
+ return result;
+ }
+
+ // append atom name to string pool and return offset
+ uint32_t getNameOffset(StringRef name) {
+ if ( name.empty() )
+ return 0;
+ uint32_t result = _stringPool.size();
+ _stringPool.insert(_stringPool.end(), name.begin(), name.end());
+ _stringPool.push_back(0);
+ return result;
+ }
+
+ // append atom cotent to content pool and return offset
+ uint32_t getContentOffset(const DefinedAtom& atom) {
+ if (!atom.occupiesDiskSpace())
+ return 0;
+ uint32_t result = _contentPool.size();
+ ArrayRef<uint8_t> cont = atom.rawContent();
+ _contentPool.insert(_contentPool.end(), cont.begin(), cont.end());
+ return result;
+ }
+
+ // reuse existing attributes entry or create a new one and return offet
+ uint32_t getAttributeOffset(const DefinedAtom& atom) {
+ NativeAtomAttributesV1 attrs = computeAttributesV1(atom);
+ return getOrPushAttribute(_attributes, attrs);
+ }
+
+ uint32_t getAttributeOffset(const AbsoluteAtom& atom) {
+ NativeAtomAttributesV1 attrs = computeAbsoluteAttributes(atom);
+ return getOrPushAttribute(_absAttributes, attrs);
+ }
+
+ uint32_t getOrPushAttribute(std::vector<NativeAtomAttributesV1> &dest,
+ const NativeAtomAttributesV1 &attrs) {
+ for (size_t i = 0, e = dest.size(); i < e; ++i) {
+ if (!memcmp(&dest[i], &attrs, sizeof(attrs))) {
+ // found that this set of attributes already used, so re-use
+ return i * sizeof(attrs);
+ }
+ }
+ // append new attribute set to end
+ uint32_t result = dest.size() * sizeof(attrs);
+ dest.push_back(attrs);
+ return result;
+ }
+
+ uint32_t sectionNameOffset(const DefinedAtom& atom) {
+ // if section based on content, then no custom section name available
+ if (atom.sectionChoice() == DefinedAtom::sectionBasedOnContent)
+ return 0;
+ StringRef name = atom.customSectionName();
+ assert(!name.empty());
+ // look to see if this section name was used by another atom
+ for (auto &it : _sectionNames)
+ 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(name, result));
+ return result;
+ }
+
+ NativeAtomAttributesV1 computeAttributesV1(const DefinedAtom& atom) {
+ NativeAtomAttributesV1 attrs;
+ attrs.sectionNameOffset = sectionNameOffset(atom);
+ attrs.align2 = atom.alignment().powerOf2;
+ attrs.alignModulus = atom.alignment().modulus;
+ 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.dynamicExport = atom.dynamicExport();
+ attrs.codeModel = atom.codeModel();
+ attrs.permissions = atom.permissions();
+ return attrs;
+ }
+
+ NativeAtomAttributesV1 computeAbsoluteAttributes(const AbsoluteAtom& atom) {
+ NativeAtomAttributesV1 attrs;
+ attrs.scope = atom.scope();
+ return attrs;
+ }
+
+ // add references for this atom in a contiguous block in NCS_ReferencesArrayV2
+ uint32_t getReferencesIndex(const DefinedAtom& atom, unsigned& refsCount) {
+ size_t startRefSize = _referencesV2.size();
+ uint32_t result = startRefSize;
+ for (const Reference *ref : atom) {
+ NativeReferenceIvarsV2 nref;
+ nref.offsetInAtom = ref->offsetInAtom();
+ nref.kindNamespace = (uint8_t)ref->kindNamespace();
+ nref.kindArch = (uint8_t)ref->kindArch();
+ nref.kindValue = ref->kindValue();
+ nref.targetIndex = this->getTargetIndex(ref->target());
+ nref.addend = ref->addend();
+ nref.tag = ref->tag();
+ _referencesV2.push_back(nref);
+ }
+ refsCount = _referencesV2.size() - startRefSize;
+ return (refsCount == 0) ? 0 : result;
+ }
+
+ uint32_t getTargetIndex(const Atom* target) {
+ if ( target == nullptr )
+ return NativeReferenceIvarsV2::noTarget;
+ TargetToIndex::const_iterator pos = _targetsTableIndex.find(target);
+ if ( pos != _targetsTableIndex.end() ) {
+ return pos->second;
+ }
+ uint32_t result = _targetsTableIndex.size();
+ _targetsTableIndex[target] = result;
+ return result;
+ }
+
+ void writeTargetTable(raw_ostream &out) {
+ // Build table of target indexes
+ uint32_t maxTargetIndex = _targetsTableIndex.size();
+ assert(maxTargetIndex > 0);
+ std::vector<uint32_t> targetIndexes(maxTargetIndex);
+ for (auto &it : _targetsTableIndex) {
+ const Atom* atom = it.first;
+ uint32_t targetIndex = it.second;
+ assert(targetIndex < maxTargetIndex);
+
+ TargetToIndex::iterator pos = _definedAtomIndex.find(atom);
+ if (pos != _definedAtomIndex.end()) {
+ targetIndexes[targetIndex] = pos->second;
+ continue;
+ }
+ uint32_t base = _definedAtomIvars.size();
+
+ pos = _undefinedAtomIndex.find(atom);
+ if (pos != _undefinedAtomIndex.end()) {
+ targetIndexes[targetIndex] = pos->second + base;
+ continue;
+ }
+ base += _undefinedAtomIndex.size();
+
+ pos = _sharedLibraryAtomIndex.find(atom);
+ if (pos != _sharedLibraryAtomIndex.end()) {
+ targetIndexes[targetIndex] = pos->second + base;
+ continue;
+ }
+ base += _sharedLibraryAtomIndex.size();
+
+ pos = _absoluteAtomIndex.find(atom);
+ assert(pos != _absoluteAtomIndex.end());
+ targetIndexes[targetIndex] = pos->second + base;
+ }
+ // write table
+ out.write((char*)&targetIndexes[0], maxTargetIndex * sizeof(uint32_t));
+ }
+
+ uint32_t getAddendIndex(Reference::Addend addend) {
+ if ( addend == 0 )
+ return 0; // addend index zero is used to mean "no addend"
+ AddendToIndex::const_iterator pos = _addendsTableIndex.find(addend);
+ if ( pos != _addendsTableIndex.end() ) {
+ return pos->second;
+ }
+ uint32_t result = _addendsTableIndex.size() + 1; // one-based index
+ _addendsTableIndex[addend] = result;
+ return result;
+ }
+
+ void writeAddendTable(raw_ostream &out) {
+ // Build table of addends
+ uint32_t maxAddendIndex = _addendsTableIndex.size();
+ std::vector<Reference::Addend> addends(maxAddendIndex);
+ for (auto &it : _addendsTableIndex) {
+ Reference::Addend addend = it.first;
+ uint32_t index = it.second;
+ assert(index <= maxAddendIndex);
+ addends[index-1] = addend;
+ }
+ // write table
+ out.write((char*)&addends[0], maxAddendIndex*sizeof(Reference::Addend));
+ }
+
+ typedef std::vector<std::pair<StringRef, uint32_t>> NameToOffsetVector;
+
+ typedef llvm::DenseMap<const Atom*, uint32_t> TargetToIndex;
+ typedef llvm::DenseMap<Reference::Addend, uint32_t> AddendToIndex;
+
+ NativeFileHeader* _headerBuffer;
+ size_t _headerBufferSize;
+ std::vector<char> _stringPool;
+ std::vector<uint8_t> _contentPool;
+ std::vector<NativeDefinedAtomIvarsV1> _definedAtomIvars;
+ std::vector<NativeAtomAttributesV1> _attributes;
+ std::vector<NativeAtomAttributesV1> _absAttributes;
+ std::vector<NativeUndefinedAtomIvarsV1> _undefinedAtomIvars;
+ std::vector<NativeSharedLibraryAtomIvarsV1> _sharedLibraryAtomIvars;
+ std::vector<NativeAbsoluteAtomIvarsV1> _absoluteAtomIvars;
+ std::vector<NativeReferenceIvarsV1> _referencesV1;
+ std::vector<NativeReferenceIvarsV2> _referencesV2;
+ TargetToIndex _targetsTableIndex;
+ TargetToIndex _definedAtomIndex;
+ TargetToIndex _undefinedAtomIndex;
+ TargetToIndex _sharedLibraryAtomIndex;
+ TargetToIndex _absoluteAtomIndex;
+ AddendToIndex _addendsTableIndex;
+ NameToOffsetVector _sectionNames;
+ NameToOffsetVector _sharedLibraryNames;
+};
+} // end namespace native
+
+std::unique_ptr<Writer> createWriterNative() {
+ return std::unique_ptr<Writer>(new native::Writer());
+}
+} // end namespace lld