diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2015-03-24 21:31:36 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2015-03-24 21:31:36 +0000 |
| commit | fb911942f1434f3d1750f83f25f5e42c80e60638 (patch) | |
| tree | 1678c4a4f0182e4029a86d135aa4a1b7d09e3c41 /lib/Core | |
Notes
Diffstat (limited to 'lib/Core')
| -rw-r--r-- | lib/Core/CMakeLists.txt | 12 | ||||
| -rw-r--r-- | lib/Core/DefinedAtom.cpp | 96 | ||||
| -rw-r--r-- | lib/Core/Error.cpp | 151 | ||||
| -rw-r--r-- | lib/Core/File.cpp | 30 | ||||
| -rw-r--r-- | lib/Core/LinkingContext.cpp | 104 | ||||
| -rw-r--r-- | lib/Core/Makefile | 13 | ||||
| -rw-r--r-- | lib/Core/Reader.cpp | 117 | ||||
| -rw-r--r-- | lib/Core/Resolver.cpp | 516 | ||||
| -rw-r--r-- | lib/Core/SymbolTable.cpp | 390 | ||||
| -rw-r--r-- | lib/Core/TODO.txt | 18 | ||||
| -rw-r--r-- | lib/Core/Writer.cpp | 23 |
11 files changed, 1470 insertions, 0 deletions
diff --git a/lib/Core/CMakeLists.txt b/lib/Core/CMakeLists.txt new file mode 100644 index 000000000000..009b50a38335 --- /dev/null +++ b/lib/Core/CMakeLists.txt @@ -0,0 +1,12 @@ +add_llvm_library(lldCore + DefinedAtom.cpp + Error.cpp + File.cpp + LinkingContext.cpp + Reader.cpp + Resolver.cpp + SymbolTable.cpp + Writer.cpp + LINK_LIBS + LLVMSupport + ) diff --git a/lib/Core/DefinedAtom.cpp b/lib/Core/DefinedAtom.cpp new file mode 100644 index 000000000000..b3f81ca65a91 --- /dev/null +++ b/lib/Core/DefinedAtom.cpp @@ -0,0 +1,96 @@ +//===- DefinedAtom.cpp ------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/ErrorHandling.h" +#include "lld/Core/DefinedAtom.h" +#include "lld/Core/File.h" + +namespace lld { + +DefinedAtom::ContentPermissions DefinedAtom::permissions() const { + // By default base permissions on content type. + return permissions(this->contentType()); +} + +// Utility function for deriving permissions from content type +DefinedAtom::ContentPermissions DefinedAtom::permissions(ContentType type) { + switch (type) { + case typeCode: + case typeResolver: + case typeBranchIsland: + case typeBranchShim: + case typeStub: + case typeStubHelper: + case typeMachHeader: + return permR_X; + + case typeConstant: + case typeCString: + case typeUTF16String: + case typeCFI: + case typeLSDA: + case typeLiteral4: + case typeLiteral8: + case typeLiteral16: + case typeDTraceDOF: + case typeCompactUnwindInfo: + case typeProcessedUnwindInfo: + case typeRONote: + case typeNoAlloc: + return permR__; + + case typeData: + case typeDataFast: + case typeZeroFill: + case typeZeroFillFast: + case typeObjC1Class: + case typeLazyPointer: + case typeLazyDylibPointer: + case typeThunkTLV: + case typeRWNote: + return permRW_; + + case typeGOT: + case typeConstData: + case typeCFString: + case typeInitializerPtr: + case typeTerminatorPtr: + case typeCStringPtr: + case typeObjCClassPtr: + case typeObjC2CategoryList: + case typeInterposingTuples: + case typeTLVInitialData: + case typeTLVInitialZeroFill: + case typeTLVInitializerPtr: + case typeThreadData: + case typeThreadZeroFill: + return permRW_L; + + case typeGroupComdat: + case typeGnuLinkOnce: + case typeUnknown: + case typeTempLTO: + return permUnknown; + } + llvm_unreachable("unknown content type"); +} + +bool DefinedAtom::compareByPosition(const DefinedAtom *lhs, + const DefinedAtom *rhs) { + if (lhs == rhs) + return false; + const File *lhsFile = &lhs->file(); + const File *rhsFile = &rhs->file(); + if (lhsFile->ordinal() != rhsFile->ordinal()) + return lhsFile->ordinal() < rhsFile->ordinal(); + assert(lhs->ordinal() != rhs->ordinal()); + return lhs->ordinal() < rhs->ordinal(); +} + +} // namespace diff --git a/lib/Core/Error.cpp b/lib/Core/Error.cpp new file mode 100644 index 000000000000..24809c3869e5 --- /dev/null +++ b/lib/Core/Error.cpp @@ -0,0 +1,151 @@ +//===- Error.cpp - system_error extensions for lld --------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/Core/Error.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/ErrorHandling.h" +#include <mutex> +#include <string> +#include <vector> + +using namespace lld; + +class _NativeReaderErrorCategory : public std::error_category { +public: + const char* name() const LLVM_NOEXCEPT override { + return "lld.native.reader"; + } + + std::string message(int ev) const override { + switch (static_cast<NativeReaderError>(ev)) { + case NativeReaderError::success: + return "Success"; + case NativeReaderError::unknown_file_format: + return "Unknown file format"; + case NativeReaderError::file_too_short: + return "file truncated"; + case NativeReaderError::file_malformed: + return "file malformed"; + case NativeReaderError::memory_error: + return "out of memory"; + case NativeReaderError::unknown_chunk_type: + return "unknown chunk type"; + case NativeReaderError::conflicting_target_machine: + return "conflicting target machine"; + } + llvm_unreachable("An enumerator of NativeReaderError does not have a " + "message defined."); + } +}; + +const std::error_category &lld::native_reader_category() { + static _NativeReaderErrorCategory o; + return o; +} + +class _YamlReaderErrorCategory : public std::error_category { +public: + const char* name() const LLVM_NOEXCEPT override { + return "lld.yaml.reader"; + } + + std::string message(int ev) const override { + switch (static_cast<YamlReaderError>(ev)) { + case YamlReaderError::success: + return "Success"; + case YamlReaderError::unknown_keyword: + return "Unknown keyword found in yaml file"; + case YamlReaderError::illegal_value: + return "Bad value found in yaml file"; + } + llvm_unreachable("An enumerator of YamlReaderError does not have a " + "message defined."); + } +}; + +const std::error_category &lld::YamlReaderCategory() { + static _YamlReaderErrorCategory o; + return o; +} + +class _LinkerScriptReaderErrorCategory : public std::error_category { +public: + const char *name() const LLVM_NOEXCEPT override { + return "lld.linker-script.reader"; + } + + std::string message(int ev) const override { + switch (static_cast<LinkerScriptReaderError>(ev)) { + case LinkerScriptReaderError::success: + return "Success"; + case LinkerScriptReaderError::parse_error: + return "Error parsing linker script"; + case LinkerScriptReaderError::unknown_symbol_in_expr: + return "Unknown symbol found when evaluating linker script expression"; + case LinkerScriptReaderError::unrecognized_function_in_expr: + return "Unrecognized function call when evaluating linker script " + "expression"; + } + llvm_unreachable("An enumerator of LinkerScriptReaderError does not have a " + "message defined."); + } +}; + +const std::error_category &lld::LinkerScriptReaderCategory() { + static _LinkerScriptReaderErrorCategory o; + return o; +} + + +namespace lld { + +/// Temporary class to enable make_dynamic_error_code() until +/// llvm::ErrorOr<> is updated to work with error encapsulations +/// other than error_code. +class dynamic_error_category : public std::error_category { +public: + ~dynamic_error_category() LLVM_NOEXCEPT {} + + const char *name() const LLVM_NOEXCEPT override { + return "lld.dynamic_error"; + } + + std::string message(int ev) const override { + assert(ev >= 0); + assert(ev < (int)_messages.size()); + // The value is an index into the string vector. + return _messages[ev]; + } + + int add(std::string msg) { + std::lock_guard<std::recursive_mutex> lock(_mutex); + // Value zero is always the successs value. + if (_messages.empty()) + _messages.push_back("Success"); + _messages.push_back(msg); + // Return the index of the string just appended. + return _messages.size() - 1; + } + +private: + std::vector<std::string> _messages; + std::recursive_mutex _mutex; +}; + +static dynamic_error_category categorySingleton; + +std::error_code make_dynamic_error_code(StringRef msg) { + return std::error_code(categorySingleton.add(msg), categorySingleton); +} + +std::error_code make_dynamic_error_code(const Twine &msg) { + return std::error_code(categorySingleton.add(msg.str()), categorySingleton); +} + +} diff --git a/lib/Core/File.cpp b/lib/Core/File.cpp new file mode 100644 index 000000000000..dbac86b368aa --- /dev/null +++ b/lib/Core/File.cpp @@ -0,0 +1,30 @@ +//===- Core/File.cpp - A Container of Atoms -------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/Core/File.h" +#include "lld/Core/LLVM.h" +#include <mutex> + +namespace lld { + +File::~File() {} + +File::atom_collection_empty<DefinedAtom> File::_noDefinedAtoms; +File::atom_collection_empty<UndefinedAtom> File::_noUndefinedAtoms; +File::atom_collection_empty<SharedLibraryAtom> File::_noSharedLibraryAtoms; +File::atom_collection_empty<AbsoluteAtom> File::_noAbsoluteAtoms; + +std::error_code File::parse() { + std::lock_guard<std::mutex> lock(_parseMutex); + if (!_lastError.hasValue()) + _lastError = doParse(); + return _lastError.getValue(); +} + +} // namespace lld diff --git a/lib/Core/LinkingContext.cpp b/lib/Core/LinkingContext.cpp new file mode 100644 index 000000000000..c6656b935916 --- /dev/null +++ b/lib/Core/LinkingContext.cpp @@ -0,0 +1,104 @@ +//===- lib/Core/LinkingContext.cpp - Linker Context Object Interface ------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/Core/Alias.h" +#include "lld/Core/LinkingContext.h" +#include "lld/Core/Resolver.h" +#include "lld/Core/Simple.h" +#include "lld/Core/Writer.h" +#include "llvm/ADT/Triple.h" + +namespace lld { + +LinkingContext::LinkingContext() + : _deadStrip(false), _allowDuplicates(false), + _globalsAreDeadStripRoots(false), + _searchArchivesToOverrideTentativeDefinitions(false), + _searchSharedLibrariesToOverrideTentativeDefinitions(false), + _warnIfCoalesableAtomsHaveDifferentCanBeNull(false), + _warnIfCoalesableAtomsHaveDifferentLoadName(false), + _printRemainingUndefines(true), _allowRemainingUndefines(false), + _logInputFiles(false), _allowShlibUndefines(false), + _outputFileType(OutputFileType::Default), _nextOrdinal(0) {} + +LinkingContext::~LinkingContext() {} + +bool LinkingContext::validate(raw_ostream &diagnostics) { + return validateImpl(diagnostics); +} + +std::error_code LinkingContext::writeFile(const File &linkedFile) const { + return this->writer().writeFile(linkedFile, _outputPath); +} + +bool LinkingContext::createImplicitFiles( + std::vector<std::unique_ptr<File> > &result) { + return this->writer().createImplicitFiles(result); +} + +std::unique_ptr<File> LinkingContext::createEntrySymbolFile() const { + return createEntrySymbolFile("<command line option -e>"); +} + +std::unique_ptr<File> +LinkingContext::createEntrySymbolFile(StringRef filename) const { + if (entrySymbolName().empty()) + return nullptr; + std::unique_ptr<SimpleFile> entryFile(new SimpleFile(filename)); + entryFile->addAtom( + *(new (_allocator) SimpleUndefinedAtom(*entryFile, entrySymbolName()))); + return std::move(entryFile); +} + +std::unique_ptr<File> LinkingContext::createUndefinedSymbolFile() const { + return createUndefinedSymbolFile("<command line option -u or --defsym>"); +} + +std::unique_ptr<File> +LinkingContext::createUndefinedSymbolFile(StringRef filename) const { + if (_initialUndefinedSymbols.empty()) + return nullptr; + std::unique_ptr<SimpleFile> undefinedSymFile(new SimpleFile(filename)); + for (StringRef undefSym : _initialUndefinedSymbols) + undefinedSymFile->addAtom(*(new (_allocator) SimpleUndefinedAtom( + *undefinedSymFile, undefSym))); + return std::move(undefinedSymFile); +} + +std::unique_ptr<File> LinkingContext::createAliasSymbolFile() const { + if (getAliases().empty()) + return nullptr; + std::unique_ptr<SimpleFile> file(new SimpleFile("<alias>")); + for (const auto &i : getAliases()) { + StringRef from = i.first; + StringRef to = i.second; + SimpleDefinedAtom *fromAtom = new (_allocator) AliasAtom(*file, from); + UndefinedAtom *toAtom = new (_allocator) SimpleUndefinedAtom(*file, to); + fromAtom->addReference(Reference::KindNamespace::all, + Reference::KindArch::all, Reference::kindLayoutAfter, + 0, toAtom, 0); + file->addAtom(*fromAtom); + file->addAtom(*toAtom); + } + return std::move(file); +} + +void LinkingContext::createInternalFiles( + std::vector<std::unique_ptr<File> > &result) const { + if (std::unique_ptr<File> file = createEntrySymbolFile()) + result.push_back(std::move(file)); + if (std::unique_ptr<File> file = createUndefinedSymbolFile()) + result.push_back(std::move(file)); + if (std::unique_ptr<File> file = createAliasSymbolFile()) + result.push_back(std::move(file)); +} + +void LinkingContext::addPasses(PassManager &pm) {} + +} // end namespace lld diff --git a/lib/Core/Makefile b/lib/Core/Makefile new file mode 100644 index 000000000000..042d01a1e1b3 --- /dev/null +++ b/lib/Core/Makefile @@ -0,0 +1,13 @@ +##===- lld/lib/Core/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 := lldCore + +include $(LLD_LEVEL)/Makefile diff --git a/lib/Core/Reader.cpp b/lib/Core/Reader.cpp new file mode 100644 index 000000000000..6f8b8cbd1bf8 --- /dev/null +++ b/lib/Core/Reader.cpp @@ -0,0 +1,117 @@ +//===- lib/Core/Reader.cpp ------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/Core/File.h" +#include "lld/Core/Reader.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/FileUtilities.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include <memory> +#include <system_error> + +namespace lld { + +YamlIOTaggedDocumentHandler::~YamlIOTaggedDocumentHandler() {} + +void Registry::add(std::unique_ptr<Reader> reader) { + _readers.push_back(std::move(reader)); +} + +void Registry::add(std::unique_ptr<YamlIOTaggedDocumentHandler> handler) { + _yamlHandlers.push_back(std::move(handler)); +} + +std::error_code +Registry::loadFile(std::unique_ptr<MemoryBuffer> mb, + std::vector<std::unique_ptr<File>> &result) const { + // Get file type. + StringRef content(mb->getBufferStart(), mb->getBufferSize()); + llvm::sys::fs::file_magic fileType = llvm::sys::fs::identify_magic(content); + // Get file extension. + StringRef extension = llvm::sys::path::extension(mb->getBufferIdentifier()); + + // Ask each registered reader if it can handle this file type or extension. + for (const std::unique_ptr<Reader> &reader : _readers) { + if (!reader->canParse(fileType, extension, *mb)) + continue; + if (std::error_code ec = reader->loadFile(std::move(mb), *this, result)) + return ec; + return std::error_code(); + } + + // No Reader could parse this file. + return make_error_code(llvm::errc::executable_format_error); +} + +static const Registry::KindStrings kindStrings[] = { + {Reference::kindLayoutAfter, "layout-after"}, + {Reference::kindGroupChild, "group-child"}, + {Reference::kindAssociate, "associate"}, + LLD_KIND_STRING_END}; + +Registry::Registry() { + addKindTable(Reference::KindNamespace::all, Reference::KindArch::all, + kindStrings); +} + +bool Registry::handleTaggedDoc(llvm::yaml::IO &io, + const lld::File *&file) const { + for (const std::unique_ptr<YamlIOTaggedDocumentHandler> &h : _yamlHandlers) + if (h->handledDocTag(io, file)) + return true; + return false; +} + + +void Registry::addKindTable(Reference::KindNamespace ns, + Reference::KindArch arch, + const KindStrings array[]) { + KindEntry entry = { ns, arch, array }; + _kindEntries.push_back(entry); +} + +bool Registry::referenceKindFromString(StringRef inputStr, + Reference::KindNamespace &ns, + Reference::KindArch &arch, + Reference::KindValue &value) const { + for (const KindEntry &entry : _kindEntries) { + for (const KindStrings *pair = entry.array; !pair->name.empty(); ++pair) { + if (!inputStr.equals(pair->name)) + continue; + ns = entry.ns; + arch = entry.arch; + value = pair->value; + return true; + } + } + return false; +} + +bool Registry::referenceKindToString(Reference::KindNamespace ns, + Reference::KindArch arch, + Reference::KindValue value, + StringRef &str) const { + for (const KindEntry &entry : _kindEntries) { + if (entry.ns != ns) + continue; + if (entry.arch != arch) + continue; + for (const KindStrings *pair = entry.array; !pair->name.empty(); ++pair) { + if (pair->value != value) + continue; + str = pair->name; + return true; + } + } + return false; +} + +} // end namespace lld diff --git a/lib/Core/Resolver.cpp b/lib/Core/Resolver.cpp new file mode 100644 index 000000000000..393a7ef2bfc8 --- /dev/null +++ b/lib/Core/Resolver.cpp @@ -0,0 +1,516 @@ +//===- Core/Resolver.cpp - Resolves Atom References -----------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/Core/Atom.h" +#include "lld/Core/ArchiveLibraryFile.h" +#include "lld/Core/File.h" +#include "lld/Core/Instrumentation.h" +#include "lld/Core/LLVM.h" +#include "lld/Core/LinkingContext.h" +#include "lld/Core/Resolver.h" +#include "lld/Core/SharedLibraryFile.h" +#include "lld/Core/SymbolTable.h" +#include "lld/Core/UndefinedAtom.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <utility> +#include <vector> + +namespace lld { + +bool Resolver::handleFile(File &file) { + bool undefAdded = false; + for (const DefinedAtom *atom : file.defined()) + doDefinedAtom(*atom); + for (const UndefinedAtom *atom : file.undefined()) { + if (doUndefinedAtom(*atom)) { + undefAdded = true; + maybePreloadArchiveMember(atom->name()); + } + } + for (const SharedLibraryAtom *atom : file.sharedLibrary()) + doSharedLibraryAtom(*atom); + for (const AbsoluteAtom *atom : file.absolute()) + doAbsoluteAtom(*atom); + return undefAdded; +} + +void Resolver::forEachUndefines(File &file, bool searchForOverrides, + UndefCallback callback) { + size_t i = _undefineIndex[&file]; + do { + for (; i < _undefines.size(); ++i) { + StringRef undefName = _undefines[i]; + if (undefName.empty()) + continue; + const Atom *atom = _symbolTable.findByName(undefName); + if (!isa<UndefinedAtom>(atom) || _symbolTable.isCoalescedAway(atom)) { + // The symbol was resolved by some other file. Cache the result. + _undefines[i] = ""; + continue; + } + callback(undefName, false); + } + if (!searchForOverrides) + continue; + for (StringRef tentDefName : _symbolTable.tentativeDefinitions()) { + // Load for previous tentative may also have loaded + // something that overrode this tentative, so always check. + const Atom *curAtom = _symbolTable.findByName(tentDefName); + assert(curAtom != nullptr); + if (const DefinedAtom *curDefAtom = dyn_cast<DefinedAtom>(curAtom)) + if (curDefAtom->merge() == DefinedAtom::mergeAsTentative) + callback(tentDefName, true); + } + } while (i < _undefines.size()); + _undefineIndex[&file] = i; +} + +bool Resolver::handleArchiveFile(File &file) { + ArchiveLibraryFile *archiveFile = cast<ArchiveLibraryFile>(&file); + bool searchForOverrides = + _ctx.searchArchivesToOverrideTentativeDefinitions(); + bool undefAdded = false; + forEachUndefines(file, searchForOverrides, + [&](StringRef undefName, bool dataSymbolOnly) { + if (File *member = archiveFile->find(undefName, dataSymbolOnly)) { + member->setOrdinal(_ctx.getNextOrdinalAndIncrement()); + member->beforeLink(); + updatePreloadArchiveMap(); + undefAdded = handleFile(*member) || undefAdded; + } + }); + return undefAdded; +} + +void Resolver::handleSharedLibrary(File &file) { + // Add all the atoms from the shared library + SharedLibraryFile *sharedLibrary = cast<SharedLibraryFile>(&file); + handleFile(*sharedLibrary); + bool searchForOverrides = + _ctx.searchSharedLibrariesToOverrideTentativeDefinitions(); + forEachUndefines(file, searchForOverrides, + [&](StringRef undefName, bool dataSymbolOnly) { + if (const SharedLibraryAtom *atom = + sharedLibrary->exports(undefName, dataSymbolOnly)) + doSharedLibraryAtom(*atom); + }); +} + +bool Resolver::doUndefinedAtom(const UndefinedAtom &atom) { + DEBUG_WITH_TYPE("resolver", llvm::dbgs() + << " UndefinedAtom: " + << llvm::format("0x%09lX", &atom) + << ", name=" << atom.name() << "\n"); + + // add to list of known atoms + _atoms.push_back(&atom); + + // tell symbol table + bool newUndefAdded = _symbolTable.add(atom); + if (newUndefAdded) + _undefines.push_back(atom.name()); + + // If the undefined symbol has an alternative name, try to resolve the + // symbol with the name to give it a second chance. This feature is used + // for COFF "weak external" symbol. + if (newUndefAdded || !_symbolTable.isDefined(atom.name())) { + if (const UndefinedAtom *fallbackAtom = atom.fallback()) { + doUndefinedAtom(*fallbackAtom); + _symbolTable.addReplacement(&atom, fallbackAtom); + } + } + return newUndefAdded; +} + +/// \brief Add the section group and the group-child reference members. +void Resolver::maybeAddSectionGroupOrGnuLinkOnce(const DefinedAtom &atom) { + // First time adding a group? + bool isFirstTime = _symbolTable.addGroup(atom); + + if (!isFirstTime) { + // If duplicate symbols are allowed, select the first group. + if (_ctx.getAllowDuplicates()) + return; + auto *prevGroup = dyn_cast<DefinedAtom>(_symbolTable.findGroup(atom.name())); + assert(prevGroup && + "Internal Error: The group atom could only be a defined atom"); + // The atoms should be of the same content type, reject invalid group + // resolution behaviors. + if (atom.contentType() == prevGroup->contentType()) + return; + llvm::errs() << "SymbolTable: error while merging " << atom.name() + << "\n"; + llvm::report_fatal_error("duplicate symbol error"); + return; + } + + for (const Reference *r : atom) { + if (r->kindNamespace() == lld::Reference::KindNamespace::all && + 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"); + _atoms.push_back(target); + _symbolTable.add(*target); + } + } +} + +// Called on each atom when a file is added. Returns true if a given +// atom is added to the symbol table. +void Resolver::doDefinedAtom(const DefinedAtom &atom) { + DEBUG_WITH_TYPE("resolver", llvm::dbgs() + << " DefinedAtom: " + << llvm::format("0x%09lX", &atom) + << ", file=#" + << atom.file().ordinal() + << ", atom=#" + << atom.ordinal() + << ", name=" + << atom.name() + << "\n"); + + // add to list of known atoms + _atoms.push_back(&atom); + + if (atom.isGroupParent()) { + maybeAddSectionGroupOrGnuLinkOnce(atom); + } else { + _symbolTable.add(atom); + } + + // An atom that should never be dead-stripped is a dead-strip root. + if (_ctx.deadStrip() && atom.deadStrip() == DefinedAtom::deadStripNever) { + _deadStripRoots.insert(&atom); + } +} + +void Resolver::doSharedLibraryAtom(const SharedLibraryAtom &atom) { + DEBUG_WITH_TYPE("resolver", llvm::dbgs() + << " SharedLibraryAtom: " + << llvm::format("0x%09lX", &atom) + << ", name=" + << atom.name() + << "\n"); + + // add to list of known atoms + _atoms.push_back(&atom); + + // tell symbol table + _symbolTable.add(atom); +} + +void Resolver::doAbsoluteAtom(const AbsoluteAtom &atom) { + DEBUG_WITH_TYPE("resolver", llvm::dbgs() + << " AbsoluteAtom: " + << llvm::format("0x%09lX", &atom) + << ", name=" + << atom.name() + << "\n"); + + // add to list of known atoms + _atoms.push_back(&atom); + + // tell symbol table + if (atom.scope() != Atom::scopeTranslationUnit) + _symbolTable.add(atom); +} + +// utility to add a vector of atoms +void Resolver::addAtoms(const std::vector<const DefinedAtom *> &newAtoms) { + for (const DefinedAtom *newAtom : newAtoms) + doDefinedAtom(*newAtom); +} + +// Instantiate an archive file member if there's a file containing a +// defined symbol for a given symbol name. Instantiation is done in a +// different worker thread and has no visible side effect. +void Resolver::maybePreloadArchiveMember(StringRef sym) { + auto it = _archiveMap.find(sym); + if (it == _archiveMap.end()) + return; + ArchiveLibraryFile *archive = it->second; + archive->preload(_ctx.getTaskGroup(), sym); +} + +// Returns true if at least one of N previous files has created an +// undefined symbol. +bool Resolver::undefinesAdded(int begin, int end) { + std::vector<std::unique_ptr<Node>> &inputs = _ctx.getNodes(); + for (int i = begin; i < end; ++i) + if (FileNode *node = dyn_cast<FileNode>(inputs[i].get())) + if (_newUndefinesAdded[node->getFile()]) + return true; + return false; +} + +File *Resolver::getFile(int &index) { + std::vector<std::unique_ptr<Node>> &inputs = _ctx.getNodes(); + if ((size_t)index >= inputs.size()) + return nullptr; + if (GroupEnd *group = dyn_cast<GroupEnd>(inputs[index].get())) { + // We are at the end of the current group. If one or more new + // undefined atom has been added in the last groupSize files, we + // reiterate over the files. + int size = group->getSize(); + if (undefinesAdded(index - size, index)) { + index -= size; + return getFile(index); + } + ++index; + return getFile(index); + } + return cast<FileNode>(inputs[index++].get())->getFile(); +} + +// Update a map of Symbol -> ArchiveFile. The map is used for speculative +// file loading. +void Resolver::updatePreloadArchiveMap() { + std::vector<std::unique_ptr<Node>> &nodes = _ctx.getNodes(); + for (int i = nodes.size() - 1; i >= 0; --i) { + auto *fnode = dyn_cast<FileNode>(nodes[i].get()); + if (!fnode) + continue; + auto *archive = dyn_cast<ArchiveLibraryFile>(fnode->getFile()); + if (!archive || _archiveSeen.count(archive)) + continue; + _archiveSeen.insert(archive); + for (StringRef sym : archive->getDefinedSymbols()) + _archiveMap[sym] = archive; + } +} + +// Keep adding atoms until _ctx.getNextFile() returns an error. This +// function is where undefined atoms are resolved. +bool Resolver::resolveUndefines() { + ScopedTask task(getDefaultDomain(), "resolveUndefines"); + int index = 0; + std::set<File *> seen; + for (;;) { + bool undefAdded = false; + File *file = getFile(index); + if (!file) + return true; + if (std::error_code ec = file->parse()) { + llvm::errs() << "Cannot open " + file->path() + << ": " << ec.message() << "\n"; + return false; + } + file->beforeLink(); + updatePreloadArchiveMap(); + switch (file->kind()) { + case File::kindObject: + // The same file may be visited more than once if the file is + // in --start-group and --end-group. Only library files should + // be processed more than once. + if (seen.count(file)) + break; + seen.insert(file); + assert(!file->hasOrdinal()); + file->setOrdinal(_ctx.getNextOrdinalAndIncrement()); + undefAdded = handleFile(*file); + break; + case File::kindArchiveLibrary: + if (!file->hasOrdinal()) + file->setOrdinal(_ctx.getNextOrdinalAndIncrement()); + undefAdded = handleArchiveFile(*file); + break; + case File::kindSharedLibrary: + if (!file->hasOrdinal()) + file->setOrdinal(_ctx.getNextOrdinalAndIncrement()); + handleSharedLibrary(*file); + break; + } + _newUndefinesAdded[file] = undefAdded; + } +} + +// switch all references to undefined or coalesced away atoms +// to the new defined atom +void Resolver::updateReferences() { + ScopedTask task(getDefaultDomain(), "updateReferences"); + for (const Atom *atom : _atoms) { + if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom)) { + for (const Reference *ref : *defAtom) { + // A reference of type kindAssociate should't be updated. + // Instead, an atom having such reference will be removed + // if the target atom is coalesced away, so that they will + // go away as a group. + if (ref->kindNamespace() == lld::Reference::KindNamespace::all && + ref->kindValue() == lld::Reference::kindAssociate) { + if (_symbolTable.isCoalescedAway(atom)) + _deadAtoms.insert(ref->target()); + continue; + } + const Atom *newTarget = _symbolTable.replacement(ref->target()); + const_cast<Reference *>(ref)->setTarget(newTarget); + } + } + } +} + +// For dead code stripping, recursively mark atoms "live" +void Resolver::markLive(const Atom *atom) { + // Mark the atom is live. If it's already marked live, then stop recursion. + auto exists = _liveAtoms.insert(atom); + if (!exists.second) + return; + + // Mark all atoms it references as live + if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom)) { + for (const Reference *ref : *defAtom) + markLive(ref->target()); + for (auto &p : llvm::make_range(_reverseRef.equal_range(defAtom))) { + const Atom *target = p.second; + markLive(target); + } + } +} + +static bool isBackref(const Reference *ref) { + if (ref->kindNamespace() != lld::Reference::KindNamespace::all) + return false; + return (ref->kindValue() == lld::Reference::kindLayoutAfter || + ref->kindValue() == lld::Reference::kindGroupChild); +} + +// remove all atoms not actually used +void Resolver::deadStripOptimize() { + ScopedTask task(getDefaultDomain(), "deadStripOptimize"); + // only do this optimization with -dead_strip + if (!_ctx.deadStrip()) + return; + + // Some type of references prevent referring atoms to be dead-striped. + // Make a reverse map of such references before traversing the graph. + // While traversing the list of atoms, mark AbsoluteAtoms as live + // in order to avoid reclaim. + for (const Atom *atom : _atoms) { + if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom)) + for (const Reference *ref : *defAtom) + if (isBackref(ref)) + _reverseRef.insert(std::make_pair(ref->target(), atom)); + if (const AbsoluteAtom *absAtom = dyn_cast<AbsoluteAtom>(atom)) + markLive(absAtom); + } + + // By default, shared libraries are built with all globals as dead strip roots + if (_ctx.globalsAreDeadStripRoots()) + for (const Atom *atom : _atoms) + if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom)) + if (defAtom->scope() == DefinedAtom::scopeGlobal) + _deadStripRoots.insert(defAtom); + + // Or, use list of names that are dead strip roots. + for (const StringRef &name : _ctx.deadStripRoots()) { + const Atom *symAtom = _symbolTable.findByName(name); + assert(symAtom); + _deadStripRoots.insert(symAtom); + } + + // mark all roots as live, and recursively all atoms they reference + for (const Atom *dsrAtom : _deadStripRoots) + markLive(dsrAtom); + + // now remove all non-live atoms from _atoms + _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), [&](const Atom *a) { + return _liveAtoms.count(a) == 0; + }), + _atoms.end()); +} + +// error out if some undefines remain +bool Resolver::checkUndefines() { + // build vector of remaining undefined symbols + std::vector<const UndefinedAtom *> undefinedAtoms = _symbolTable.undefines(); + if (_ctx.deadStrip()) { + // When dead code stripping, we don't care if dead atoms are undefined. + undefinedAtoms.erase( + std::remove_if(undefinedAtoms.begin(), undefinedAtoms.end(), + [&](const Atom *a) { return _liveAtoms.count(a) == 0; }), + undefinedAtoms.end()); + } + + if (undefinedAtoms.empty()) + return false; + + // Warn about unresolved symbols. + bool foundUndefines = false; + for (const UndefinedAtom *undef : undefinedAtoms) { + // Skip over a weak symbol. + if (undef->canBeNull() != UndefinedAtom::canBeNullNever) + continue; + + // If this is a library and undefined symbols are allowed on the + // target platform, skip over it. + if (isa<SharedLibraryFile>(undef->file()) && _ctx.allowShlibUndefines()) + continue; + + // If the undefine is coalesced away, skip over it. + if (_symbolTable.isCoalescedAway(undef)) + continue; + + // Seems like this symbol is undefined. Warn that. + foundUndefines = true; + if (_ctx.printRemainingUndefines()) { + llvm::errs() << "Undefined symbol: " << undef->file().path() + << ": " << _ctx.demangle(undef->name()) + << "\n"; + } + } + if (!foundUndefines) + return false; + if (_ctx.printRemainingUndefines()) + llvm::errs() << "symbol(s) not found\n"; + return true; +} + +// remove from _atoms all coaleseced away atoms +void Resolver::removeCoalescedAwayAtoms() { + ScopedTask task(getDefaultDomain(), "removeCoalescedAwayAtoms"); + _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), [&](const Atom *a) { + return _symbolTable.isCoalescedAway(a) || _deadAtoms.count(a); + }), + _atoms.end()); +} + +bool Resolver::resolve() { + updatePreloadArchiveMap(); + if (!resolveUndefines()) + return false; + updateReferences(); + deadStripOptimize(); + if (checkUndefines()) + if (!_ctx.allowRemainingUndefines()) + return false; + removeCoalescedAwayAtoms(); + _result->addAtoms(_atoms); + return true; +} + +void Resolver::MergedFile::addAtoms(std::vector<const Atom *> &all) { + ScopedTask task(getDefaultDomain(), "addAtoms"); + DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "Resolver final atom list:\n"); + for (const Atom *atom : all) { + DEBUG_WITH_TYPE("resolver", llvm::dbgs() + << llvm::format(" 0x%09lX", atom) + << ", name=" + << atom->name() + << "\n"); + addAtom(*atom); + } +} + +} // namespace lld diff --git a/lib/Core/SymbolTable.cpp b/lib/Core/SymbolTable.cpp new file mode 100644 index 000000000000..f3f2da9262e0 --- /dev/null +++ b/lib/Core/SymbolTable.cpp @@ -0,0 +1,390 @@ +//===- Core/SymbolTable.cpp - Main Symbol Table ---------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/Core/SymbolTable.h" +#include "lld/Core/AbsoluteAtom.h" +#include "lld/Core/Atom.h" +#include "lld/Core/DefinedAtom.h" +#include "lld/Core/File.h" +#include "lld/Core/LLVM.h" +#include "lld/Core/LinkingContext.h" +#include "lld/Core/Resolver.h" +#include "lld/Core/SharedLibraryAtom.h" +#include "lld/Core/UndefinedAtom.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cstdlib> +#include <vector> + +namespace lld { +SymbolTable::SymbolTable(LinkingContext &context) : _context(context) {} + +bool SymbolTable::add(const UndefinedAtom &atom) { return addByName(atom); } + +bool SymbolTable::add(const SharedLibraryAtom &atom) { return addByName(atom); } + +bool SymbolTable::add(const AbsoluteAtom &atom) { return addByName(atom); } + +bool SymbolTable::add(const DefinedAtom &atom) { + if (!atom.name().empty() && + atom.scope() != DefinedAtom::scopeTranslationUnit) { + // Named atoms cannot be merged by content. + assert(atom.merge() != DefinedAtom::mergeByContent); + // Track named atoms that are not scoped to file (static). + return addByName(atom); + } + if (atom.merge() == DefinedAtom::mergeByContent) { + // Named atoms cannot be merged by content. + assert(atom.name().empty()); + // Currently only read-only constants can be merged. + if (atom.permissions() == DefinedAtom::permR__) + return addByContent(atom); + // TODO: support mergeByContent of data atoms by comparing content & fixups. + } + return false; +} + +const Atom *SymbolTable::findGroup(StringRef sym) { + NameToAtom::iterator pos = _groupTable.find(sym); + if (pos == _groupTable.end()) + return nullptr; + return pos->second; +} + +bool SymbolTable::addGroup(const DefinedAtom &da) { + StringRef name = da.name(); + assert(!name.empty()); + const Atom *existing = findGroup(name); + if (existing == nullptr) { + _groupTable[name] = &da; + return true; + } + _replacedAtoms[&da] = existing; + return false; +} + +enum NameCollisionResolution { + NCR_First, + NCR_Second, + NCR_DupDef, + NCR_DupUndef, + NCR_DupShLib, + NCR_Error +}; + +static NameCollisionResolution cases[4][4] = { + //regular absolute undef sharedLib + { + // first is regular + NCR_DupDef, NCR_Error, NCR_First, NCR_First + }, + { + // first is absolute + NCR_Error, NCR_Error, NCR_First, NCR_First + }, + { + // first is undef + NCR_Second, NCR_Second, NCR_DupUndef, NCR_Second + }, + { + // first is sharedLib + NCR_Second, NCR_Second, NCR_First, NCR_DupShLib + } +}; + +static NameCollisionResolution collide(Atom::Definition first, + Atom::Definition second) { + return cases[first][second]; +} + +enum MergeResolution { + MCR_First, + MCR_Second, + MCR_Largest, + MCR_SameSize, + MCR_Error +}; + +static MergeResolution mergeCases[][6] = { + // no tentative weak weakAddress sameNameAndSize largest + {MCR_Error, MCR_First, MCR_First, MCR_First, MCR_SameSize, MCR_Largest}, // no + {MCR_Second, MCR_Largest, MCR_Second, MCR_Second, MCR_SameSize, MCR_Largest}, // tentative + {MCR_Second, MCR_First, MCR_First, MCR_Second, MCR_SameSize, MCR_Largest}, // weak + {MCR_Second, MCR_First, MCR_First, MCR_First, MCR_SameSize, MCR_Largest}, // weakAddress + {MCR_SameSize, MCR_SameSize, MCR_SameSize, MCR_SameSize, MCR_SameSize, MCR_SameSize}, // sameSize + {MCR_Largest, MCR_Largest, MCR_Largest, MCR_Largest, MCR_SameSize, MCR_Largest}, // largest +}; + +static MergeResolution mergeSelect(DefinedAtom::Merge first, + DefinedAtom::Merge second) { + assert(first != DefinedAtom::mergeByContent); + assert(second != DefinedAtom::mergeByContent); + return mergeCases[first][second]; +} + +bool SymbolTable::addByName(const Atom &newAtom) { + StringRef name = newAtom.name(); + assert(!name.empty()); + const Atom *existing = findByName(name); + if (existing == nullptr) { + // Name is not in symbol table yet, add it associate with this atom. + _nameTable[name] = &newAtom; + return true; + } + + // Do nothing if the same object is added more than once. + if (existing == &newAtom) + return false; + + // Name is already in symbol table and associated with another atom. + bool useNew = true; + switch (collide(existing->definition(), newAtom.definition())) { + case NCR_First: + useNew = false; + break; + case NCR_Second: + useNew = true; + break; + case NCR_DupDef: { + const auto *existingDef = cast<DefinedAtom>(existing); + const auto *newDef = cast<DefinedAtom>(&newAtom); + switch (mergeSelect(existingDef->merge(), newDef->merge())) { + case MCR_First: + useNew = false; + break; + case MCR_Second: + useNew = true; + break; + case MCR_Largest: { + uint64_t existingSize = existingDef->sectionSize(); + uint64_t newSize = newDef->sectionSize(); + useNew = (newSize >= existingSize); + break; + } + case MCR_SameSize: { + uint64_t existingSize = existingDef->sectionSize(); + uint64_t newSize = newDef->sectionSize(); + if (existingSize == newSize) { + useNew = true; + break; + } + llvm::errs() << "Size mismatch: " + << existing->name() << " (" << existingSize << ") " + << newAtom.name() << " (" << newSize << ")\n"; + // fallthrough + } + case MCR_Error: + if (!_context.getAllowDuplicates()) { + llvm::errs() << "Duplicate symbols: " + << existing->name() + << ":" + << existing->file().path() + << " and " + << newAtom.name() + << ":" + << newAtom.file().path() + << "\n"; + llvm::report_fatal_error("duplicate symbol error"); + } + useNew = false; + break; + } + break; + } + case NCR_DupUndef: { + const UndefinedAtom* existingUndef = cast<UndefinedAtom>(existing); + const UndefinedAtom* newUndef = cast<UndefinedAtom>(&newAtom); + + bool sameCanBeNull = (existingUndef->canBeNull() == newUndef->canBeNull()); + if (!sameCanBeNull && + _context.warnIfCoalesableAtomsHaveDifferentCanBeNull()) { + llvm::errs() << "lld warning: undefined symbol " + << existingUndef->name() + << " has different weakness in " + << existingUndef->file().path() + << " and in " << newUndef->file().path() << "\n"; + } + + const UndefinedAtom *existingFallback = existingUndef->fallback(); + const UndefinedAtom *newFallback = newUndef->fallback(); + bool hasDifferentFallback = + (existingFallback && newFallback && + existingFallback->name() != newFallback->name()); + if (hasDifferentFallback) { + llvm::errs() << "lld warning: undefined symbol " + << existingUndef->name() << " has different fallback: " + << existingFallback->name() << " in " + << existingUndef->file().path() << " and " + << newFallback->name() << " in " + << newUndef->file().path() << "\n"; + } + + bool hasNewFallback = newUndef->fallback(); + if (sameCanBeNull) + useNew = hasNewFallback; + else + useNew = (newUndef->canBeNull() < existingUndef->canBeNull()); + break; + } + case NCR_DupShLib: { + const SharedLibraryAtom *curShLib = cast<SharedLibraryAtom>(existing); + const SharedLibraryAtom *newShLib = cast<SharedLibraryAtom>(&newAtom); + bool sameNullness = + (curShLib->canBeNullAtRuntime() == newShLib->canBeNullAtRuntime()); + bool sameName = curShLib->loadName().equals(newShLib->loadName()); + if (sameName && !sameNullness && + _context.warnIfCoalesableAtomsHaveDifferentCanBeNull()) { + // FIXME: need diagonstics interface for writing warning messages + llvm::errs() << "lld warning: shared library symbol " + << curShLib->name() << " has different weakness in " + << curShLib->file().path() << " and in " + << newShLib->file().path(); + } + if (!sameName && _context.warnIfCoalesableAtomsHaveDifferentLoadName()) { + // FIXME: need diagonstics interface for writing warning messages + llvm::errs() << "lld warning: shared library symbol " + << curShLib->name() << " has different load path in " + << curShLib->file().path() << " and in " + << newShLib->file().path(); + } + useNew = false; + break; + } + case NCR_Error: + llvm::errs() << "SymbolTable: error while merging " << name << "\n"; + llvm::report_fatal_error("duplicate symbol error"); + break; + } + + // Give context a chance to change which is kept. + _context.notifySymbolTableCoalesce(existing, &newAtom, useNew); + + if (useNew) { + // Update name table to use new atom. + _nameTable[name] = &newAtom; + // Add existing atom to replacement table. + _replacedAtoms[existing] = &newAtom; + } else { + // New atom is not being used. Add it to replacement table. + _replacedAtoms[&newAtom] = existing; + } + return false; +} + +unsigned SymbolTable::AtomMappingInfo::getHashValue(const DefinedAtom *atom) { + auto content = atom->rawContent(); + return llvm::hash_combine(atom->size(), + atom->contentType(), + llvm::hash_combine_range(content.begin(), + content.end())); +} + +bool SymbolTable::AtomMappingInfo::isEqual(const DefinedAtom * const l, + const DefinedAtom * const r) { + if (l == r) + return true; + if (l == getEmptyKey()) + return false; + if (r == getEmptyKey()) + return false; + if (l == getTombstoneKey()) + return false; + if (r == getTombstoneKey()) + return false; + if (l->contentType() != r->contentType()) + return false; + if (l->size() != r->size()) + return false; + if (l->sectionChoice() != r->sectionChoice()) + return false; + if (l->sectionChoice() == DefinedAtom::sectionCustomRequired) { + if (!l->customSectionName().equals(r->customSectionName())) + return false; + } + ArrayRef<uint8_t> lc = l->rawContent(); + ArrayRef<uint8_t> rc = r->rawContent(); + return memcmp(lc.data(), rc.data(), lc.size()) == 0; +} + +bool SymbolTable::addByContent(const DefinedAtom &newAtom) { + AtomContentSet::iterator pos = _contentTable.find(&newAtom); + if (pos == _contentTable.end()) { + _contentTable.insert(&newAtom); + return true; + } + const Atom* existing = *pos; + // New atom is not being used. Add it to replacement table. + _replacedAtoms[&newAtom] = existing; + return false; +} + +const Atom *SymbolTable::findByName(StringRef sym) { + NameToAtom::iterator pos = _nameTable.find(sym); + if (pos == _nameTable.end()) + return nullptr; + return pos->second; +} + +bool SymbolTable::isDefined(StringRef sym) { + if (const Atom *atom = findByName(sym)) + return !isa<UndefinedAtom>(atom); + return false; +} + +void SymbolTable::addReplacement(const Atom *replaced, + const Atom *replacement) { + _replacedAtoms[replaced] = replacement; +} + +const Atom *SymbolTable::replacement(const Atom *atom) { + // Find the replacement for a given atom. Atoms in _replacedAtoms + // may be chained, so find the last one. + for (;;) { + AtomToAtom::iterator pos = _replacedAtoms.find(atom); + if (pos == _replacedAtoms.end()) + return atom; + atom = pos->second; + } +} + +bool SymbolTable::isCoalescedAway(const Atom *atom) { + return _replacedAtoms.count(atom) > 0; +} + +std::vector<const UndefinedAtom *> SymbolTable::undefines() { + std::vector<const UndefinedAtom *> ret; + for (auto it : _nameTable) { + const Atom *atom = it.second; + assert(atom != nullptr); + if (const auto *undef = dyn_cast<const UndefinedAtom>(atom)) + if (_replacedAtoms.count(undef) == 0) + ret.push_back(undef); + } + return ret; +} + +std::vector<StringRef> SymbolTable::tentativeDefinitions() { + std::vector<StringRef> ret; + for (auto entry : _nameTable) { + const Atom *atom = entry.second; + StringRef name = entry.first; + assert(atom != nullptr); + if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom)) + if (defAtom->merge() == DefinedAtom::mergeAsTentative) + ret.push_back(name); + } + return ret; +} + +} // namespace lld diff --git a/lib/Core/TODO.txt b/lib/Core/TODO.txt new file mode 100644 index 000000000000..196a3e02c2fc --- /dev/null +++ b/lib/Core/TODO.txt @@ -0,0 +1,18 @@ +lib/Core +~~~~~~~~ + +* Add endianness support to the native reader and writer. + +* The NativeReader has lots of similar code for converting arrays of ivar + data in mapped memory into arrays of objects. The commonality can be + factored out, maybe templatized. + +* The NativeFileFormat.h is old school C structs and constants. We scope + things better by defining constants used with a struct inside the struct + declaration. + +* The native reader and writer currently just blast in memory enumeration + values (e.g. DefinedAtom::Scope) into a byte in the disk format. To support + future changes to the enumerations, there should be a translation layer + to map disk values to in-memory values. + diff --git a/lib/Core/Writer.cpp b/lib/Core/Writer.cpp new file mode 100644 index 000000000000..39bcc9e68523 --- /dev/null +++ b/lib/Core/Writer.cpp @@ -0,0 +1,23 @@ +//===- lib/Core/Writer.cpp ------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/Core/File.h" +#include "lld/Core/Writer.h" + +namespace lld { +Writer::Writer() { +} + +Writer::~Writer() { +} + +bool Writer::createImplicitFiles(std::vector<std::unique_ptr<File> > &) { + return true; +} +} // end namespace lld |
