summaryrefslogtreecommitdiff
path: root/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ReaderWriter/PECOFF/ReaderCOFF.cpp')
-rw-r--r--lib/ReaderWriter/PECOFF/ReaderCOFF.cpp1140
1 files changed, 0 insertions, 1140 deletions
diff --git a/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp b/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp
deleted file mode 100644
index f060bd8dc0bc0..0000000000000
--- a/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp
+++ /dev/null
@@ -1,1140 +0,0 @@
-//===- lib/ReaderWriter/PECOFF/ReaderCOFF.cpp -----------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "Atoms.h"
-#include "lld/Core/Alias.h"
-#include "lld/Core/File.h"
-#include "lld/Core/Reader.h"
-#include "lld/Driver/Driver.h"
-#include "lld/ReaderWriter/PECOFFLinkingContext.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/Object/COFF.h"
-#include "llvm/Support/Casting.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/Endian.h"
-#include "llvm/Support/Errc.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/FileOutputBuffer.h"
-#include "llvm/Support/FileUtilities.h"
-#include "llvm/Support/Memory.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/Program.h"
-#include "llvm/Support/raw_ostream.h"
-#include <algorithm>
-#include <map>
-#include <mutex>
-#include <set>
-#include <system_error>
-#include <vector>
-
-#define DEBUG_TYPE "ReaderCOFF"
-
-using lld::pecoff::COFFBSSAtom;
-using lld::pecoff::COFFDefinedAtom;
-using lld::pecoff::COFFDefinedFileAtom;
-using lld::pecoff::COFFUndefinedAtom;
-using llvm::object::coff_aux_section_definition;
-using llvm::object::coff_aux_weak_external;
-using llvm::object::coff_relocation;
-using llvm::object::coff_section;
-using llvm::object::coff_symbol;
-using llvm::support::ulittle32_t;
-
-using namespace lld;
-
-namespace {
-
-class BumpPtrStringSaver : public llvm::cl::StringSaver {
-public:
- const char *SaveString(const char *str) override {
- size_t len = strlen(str);
- std::lock_guard<std::mutex> lock(_allocMutex);
- char *copy = _alloc.Allocate<char>(len + 1);
- memcpy(copy, str, len + 1);
- return copy;
- }
-
-private:
- llvm::BumpPtrAllocator _alloc;
- std::mutex _allocMutex;
-};
-
-class FileCOFF : public File {
-private:
- typedef std::vector<llvm::object::COFFSymbolRef> SymbolVectorT;
- typedef std::map<const coff_section *, SymbolVectorT> SectionToSymbolsT;
-
-public:
- FileCOFF(std::unique_ptr<MemoryBuffer> mb, PECOFFLinkingContext &ctx)
- : File(mb->getBufferIdentifier(), kindObject), _mb(std::move(mb)),
- _compatibleWithSEH(false), _ordinal(1),
- _machineType(llvm::COFF::MT_Invalid), _ctx(ctx) {}
-
- std::error_code doParse() override;
- bool isCompatibleWithSEH() const { return _compatibleWithSEH; }
- llvm::COFF::MachineTypes getMachineType() { return _machineType; }
-
- 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;
- }
-
- void beforeLink() override;
-
- void addUndefinedSymbol(StringRef sym) {
- _undefinedAtoms._atoms.push_back(new (_alloc) COFFUndefinedAtom(*this, sym));
- }
-
- AliasAtom *createAlias(StringRef name, const DefinedAtom *target, int cnt);
- void createAlternateNameAtoms();
- std::error_code parseDirectiveSection(StringRef directives);
-
- mutable llvm::BumpPtrAllocator _alloc;
-
-private:
- std::error_code readSymbolTable(SymbolVectorT &result);
-
- void createAbsoluteAtoms(const SymbolVectorT &symbols,
- std::vector<const AbsoluteAtom *> &result);
-
- std::error_code
- createUndefinedAtoms(const SymbolVectorT &symbols,
- std::vector<const UndefinedAtom *> &result);
-
- std::error_code
- createDefinedSymbols(const SymbolVectorT &symbols,
- std::vector<const DefinedAtom *> &result);
-
- std::error_code cacheSectionAttributes();
- std::error_code maybeCreateSXDataAtoms();
-
- std::error_code
- AtomizeDefinedSymbolsInSection(const coff_section *section,
- SymbolVectorT &symbols,
- std::vector<COFFDefinedFileAtom *> &atoms);
-
- std::error_code
- AtomizeDefinedSymbols(SectionToSymbolsT &definedSymbols,
- std::vector<const DefinedAtom *> &definedAtoms);
-
- std::error_code findAtomAt(const coff_section *section,
- uint32_t targetAddress,
- COFFDefinedFileAtom *&result,
- uint32_t &offsetInAtom);
-
- std::error_code getAtomBySymbolIndex(uint32_t index, Atom *&ret);
-
- std::error_code
- addRelocationReference(const coff_relocation *rel,
- const coff_section *section);
-
- std::error_code getSectionContents(StringRef sectionName,
- ArrayRef<uint8_t> &result);
- std::error_code getReferenceArch(Reference::KindArch &result);
- std::error_code addRelocationReferenceToAtoms();
- std::error_code findSection(StringRef name, const coff_section *&result);
- StringRef ArrayRefToString(ArrayRef<uint8_t> array);
- uint64_t getNextOrdinal();
-
- std::unique_ptr<const llvm::object::COFFObjectFile> _obj;
- std::unique_ptr<MemoryBuffer> _mb;
- atom_collection_vector<DefinedAtom> _definedAtoms;
- atom_collection_vector<UndefinedAtom> _undefinedAtoms;
- atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
- atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
-
- // The target type of the object.
- Reference::KindArch _referenceArch;
-
- // True if the object has "@feat.00" symbol.
- bool _compatibleWithSEH;
-
- // A map from symbol to its name. All symbols should be in this map except
- // unnamed ones.
- std::map<llvm::object::COFFSymbolRef, StringRef> _symbolName;
-
- // A map from symbol to its resultant atom.
- std::map<llvm::object::COFFSymbolRef, Atom *> _symbolAtom;
-
- // A map from symbol to its aux symbol.
- std::map<llvm::object::COFFSymbolRef, llvm::object::COFFSymbolRef> _auxSymbol;
-
- // A map from section to its atoms.
- std::map<const coff_section *, std::vector<COFFDefinedFileAtom *>>
- _sectionAtoms;
-
- // A set of COMDAT sections.
- std::set<const coff_section *> _comdatSections;
-
- // A map to get whether the section allows its contents to be merged or not.
- std::map<const coff_section *, DefinedAtom::Merge> _merge;
-
- // COMDAT associative sections
- std::multimap<const coff_section *, const coff_section *> _association;
-
- // A sorted map to find an atom from a section and an offset within
- // the section.
- std::map<const coff_section *, std::multimap<uint32_t, COFFDefinedAtom *>>
- _definedAtomLocations;
-
- uint64_t _ordinal;
- llvm::COFF::MachineTypes _machineType;
- PECOFFLinkingContext &_ctx;
- mutable BumpPtrStringSaver _stringSaver;
-};
-
-// Converts the COFF symbol attribute to the LLD's atom attribute.
-Atom::Scope getScope(llvm::object::COFFSymbolRef symbol) {
- switch (symbol.getStorageClass()) {
- case llvm::COFF::IMAGE_SYM_CLASS_EXTERNAL:
- return Atom::scopeGlobal;
- case llvm::COFF::IMAGE_SYM_CLASS_STATIC:
- case llvm::COFF::IMAGE_SYM_CLASS_LABEL:
- return Atom::scopeTranslationUnit;
- }
- llvm_unreachable("Unknown scope");
-}
-
-DefinedAtom::ContentType getContentType(const coff_section *section) {
- if (section->Characteristics & llvm::COFF::IMAGE_SCN_CNT_CODE)
- return DefinedAtom::typeCode;
- if (section->Characteristics & llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA)
- return DefinedAtom::typeData;
- if (section->Characteristics & llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
- return DefinedAtom::typeZeroFill;
- return DefinedAtom::typeUnknown;
-}
-
-DefinedAtom::ContentPermissions getPermissions(const coff_section *section) {
- if (section->Characteristics & llvm::COFF::IMAGE_SCN_MEM_READ &&
- section->Characteristics & llvm::COFF::IMAGE_SCN_MEM_WRITE)
- return DefinedAtom::permRW_;
- if (section->Characteristics & llvm::COFF::IMAGE_SCN_MEM_READ &&
- section->Characteristics & llvm::COFF::IMAGE_SCN_MEM_EXECUTE)
- return DefinedAtom::permR_X;
- if (section->Characteristics & llvm::COFF::IMAGE_SCN_MEM_READ)
- return DefinedAtom::permR__;
- return DefinedAtom::perm___;
-}
-
-/// Returns the alignment of the section. The contents of the section must be
-/// aligned by this value in the resulting executable/DLL.
-DefinedAtom::Alignment getAlignment(const coff_section *section) {
- if (section->Characteristics & llvm::COFF::IMAGE_SCN_TYPE_NO_PAD)
- return DefinedAtom::Alignment(0);
-
- // Bit [20:24] contains section alignment information. We need to decrease
- // the value stored by 1 in order to get the real exponent (e.g, ALIGN_1BYTE
- // is 0x00100000, but the exponent should be 0)
- uint32_t characteristics = (section->Characteristics >> 20) & 0xf;
-
- // If all bits are off, we treat it as if ALIGN_1BYTE was on. The PE/COFF spec
- // does not say anything about this case, but CVTRES.EXE does not set any bit
- // in characteristics[20:24], and its output is intended to be copied to .rsrc
- // section with no padding, so I think doing this is the right thing.
- if (characteristics == 0)
- return DefinedAtom::Alignment(0);
-
- uint32_t powerOf2 = characteristics - 1;
- return DefinedAtom::Alignment(powerOf2);
-}
-
-DefinedAtom::Merge getMerge(const coff_aux_section_definition *auxsym) {
- switch (auxsym->Selection) {
- case llvm::COFF::IMAGE_COMDAT_SELECT_NODUPLICATES:
- return DefinedAtom::mergeNo;
- case llvm::COFF::IMAGE_COMDAT_SELECT_ANY:
- return DefinedAtom::mergeAsWeakAndAddressUsed;
- case llvm::COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH:
- // TODO: This mapping is wrong. Fix it.
- return DefinedAtom::mergeByContent;
- case llvm::COFF::IMAGE_COMDAT_SELECT_SAME_SIZE:
- return DefinedAtom::mergeSameNameAndSize;
- case llvm::COFF::IMAGE_COMDAT_SELECT_LARGEST:
- return DefinedAtom::mergeByLargestSection;
- case llvm::COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE:
- case llvm::COFF::IMAGE_COMDAT_SELECT_NEWEST:
- // FIXME: These attributes has more complicated semantics than the regular
- // weak symbol. These are mapped to mergeAsWeakAndAddressUsed for now
- // because the core linker does not support them yet. We eventually have
- // to implement them for full COFF support.
- return DefinedAtom::mergeAsWeakAndAddressUsed;
- default:
- llvm_unreachable("Unknown merge type");
- }
-}
-
-StringRef getMachineName(llvm::COFF::MachineTypes Type) {
- switch (Type) {
- default: llvm_unreachable("unsupported machine type");
- case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
- return "ARM";
- case llvm::COFF::IMAGE_FILE_MACHINE_I386:
- return "X86";
- case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
- return "X64";
- }
-}
-
-std::error_code FileCOFF::doParse() {
- auto binaryOrErr = llvm::object::createBinary(_mb->getMemBufferRef());
- if (std::error_code ec = binaryOrErr.getError())
- return ec;
- std::unique_ptr<llvm::object::Binary> bin = std::move(binaryOrErr.get());
-
- _obj.reset(dyn_cast<const llvm::object::COFFObjectFile>(bin.get()));
- if (!_obj)
- return make_error_code(llvm::object::object_error::invalid_file_type);
- bin.release();
-
- _machineType = static_cast<llvm::COFF::MachineTypes>(_obj->getMachine());
-
- if (getMachineType() != llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN &&
- getMachineType() != _ctx.getMachineType()) {
- llvm::errs() << "module machine type '"
- << getMachineName(getMachineType())
- << "' conflicts with target machine type '"
- << getMachineName(_ctx.getMachineType()) << "'\n";
- return NativeReaderError::conflicting_target_machine;
- }
-
- if (std::error_code ec = getReferenceArch(_referenceArch))
- return ec;
-
- // Read the symbol table and atomize them if possible. Defined atoms
- // cannot be atomized in one pass, so they will be not be atomized but
- // added to symbolToAtom.
- SymbolVectorT symbols;
- if (std::error_code ec = readSymbolTable(symbols))
- return ec;
-
- createAbsoluteAtoms(symbols, _absoluteAtoms._atoms);
- if (std::error_code ec =
- createUndefinedAtoms(symbols, _undefinedAtoms._atoms))
- return ec;
- if (std::error_code ec = createDefinedSymbols(symbols, _definedAtoms._atoms))
- return ec;
- if (std::error_code ec = addRelocationReferenceToAtoms())
- return ec;
- if (std::error_code ec = maybeCreateSXDataAtoms())
- return ec;
-
- // Check for /SAFESEH.
- if (_ctx.requireSEH() && !isCompatibleWithSEH()) {
- llvm::errs() << "/SAFESEH is specified, but "
- << _mb->getBufferIdentifier()
- << " is not compatible with SEH.\n";
- return llvm::object::object_error::parse_failed;
- }
- return std::error_code();
-}
-
-void FileCOFF::beforeLink() {
- // Acquire the mutex to mutate _ctx.
- std::lock_guard<std::recursive_mutex> lock(_ctx.getMutex());
- std::set<StringRef> undefSyms;
-
- // Interpret .drectve section if the section has contents.
- ArrayRef<uint8_t> directives;
- if (getSectionContents(".drectve", directives))
- return;
- if (!directives.empty()) {
- std::set<StringRef> orig;
- for (StringRef sym : _ctx.initialUndefinedSymbols())
- orig.insert(sym);
- if (parseDirectiveSection(ArrayRefToString(directives)))
- return;
- for (StringRef sym : _ctx.initialUndefinedSymbols())
- if (orig.count(sym) == 0)
- undefSyms.insert(sym);
- }
-
- // Add /INCLUDE'ed symbols to the file as if they existed in the
- // file as undefined symbols.
- for (StringRef sym : undefSyms) {
- addUndefinedSymbol(sym);
- _ctx.addDeadStripRoot(sym);
- }
-
- // One can define alias symbols using /alternatename:<sym>=<sym> option.
- // The mapping for /alternatename is in the context object. This helper
- // function iterate over defined atoms and create alias atoms if needed.
- createAlternateNameAtoms();
-
- // In order to emit SEH table, all input files need to be compatible with
- // SEH. Disable SEH if the file being read is not compatible.
- if (!isCompatibleWithSEH())
- _ctx.setSafeSEH(false);
-}
-
-/// Iterate over the symbol table to retrieve all symbols.
-std::error_code
-FileCOFF::readSymbolTable(SymbolVectorT &result) {
- for (uint32_t i = 0, e = _obj->getNumberOfSymbols(); i != e; ++i) {
- // Retrieve the symbol.
- ErrorOr<llvm::object::COFFSymbolRef> sym = _obj->getSymbol(i);
- StringRef name;
- if (std::error_code ec = sym.getError())
- return ec;
- if (sym->getSectionNumber() == llvm::COFF::IMAGE_SYM_DEBUG)
- goto next;
- result.push_back(*sym);
-
- if (std::error_code ec = _obj->getSymbolName(*sym, name))
- return ec;
-
- // Existence of the symbol @feat.00 indicates that object file is compatible
- // with Safe Exception Handling.
- if (name == "@feat.00") {
- _compatibleWithSEH = true;
- goto next;
- }
-
- // Cache the name.
- _symbolName[*sym] = name;
-
- // Symbol may be followed by auxiliary symbol table records. The aux
- // record can be in any format, but the size is always the same as the
- // regular symbol. The aux record supplies additional information for the
- // standard symbol. We do not interpret the aux record here, but just
- // store it to _auxSymbol.
- if (sym->getNumberOfAuxSymbols() > 0) {
- ErrorOr<llvm::object::COFFSymbolRef> aux = _obj->getSymbol(i + 1);
- if (std::error_code ec = aux.getError())
- return ec;
- _auxSymbol[*sym] = *aux;
- }
- next:
- i += sym->getNumberOfAuxSymbols();
- }
- return std::error_code();
-}
-
-/// Create atoms for the absolute symbols.
-void FileCOFF::createAbsoluteAtoms(const SymbolVectorT &symbols,
- std::vector<const AbsoluteAtom *> &result) {
- for (llvm::object::COFFSymbolRef sym : symbols) {
- if (sym.getSectionNumber() != llvm::COFF::IMAGE_SYM_ABSOLUTE)
- continue;
- auto *atom = new (_alloc) SimpleAbsoluteAtom(*this, _symbolName[sym],
- getScope(sym), sym.getValue());
- result.push_back(atom);
- _symbolAtom[sym] = atom;
- }
-}
-
-/// Create atoms for the undefined symbols. This code is bit complicated
-/// because it supports "weak externals" mechanism of COFF. If an undefined
-/// symbol (sym1) has auxiliary data, the data contains a symbol table index
-/// at which the "second symbol" (sym2) for sym1 exists. If sym1 is resolved,
-/// it's linked normally. If not, sym1 is resolved as if it has sym2's
-/// name. This relationship between sym1 and sym2 is represented using
-/// fallback mechanism of undefined symbol.
-std::error_code
-FileCOFF::createUndefinedAtoms(const SymbolVectorT &symbols,
- std::vector<const UndefinedAtom *> &result) {
- std::map<llvm::object::COFFSymbolRef, llvm::object::COFFSymbolRef>
- weakExternal;
- std::set<llvm::object::COFFSymbolRef> fallback;
- for (llvm::object::COFFSymbolRef sym : symbols) {
- if (sym.getSectionNumber() != llvm::COFF::IMAGE_SYM_UNDEFINED)
- continue;
- // Create a mapping from sym1 to sym2, if the undefined symbol has
- // auxiliary data.
- auto iter = _auxSymbol.find(sym);
- if (iter == _auxSymbol.end())
- continue;
- const coff_aux_weak_external *aux =
- reinterpret_cast<const coff_aux_weak_external *>(
- iter->second.getRawPtr());
- ErrorOr<llvm::object::COFFSymbolRef> sym2 = _obj->getSymbol(aux->TagIndex);
- if (std::error_code ec = sym2.getError())
- return ec;
- weakExternal[sym] = *sym2;
- fallback.insert(*sym2);
- }
-
- // Create atoms for the undefined symbols.
- for (llvm::object::COFFSymbolRef sym : symbols) {
- if (sym.getSectionNumber() != llvm::COFF::IMAGE_SYM_UNDEFINED)
- continue;
- if (fallback.count(sym) > 0)
- continue;
-
- // If the symbol has sym2, create an undefiend atom for sym2, so that we
- // can pass it as a fallback atom.
- UndefinedAtom *fallback = nullptr;
- auto iter = weakExternal.find(sym);
- if (iter != weakExternal.end()) {
- llvm::object::COFFSymbolRef sym2 = iter->second;
- fallback = new (_alloc) COFFUndefinedAtom(*this, _symbolName[sym2]);
- _symbolAtom[sym2] = fallback;
- }
-
- // Create an atom for the symbol.
- auto *atom =
- new (_alloc) COFFUndefinedAtom(*this, _symbolName[sym], fallback);
- result.push_back(atom);
- _symbolAtom[sym] = atom;
- }
- return std::error_code();
-}
-
-/// Create atoms for the defined symbols. This pass is a bit complicated than
-/// the other two, because in order to create the atom for the defined symbol
-/// we need to know the adjacent symbols.
-std::error_code
-FileCOFF::createDefinedSymbols(const SymbolVectorT &symbols,
- std::vector<const DefinedAtom *> &result) {
- // A defined atom can be merged if its section attribute allows its contents
- // to be merged. In COFF, it's not very easy to get the section attribute
- // for the symbol, so scan all sections in advance and cache the attributes
- // for later use.
- if (std::error_code ec = cacheSectionAttributes())
- return ec;
-
- // Filter non-defined atoms, and group defined atoms by its section.
- SectionToSymbolsT definedSymbols;
- for (llvm::object::COFFSymbolRef sym : symbols) {
- // A symbol with section number 0 and non-zero value represents a common
- // symbol. The MS COFF spec did not give a definition of what the common
- // symbol is. We should probably follow ELF's definition shown below.
- //
- // - If one object file has a common symbol and another has a definition,
- // the common symbol is treated as an undefined reference.
- // - If there is no definition for a common symbol, the program linker
- // acts as though it saw a definition initialized to zero of the
- // appropriate size.
- // - Two object files may have common symbols of
- // different sizes, in which case the program linker will use the
- // largest size.
- //
- // FIXME: We are currently treating the common symbol as a normal
- // mergeable atom. Implement the above semantcis.
- if (sym.getSectionNumber() == llvm::COFF::IMAGE_SYM_UNDEFINED &&
- sym.getValue() > 0) {
- StringRef name = _symbolName[sym];
- uint32_t size = sym.getValue();
- auto *atom = new (_alloc)
- COFFBSSAtom(*this, name, getScope(sym), DefinedAtom::permRW_,
- DefinedAtom::mergeAsWeakAndAddressUsed, size, getNextOrdinal());
-
- // Common symbols should be aligned on natural boundaries with the maximum
- // of 32 byte. It's not documented anywhere, but it's what MSVC link.exe
- // seems to be doing.
- uint64_t alignment = std::min((uint64_t)32, llvm::NextPowerOf2(size));
- atom->setAlignment(
- DefinedAtom::Alignment(llvm::countTrailingZeros(alignment)));
- result.push_back(atom);
- continue;
- }
-
- // Skip if it's not for defined atom.
- if (sym.getSectionNumber() == llvm::COFF::IMAGE_SYM_DEBUG ||
- sym.getSectionNumber() == llvm::COFF::IMAGE_SYM_ABSOLUTE ||
- sym.getSectionNumber() == llvm::COFF::IMAGE_SYM_UNDEFINED)
- continue;
-
- const coff_section *sec;
- if (std::error_code ec = _obj->getSection(sym.getSectionNumber(), sec))
- return ec;
- assert(sec && "SectionIndex > 0, Sec must be non-null!");
-
- uint8_t sc = sym.getStorageClass();
- if (sc != llvm::COFF::IMAGE_SYM_CLASS_EXTERNAL &&
- sc != llvm::COFF::IMAGE_SYM_CLASS_STATIC &&
- sc != llvm::COFF::IMAGE_SYM_CLASS_FUNCTION &&
- sc != llvm::COFF::IMAGE_SYM_CLASS_LABEL) {
- llvm::errs() << "Unable to create atom for: " << _symbolName[sym] << " ("
- << static_cast<int>(sc) << ")\n";
- return llvm::object::object_error::parse_failed;
- }
-
- definedSymbols[sec].push_back(sym);
- }
-
- // Atomize the defined symbols.
- if (std::error_code ec = AtomizeDefinedSymbols(definedSymbols, result))
- return ec;
-
- return std::error_code();
-}
-
-// Cache the COMDAT attributes, which indicate whether the symbols in the
-// section can be merged or not.
-std::error_code FileCOFF::cacheSectionAttributes() {
- // The COMDAT section attribute is not an attribute of coff_section, but is
- // stored in the auxiliary symbol for the first symbol referring a COMDAT
- // section. It feels to me that it's unnecessarily complicated, but this is
- // how COFF works.
- for (auto i : _auxSymbol) {
- // Read a section from the file
- llvm::object::COFFSymbolRef sym = i.first;
- if (sym.getSectionNumber() == llvm::COFF::IMAGE_SYM_ABSOLUTE ||
- sym.getSectionNumber() == llvm::COFF::IMAGE_SYM_UNDEFINED)
- continue;
-
- const coff_section *sec;
- if (std::error_code ec = _obj->getSection(sym.getSectionNumber(), sec))
- return ec;
- const coff_aux_section_definition *aux =
- reinterpret_cast<const coff_aux_section_definition *>(
- i.second.getRawPtr());
-
- if (sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_COMDAT) {
- // Read aux symbol data.
- _comdatSections.insert(sec);
- _merge[sec] = getMerge(aux);
- }
-
- // Handle associative sections.
- if (aux->Selection == llvm::COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
- const coff_section *parent;
- if (std::error_code ec =
- _obj->getSection(aux->getNumber(sym.isBigObj()), parent))
- return ec;
- _association.insert(std::make_pair(parent, sec));
- }
- }
-
- // The sections that does not have auxiliary symbol are regular sections, in
- // which symbols are not allowed to be merged.
- for (const auto &section : _obj->sections()) {
- const coff_section *sec = _obj->getCOFFSection(section);
- if (!_merge.count(sec))
- _merge[sec] = DefinedAtom::mergeNo;
- }
- return std::error_code();
-}
-
-/// Atomize \p symbols and append the results to \p atoms. The symbols are
-/// assumed to have been defined in the \p section.
-std::error_code FileCOFF::AtomizeDefinedSymbolsInSection(
- const coff_section *section, SymbolVectorT &symbols,
- std::vector<COFFDefinedFileAtom *> &atoms) {
- // Sort symbols by position.
- std::stable_sort(
- symbols.begin(), symbols.end(),
- [](llvm::object::COFFSymbolRef a, llvm::object::COFFSymbolRef b)
- -> bool { return a.getValue() < b.getValue(); });
-
- StringRef sectionName;
- if (std::error_code ec = _obj->getSectionName(section, sectionName))
- return ec;
-
- // BSS section does not have contents. If this is the BSS section, create
- // COFFBSSAtom instead of COFFDefinedAtom.
- if (section->Characteristics & llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) {
- for (auto si = symbols.begin(), se = symbols.end(); si != se; ++si) {
- llvm::object::COFFSymbolRef sym = *si;
- uint32_t size = (si + 1 == se) ? section->SizeOfRawData - sym.getValue()
- : si[1].getValue() - sym.getValue();
- auto *atom = new (_alloc) COFFBSSAtom(
- *this, _symbolName[sym], getScope(sym), getPermissions(section),
- DefinedAtom::mergeAsWeakAndAddressUsed, size, getNextOrdinal());
- atoms.push_back(atom);
- _symbolAtom[sym] = atom;
- }
- return std::error_code();
- }
-
- ArrayRef<uint8_t> secData;
- if (std::error_code ec = _obj->getSectionContents(section, secData))
- return ec;
-
- // A section with IMAGE_SCN_LNK_{INFO,REMOVE} attribute will never become
- // a part of the output image. That's what the COFF spec says.
- if (section->Characteristics & llvm::COFF::IMAGE_SCN_LNK_INFO ||
- section->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE)
- return std::error_code();
-
- // Supporting debug info needs more work than just linking and combining
- // .debug sections. We don't support it yet. Let's discard .debug sections at
- // the very beginning of the process so that we don't spend time on linking
- // blobs that nobody would understand.
- if ((section->Characteristics & llvm::COFF::IMAGE_SCN_MEM_DISCARDABLE) &&
- (sectionName == ".debug" || sectionName.startswith(".debug$"))) {
- return std::error_code();
- }
-
- DefinedAtom::ContentType type = getContentType(section);
- DefinedAtom::ContentPermissions perms = getPermissions(section);
- uint64_t sectionSize = section->SizeOfRawData;
- bool isComdat = (_comdatSections.count(section) == 1);
-
- // Create an atom for the entire section.
- if (symbols.empty()) {
- ArrayRef<uint8_t> data(secData.data(), secData.size());
- auto *atom = new (_alloc) COFFDefinedAtom(
- *this, "", sectionName, sectionSize, Atom::scopeTranslationUnit,
- type, isComdat, perms, _merge[section], data, getNextOrdinal());
- atoms.push_back(atom);
- _definedAtomLocations[section].insert(std::make_pair(0, atom));
- return std::error_code();
- }
-
- // Create an unnamed atom if the first atom isn't at the start of the
- // section.
- if (symbols[0].getValue() != 0) {
- uint64_t size = symbols[0].getValue();
- ArrayRef<uint8_t> data(secData.data(), size);
- auto *atom = new (_alloc) COFFDefinedAtom(
- *this, "", sectionName, sectionSize, Atom::scopeTranslationUnit,
- type, isComdat, perms, _merge[section], data, getNextOrdinal());
- atoms.push_back(atom);
- _definedAtomLocations[section].insert(std::make_pair(0, atom));
- }
-
- for (auto si = symbols.begin(), se = symbols.end(); si != se; ++si) {
- const uint8_t *start = secData.data() + si->getValue();
- // if this is the last symbol, take up the remaining data.
- const uint8_t *end = (si + 1 == se) ? secData.data() + secData.size()
- : secData.data() + (si + 1)->getValue();
- ArrayRef<uint8_t> data(start, end);
- auto *atom = new (_alloc) COFFDefinedAtom(
- *this, _symbolName[*si], sectionName, sectionSize, getScope(*si),
- type, isComdat, perms, _merge[section], data, getNextOrdinal());
- atoms.push_back(atom);
- _symbolAtom[*si] = atom;
- _definedAtomLocations[section].insert(std::make_pair(si->getValue(), atom));
- }
- return std::error_code();
-}
-
-std::error_code FileCOFF::AtomizeDefinedSymbols(
- SectionToSymbolsT &definedSymbols,
- std::vector<const DefinedAtom *> &definedAtoms) {
- // For each section, make atoms for all the symbols defined in the
- // section, and append the atoms to the result objects.
- for (auto &i : definedSymbols) {
- const coff_section *section = i.first;
- SymbolVectorT &symbols = i.second;
- std::vector<COFFDefinedFileAtom *> atoms;
- if (std::error_code ec =
- AtomizeDefinedSymbolsInSection(section, symbols, atoms))
- return ec;
-
- // Set alignment to the first atom so that the section contents
- // will be aligned as specified by the object section header.
- if (atoms.size() > 0)
- atoms[0]->setAlignment(getAlignment(section));
-
- // Connect atoms with layout-after edges. It prevents atoms
- // from being GC'ed if there is a reference to one of the atoms
- // in the same layout-after chain. In such case we want to emit
- // all the atoms appeared in the same chain, because the "live"
- // atom may reference other atoms in the same chain.
- if (atoms.size() >= 2)
- for (auto it = atoms.begin(), e = atoms.end(); it + 1 != e; ++it)
- addLayoutEdge(*it, *(it + 1), lld::Reference::kindLayoutAfter);
-
- for (COFFDefinedFileAtom *atom : atoms) {
- _sectionAtoms[section].push_back(atom);
- definedAtoms.push_back(atom);
- }
- }
-
- // A COMDAT section with SELECT_ASSOCIATIVE attribute refer to other
- // section. If the referred section is linked to a binary, the
- // referring section needs to be linked too. A typical use case of
- // this attribute is a static initializer; a parent is a comdat BSS
- // section, and a child is a static initializer code for the data.
- //
- // We add referring section contents to the referred section's
- // associate list, so that Resolver takes care of them.
- for (auto i : _association) {
- const coff_section *parent = i.first;
- const coff_section *child = i.second;
- if (_sectionAtoms.count(child)) {
- COFFDefinedFileAtom *p = _sectionAtoms[parent][0];
- p->addAssociate(_sectionAtoms[child][0]);
- }
- }
-
- return std::error_code();
-}
-
-/// Find the atom that is at \p targetAddress in \p section.
-std::error_code FileCOFF::findAtomAt(const coff_section *section,
- uint32_t targetAddress,
- COFFDefinedFileAtom *&result,
- uint32_t &offsetInAtom) {
- auto loc = _definedAtomLocations.find(section);
- if (loc == _definedAtomLocations.end())
- return llvm::object::object_error::parse_failed;
- std::multimap<uint32_t, COFFDefinedAtom *> &map = loc->second;
-
- auto it = map.upper_bound(targetAddress);
- if (it == map.begin())
- return llvm::object::object_error::parse_failed;
- --it;
- uint32_t atomAddress = it->first;
- result = it->second;
- offsetInAtom = targetAddress - atomAddress;
- return std::error_code();
-}
-
-/// Find the atom for the symbol that was at the \p index in the symbol
-/// table.
-std::error_code FileCOFF::getAtomBySymbolIndex(uint32_t index, Atom *&ret) {
- ErrorOr<llvm::object::COFFSymbolRef> symbol = _obj->getSymbol(index);
- if (std::error_code ec = symbol.getError())
- return ec;
- ret = _symbolAtom[*symbol];
- assert(ret);
- return std::error_code();
-}
-
-/// Add relocation information to an atom based on \p rel. \p rel is an
-/// relocation entry for the \p section, and \p atoms are all the atoms
-/// defined in the \p section.
-std::error_code FileCOFF::addRelocationReference(
- const coff_relocation *rel, const coff_section *section) {
- // The address of the item which relocation is applied. Section's
- // VirtualAddress needs to be added for historical reasons, but the value
- // is usually just zero, so adding it is usually no-op.
- uint32_t itemAddress = rel->VirtualAddress + section->VirtualAddress;
-
- Atom *targetAtom = nullptr;
- if (std::error_code ec =
- getAtomBySymbolIndex(rel->SymbolTableIndex, targetAtom))
- return ec;
-
- COFFDefinedFileAtom *atom;
- uint32_t offsetInAtom;
- if (std::error_code ec = findAtomAt(section, itemAddress, atom, offsetInAtom))
- return ec;
- atom->addReference(llvm::make_unique<SimpleReference>(
- Reference::KindNamespace::COFF, _referenceArch, rel->Type, offsetInAtom,
- targetAtom, 0));
- return std::error_code();
-}
-
-// Read section contents.
-std::error_code FileCOFF::getSectionContents(StringRef sectionName,
- ArrayRef<uint8_t> &result) {
- const coff_section *section = nullptr;
- if (std::error_code ec = findSection(sectionName, section))
- return ec;
- if (!section)
- return std::error_code();
- if (std::error_code ec = _obj->getSectionContents(section, result))
- return ec;
- return std::error_code();
-}
-
-AliasAtom *
-FileCOFF::createAlias(StringRef name, const DefinedAtom *target, int cnt) {
- AliasAtom *alias = new (_alloc) AliasAtom(*this, name);
- alias->addReference(Reference::KindNamespace::all, Reference::KindArch::all,
- Reference::kindLayoutAfter, 0, target, 0);
- alias->setMerge(DefinedAtom::mergeAsWeak);
- if (target->contentType() == DefinedAtom::typeCode)
- alias->setDeadStrip(DefinedAtom::deadStripNever);
- alias->setOrdinal(target->ordinal() - cnt);
- return alias;
-}
-
-void FileCOFF::createAlternateNameAtoms() {
- std::vector<AliasAtom *> aliases;
- for (const DefinedAtom *atom : defined()) {
- int cnt = 1;
- for (StringRef alias : _ctx.getAlternateNames(atom->name()))
- aliases.push_back(createAlias(alias, atom, cnt++));
- }
- for (AliasAtom *alias : aliases)
- _definedAtoms._atoms.push_back(alias);
-}
-
-// Interpret the contents of .drectve section. If exists, the section contains
-// a string containing command line options. The linker is expected to
-// interpret the options as if they were given via the command line.
-//
-// The section mainly contains /defaultlib (-l in Unix), but can contain any
-// options as long as they are valid.
-std::error_code
-FileCOFF::parseDirectiveSection(StringRef directives) {
- DEBUG(llvm::dbgs() << ".drectve: " << directives << "\n");
-
- // Split the string into tokens, as the shell would do for argv.
- SmallVector<const char *, 16> tokens;
- tokens.push_back("link"); // argv[0] is the command name. Will be ignored.
- llvm::cl::TokenizeWindowsCommandLine(directives, _stringSaver, tokens);
- tokens.push_back(nullptr);
-
- // Calls the command line parser to interpret the token string as if they
- // were given via the command line.
- int argc = tokens.size() - 1;
- const char **argv = &tokens[0];
- std::string errorMessage;
- llvm::raw_string_ostream stream(errorMessage);
- PECOFFLinkingContext::ParseDirectives parseDirectives =
- _ctx.getParseDirectives();
- bool parseFailed = !parseDirectives(argc, argv, _ctx, stream);
- stream.flush();
- // Print error message if error.
- if (parseFailed) {
- return make_dynamic_error_code(
- Twine("Failed to parse '") + directives + "'\n"
- + "Reason: " + errorMessage);
- }
- if (!errorMessage.empty()) {
- llvm::errs() << "lld warning: " << errorMessage << "\n";
- }
- return std::error_code();
-}
-
-/// Returns the target machine type of the current object file.
-std::error_code FileCOFF::getReferenceArch(Reference::KindArch &result) {
- switch (_obj->getMachine()) {
- case llvm::COFF::IMAGE_FILE_MACHINE_I386:
- result = Reference::KindArch::x86;
- return std::error_code();
- case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
- result = Reference::KindArch::x86_64;
- return std::error_code();
- case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
- result = Reference::KindArch::ARM;
- return std::error_code();
- case llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN:
- result = Reference::KindArch::all;
- return std::error_code();
- }
- llvm::errs() << "Unsupported machine type: 0x"
- << llvm::utohexstr(_obj->getMachine()) << '\n';
- return llvm::object::object_error::parse_failed;
-}
-
-/// Add relocation information to atoms.
-std::error_code FileCOFF::addRelocationReferenceToAtoms() {
- // Relocation entries are defined for each section.
- for (const auto &sec : _obj->sections()) {
- const coff_section *section = _obj->getCOFFSection(sec);
-
- // Skip if there's no atom for the section. Currently we do not create any
- // atoms for some sections, such as "debug$S", and such sections need to
- // be skipped here too.
- if (_sectionAtoms.find(section) == _sectionAtoms.end())
- continue;
-
- for (const auto &reloc : sec.relocations()) {
- const coff_relocation *rel = _obj->getCOFFRelocation(reloc);
- if (auto ec = addRelocationReference(rel, section))
- return ec;
- }
- }
- return std::error_code();
-}
-
-// Read .sxdata section if exists. .sxdata is a x86-only section that contains a
-// vector of symbol offsets. The symbols pointed by this section are SEH handler
-// functions contained in the same object file. The linker needs to construct a
-// SEH table and emit it to executable.
-//
-// On x86, exception handler addresses are in stack, so they are vulnerable to
-// stack overflow attack. In order to protect against it, Windows runtime uses
-// the SEH table to check if a SEH handler address in stack is a real address of
-// a handler created by compiler.
-//
-// What we want to emit from the linker is a vector of SEH handler VAs, but here
-// we have a vector of offsets to the symbol table. So we convert the latter to
-// the former.
-std::error_code FileCOFF::maybeCreateSXDataAtoms() {
- ArrayRef<uint8_t> sxdata;
- if (std::error_code ec = getSectionContents(".sxdata", sxdata))
- return ec;
- if (sxdata.empty())
- return std::error_code();
-
- auto *atom = new (_alloc) COFFDefinedAtom(
- *this, "", ".sxdata", 0, Atom::scopeTranslationUnit,
- DefinedAtom::typeData, false /*isComdat*/, DefinedAtom::permR__,
- DefinedAtom::mergeNo, sxdata, getNextOrdinal());
-
- const ulittle32_t *symbolIndex =
- reinterpret_cast<const ulittle32_t *>(sxdata.data());
- int numSymbols = sxdata.size() / sizeof(uint32_t);
-
- for (int i = 0; i < numSymbols; ++i) {
- Atom *handlerFunc;
- if (std::error_code ec = getAtomBySymbolIndex(symbolIndex[i], handlerFunc))
- return ec;
- int offsetInAtom = i * sizeof(uint32_t);
-
- uint16_t rtype;
- switch (_obj->getMachine()) {
- case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
- rtype = llvm::COFF::IMAGE_REL_AMD64_ADDR32;
- break;
- case llvm::COFF::IMAGE_FILE_MACHINE_I386:
- rtype = llvm::COFF::IMAGE_REL_I386_DIR32;
- break;
- default:
- llvm_unreachable("unsupported machine type");
- }
-
- atom->addReference(llvm::make_unique<SimpleReference>(
- Reference::KindNamespace::COFF, _referenceArch, rtype, offsetInAtom,
- handlerFunc, 0));
- }
-
- _definedAtoms._atoms.push_back(atom);
- return std::error_code();
-}
-
-/// Find a section by name.
-std::error_code FileCOFF::findSection(StringRef name,
- const coff_section *&result) {
- for (const auto &sec : _obj->sections()) {
- const coff_section *section = _obj->getCOFFSection(sec);
- StringRef sectionName;
- if (auto ec = _obj->getSectionName(section, sectionName))
- return ec;
- if (sectionName == name) {
- result = section;
- return std::error_code();
- }
- }
- // Section was not found, but it's not an error. This method returns
- // an error only when there's a read error.
- return std::error_code();
-}
-
-// Convert ArrayRef<uint8_t> to std::string. The array contains a string which
-// may not be terminated by NUL.
-StringRef FileCOFF::ArrayRefToString(ArrayRef<uint8_t> array) {
- // .drectve sections are encoded in either ASCII or UTF-8 with BOM.
- // The PE/COFF spec allows ANSI (Windows-1252 encoding), but seems
- // it's no longer in use.
- // Skip a UTF-8 byte marker if exists.
- if (array.size() >= 3 && array[0] == 0xEF && array[1] == 0xBB &&
- array[2] == 0xBF) {
- array = array.slice(3);
- }
- if (array.empty())
- return "";
- StringRef s(reinterpret_cast<const char *>(array.data()), array.size());
- s = s.substr(0, s.find_first_of('\0'));
- std::string *contents = new (_alloc) std::string(s.data(), s.size());
- return StringRef(*contents).trim();
-}
-
-// getNextOrdinal returns a monotonically increasaing uint64_t number
-// starting from 1. There's a large gap between two numbers returned
-// from this function, so that you can put other atoms between them.
-uint64_t FileCOFF::getNextOrdinal() {
- return _ordinal++ << 32;
-}
-
-class COFFObjectReader : public Reader {
-public:
- COFFObjectReader(PECOFFLinkingContext &ctx) : _ctx(ctx) {}
-
- bool canParse(file_magic magic, StringRef ext,
- const MemoryBuffer &) const override {
- return magic == llvm::sys::fs::file_magic::coff_object;
- }
-
- std::error_code
- loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry &,
- std::vector<std::unique_ptr<File>> &result) const override {
- // Parse the memory buffer as PECOFF file.
- auto *file = new FileCOFF(std::move(mb), _ctx);
- result.push_back(std::unique_ptr<File>(file));
- return std::error_code();
- }
-
-private:
- PECOFFLinkingContext &_ctx;
-};
-
-using namespace llvm::COFF;
-
-const Registry::KindStrings kindStringsI386[] = {
- LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_ABSOLUTE),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_DIR16),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_REL16),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_DIR32),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_DIR32NB),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_SEG12),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_SECTION),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_SECREL),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_TOKEN),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_SECREL7),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_REL32),
- LLD_KIND_STRING_END};
-
-const Registry::KindStrings kindStringsAMD64[] = {
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_ABSOLUTE),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_ADDR64),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_ADDR32),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_ADDR32NB),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32_1),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32_2),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32_3),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32_4),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32_5),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_SECTION),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_SECREL),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_SECREL7),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_TOKEN),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_SREL32),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_PAIR),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_SSPAN32),
- LLD_KIND_STRING_END};
-
-const Registry::KindStrings kindStringsARMNT[] = {
- LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_ABSOLUTE),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_ADDR32),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_ADDR32NB),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_BRANCH24),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_BRANCH11),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_TOKEN),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_BLX24),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_BLX11),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_SECTION),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_SECREL),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_MOV32A),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_MOV32T),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_BRANCH20T),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_BRANCH24T),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_BLX23T),
-};
-
-} // end namespace anonymous
-
-namespace lld {
-
-void Registry::addSupportCOFFObjects(PECOFFLinkingContext &ctx) {
- add(std::unique_ptr<Reader>(new COFFObjectReader(ctx)));
- addKindTable(Reference::KindNamespace::COFF, Reference::KindArch::x86,
- kindStringsI386);
- addKindTable(Reference::KindNamespace::COFF, Reference::KindArch::x86_64,
- kindStringsAMD64);
- addKindTable(Reference::KindNamespace::COFF, Reference::KindArch::ARM,
- kindStringsARMNT);
-}
-
-}