summaryrefslogtreecommitdiff
path: root/lib/ReaderWriter/PECOFF/Atoms.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ReaderWriter/PECOFF/Atoms.h')
-rw-r--r--lib/ReaderWriter/PECOFF/Atoms.h312
1 files changed, 312 insertions, 0 deletions
diff --git a/lib/ReaderWriter/PECOFF/Atoms.h b/lib/ReaderWriter/PECOFF/Atoms.h
new file mode 100644
index 000000000000..257edc17884b
--- /dev/null
+++ b/lib/ReaderWriter/PECOFF/Atoms.h
@@ -0,0 +1,312 @@
+//===- lib/ReaderWriter/PECOFF/Atoms.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_PE_COFF_ATOMS_H
+#define LLD_READER_WRITER_PE_COFF_ATOMS_H
+
+#include "lld/Core/File.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Object/COFF.h"
+#include <vector>
+
+namespace lld {
+namespace pecoff {
+class COFFDefinedAtom;
+
+class COFFUndefinedAtom : public UndefinedAtom {
+public:
+ COFFUndefinedAtom(const File &file, StringRef name,
+ const UndefinedAtom *fallback = nullptr)
+ : _owningFile(file), _name(name), _fallback(fallback) {}
+
+ const File &file() const override { return _owningFile; }
+ StringRef name() const override { return _name; }
+ CanBeNull canBeNull() const override { return CanBeNull::canBeNullNever; }
+ const UndefinedAtom *fallback() const override { return _fallback; }
+
+private:
+ const File &_owningFile;
+ StringRef _name;
+ const UndefinedAtom *_fallback;
+};
+
+/// The base class of all COFF defined atoms. A derived class of
+/// COFFBaseDefinedAtom may represent atoms read from a file or atoms created
+/// by the linker. An example of the latter case is the jump table for symbols
+/// in a DLL.
+class COFFBaseDefinedAtom : public DefinedAtom {
+public:
+ enum class Kind {
+ File,
+ Internal
+ };
+
+ const File &file() const override { return _file; }
+ StringRef name() const override { return _name; }
+ Interposable interposable() const override { return interposeNo; }
+ Merge merge() const override { return mergeNo; }
+ Alignment alignment() const override { return Alignment(0); }
+ StringRef customSectionName() const override { return ""; }
+ DeadStripKind deadStrip() const override { return deadStripNormal; }
+
+ Kind getKind() const { return _kind; }
+
+ void addReference(std::unique_ptr<SimpleReference> reference) {
+ _references.push_back(std::move(reference));
+ }
+
+ reference_iterator begin() const override {
+ return reference_iterator(*this, reinterpret_cast<const void *>(0));
+ }
+
+ reference_iterator end() const override {
+ return reference_iterator(
+ *this, reinterpret_cast<const void *>(_references.size()));
+ }
+
+protected:
+ COFFBaseDefinedAtom(const File &file, StringRef name, Kind kind)
+ : _file(file), _name(name), _kind(kind) {}
+
+private:
+ const Reference *derefIterator(const void *iter) const override {
+ size_t index = reinterpret_cast<size_t>(iter);
+ return _references[index].get();
+ }
+
+ void incrementIterator(const void *&iter) const override {
+ size_t index = reinterpret_cast<size_t>(iter);
+ iter = reinterpret_cast<const void *>(index + 1);
+ }
+
+ const File &_file;
+ StringRef _name;
+ Kind _kind;
+ std::vector<std::unique_ptr<SimpleReference>> _references;
+};
+
+/// This is the root class of the atom read from a file. This class have two
+/// subclasses; one for the regular atom and another for the BSS atom.
+class COFFDefinedFileAtom : public COFFBaseDefinedAtom {
+public:
+ COFFDefinedFileAtom(const File &file, StringRef name, StringRef sectionName,
+ uint64_t sectionSize, Scope scope,
+ ContentType contentType, ContentPermissions perms,
+ uint64_t ordinal)
+ : COFFBaseDefinedAtom(file, name, Kind::File), _sectionName(sectionName),
+ _sectionSize(sectionSize), _scope(scope), _contentType(contentType),
+ _permissions(perms), _ordinal(ordinal), _alignment(0) {}
+
+ static bool classof(const COFFBaseDefinedAtom *atom) {
+ return atom->getKind() == Kind::File;
+ }
+
+ void setAlignment(Alignment val) { _alignment = val; }
+ SectionChoice sectionChoice() const override { return sectionCustomRequired; }
+ StringRef customSectionName() const override { return _sectionName; }
+ uint64_t sectionSize() const override { return _sectionSize; }
+ Scope scope() const override { return _scope; }
+ ContentType contentType() const override { return _contentType; }
+ ContentPermissions permissions() const override { return _permissions; }
+ uint64_t ordinal() const override { return _ordinal; }
+ Alignment alignment() const override { return _alignment; }
+
+ void addAssociate(const DefinedAtom *other) {
+ auto *ref = new SimpleReference(Reference::KindNamespace::all,
+ Reference::KindArch::all,
+ lld::Reference::kindAssociate, 0, other, 0);
+ addReference(std::unique_ptr<SimpleReference>(ref));
+ }
+
+private:
+ StringRef _sectionName;
+ uint64_t _sectionSize;
+ Scope _scope;
+ ContentType _contentType;
+ ContentPermissions _permissions;
+ uint64_t _ordinal;
+ Alignment _alignment;
+ std::vector<std::unique_ptr<SimpleReference>> _references;
+};
+
+// A COFFDefinedAtom represents an atom read from a file and has contents.
+class COFFDefinedAtom : public COFFDefinedFileAtom {
+public:
+ COFFDefinedAtom(const File &file, StringRef name, StringRef sectionName,
+ uint64_t sectionSize, Scope scope, ContentType type,
+ bool isComdat, ContentPermissions perms, Merge merge,
+ ArrayRef<uint8_t> data, uint64_t ordinal)
+ : COFFDefinedFileAtom(file, name, sectionName, sectionSize,
+ scope, type, perms, ordinal),
+ _isComdat(isComdat), _merge(merge), _dataref(data) {}
+
+ Merge merge() const override { return _merge; }
+ uint64_t size() const override { return _dataref.size(); }
+ ArrayRef<uint8_t> rawContent() const override { return _dataref; }
+
+ DeadStripKind deadStrip() const override {
+ // Only COMDAT symbols would be dead-stripped.
+ return _isComdat ? deadStripNormal : deadStripNever;
+ }
+
+private:
+ bool _isComdat;
+ Merge _merge;
+ ArrayRef<uint8_t> _dataref;
+};
+
+// A COFFDefinedAtom represents an atom for BSS section.
+class COFFBSSAtom : public COFFDefinedFileAtom {
+public:
+ COFFBSSAtom(const File &file, StringRef name, Scope scope,
+ ContentPermissions perms, Merge merge, uint32_t size,
+ uint64_t ordinal)
+ : COFFDefinedFileAtom(file, name, ".bss", 0, scope, typeZeroFill,
+ perms, ordinal),
+ _merge(merge), _size(size) {}
+
+ Merge merge() const override { return _merge; }
+ uint64_t size() const override { return _size; }
+ ArrayRef<uint8_t> rawContent() const override { return _contents; }
+
+private:
+ Merge _merge;
+ uint32_t _size;
+ std::vector<uint8_t> _contents;
+};
+
+/// A COFFLinkerInternalAtom represents a defined atom created by the linker,
+/// not read from file.
+class COFFLinkerInternalAtom : public COFFBaseDefinedAtom {
+public:
+ SectionChoice sectionChoice() const override { return sectionBasedOnContent; }
+ uint64_t ordinal() const override { return _ordinal; }
+ Scope scope() const override { return scopeGlobal; }
+ Alignment alignment() const override { return Alignment(0); }
+ uint64_t size() const override { return _data.size(); }
+ ArrayRef<uint8_t> rawContent() const override { return _data; }
+
+protected:
+ COFFLinkerInternalAtom(const File &file, uint64_t ordinal,
+ std::vector<uint8_t> data, StringRef symbolName = "")
+ : COFFBaseDefinedAtom(file, symbolName, Kind::Internal),
+ _ordinal(ordinal), _data(std::move(data)) {}
+
+private:
+ uint64_t _ordinal;
+ std::vector<uint8_t> _data;
+};
+
+class COFFStringAtom : public COFFLinkerInternalAtom {
+public:
+ COFFStringAtom(const File &file, uint64_t ordinal, StringRef sectionName,
+ StringRef contents)
+ : COFFLinkerInternalAtom(file, ordinal, stringRefToVector(contents)),
+ _sectionName(sectionName) {}
+
+ SectionChoice sectionChoice() const override { return sectionCustomRequired; }
+ StringRef customSectionName() const override { return _sectionName; }
+ ContentType contentType() const override { return typeData; }
+ ContentPermissions permissions() const override { return permR__; }
+
+private:
+ StringRef _sectionName;
+
+ std::vector<uint8_t> stringRefToVector(StringRef name) const {
+ std::vector<uint8_t> ret(name.size() + 1);
+ memcpy(&ret[0], name.data(), name.size());
+ ret[name.size()] = 0;
+ return ret;
+ }
+};
+
+// A COFFSharedLibraryAtom represents a symbol for data in an import library. A
+// reference to a COFFSharedLibraryAtom will be transformed to a real reference
+// to an import address table entry in Idata pass.
+class COFFSharedLibraryAtom : public SharedLibraryAtom {
+public:
+ COFFSharedLibraryAtom(const File &file, uint16_t hint, StringRef symbolName,
+ StringRef importName, StringRef dllName)
+ : _file(file), _hint(hint), _mangledName(addImpPrefix(symbolName)),
+ _importName(importName), _dllName(dllName), _importTableEntry(nullptr) {
+ }
+
+ const File &file() const override { return _file; }
+ uint16_t hint() const { return _hint; }
+
+ /// Returns the symbol name to be used by the core linker.
+ StringRef name() const override { return _mangledName; }
+
+ /// Returns the symbol name to be used in the import description table in the
+ /// COFF header.
+ virtual StringRef importName() const { return _importName; }
+
+ StringRef loadName() const override { return _dllName; }
+ bool canBeNullAtRuntime() const override { return false; }
+ Type type() const override { return Type::Unknown; }
+ uint64_t size() const override { return 0; }
+
+ void setImportTableEntry(const DefinedAtom *atom) {
+ _importTableEntry = atom;
+ }
+
+ const DefinedAtom *getImportTableEntry() const { return _importTableEntry; }
+
+private:
+ /// Mangle the symbol name by adding "__imp_" prefix. See the file comment of
+ /// ReaderImportHeader.cpp for details about the prefix.
+ std::string addImpPrefix(StringRef symbolName) {
+ std::string ret("__imp_");
+ ret.append(symbolName);
+ return ret;
+ }
+
+ const File &_file;
+ uint16_t _hint;
+ std::string _mangledName;
+ std::string _importName;
+ StringRef _dllName;
+ const DefinedAtom *_importTableEntry;
+};
+
+// An instance of this class represents "input file" for atoms created in a
+// pass. Atoms need to be associated to an input file even if it's not read from
+// a file, so we use this class for that.
+class VirtualFile : public SimpleFile {
+public:
+ VirtualFile(const LinkingContext &ctx)
+ : SimpleFile("<virtual-file>"), _nextOrdinal(0) {
+ setOrdinal(ctx.getNextOrdinalAndIncrement());
+ }
+
+ uint64_t getNextOrdinal() { return _nextOrdinal++; }
+
+private:
+ uint64_t _nextOrdinal;
+};
+
+//===----------------------------------------------------------------------===//
+//
+// Utility functions to handle layout edges.
+//
+//===----------------------------------------------------------------------===//
+
+template <typename T, typename U>
+void addLayoutEdge(T *a, U *b, uint32_t which) {
+ auto ref = new SimpleReference(Reference::KindNamespace::all,
+ Reference::KindArch::all,
+ which, 0, b, 0);
+ a->addReference(std::unique_ptr<SimpleReference>(ref));
+}
+
+} // namespace pecoff
+} // namespace lld
+
+#endif