summaryrefslogtreecommitdiff
path: root/lib/Core
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2015-03-24 21:31:36 +0000
committerDimitry Andric <dim@FreeBSD.org>2015-03-24 21:31:36 +0000
commitfb911942f1434f3d1750f83f25f5e42c80e60638 (patch)
tree1678c4a4f0182e4029a86d135aa4a1b7d09e3c41 /lib/Core
Notes
Diffstat (limited to 'lib/Core')
-rw-r--r--lib/Core/CMakeLists.txt12
-rw-r--r--lib/Core/DefinedAtom.cpp96
-rw-r--r--lib/Core/Error.cpp151
-rw-r--r--lib/Core/File.cpp30
-rw-r--r--lib/Core/LinkingContext.cpp104
-rw-r--r--lib/Core/Makefile13
-rw-r--r--lib/Core/Reader.cpp117
-rw-r--r--lib/Core/Resolver.cpp516
-rw-r--r--lib/Core/SymbolTable.cpp390
-rw-r--r--lib/Core/TODO.txt18
-rw-r--r--lib/Core/Writer.cpp23
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