diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:48:50 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:48:50 +0000 |
commit | 1c98619801a5705c688e683be3ef9d70169a0686 (patch) | |
tree | 8422105cd1a94c368315f2db16b9ac746cf7c000 /lib/Core/Resolver.cpp | |
parent | f4f3ce4613680903220815690ad79fc7ba0a2e26 (diff) |
Notes
Diffstat (limited to 'lib/Core/Resolver.cpp')
-rw-r--r-- | lib/Core/Resolver.cpp | 330 |
1 files changed, 139 insertions, 191 deletions
diff --git a/lib/Core/Resolver.cpp b/lib/Core/Resolver.cpp index 8f89856c4a47..ef694fd972fc 100644 --- a/lib/Core/Resolver.cpp +++ b/lib/Core/Resolver.cpp @@ -19,6 +19,7 @@ #include "lld/Core/UndefinedAtom.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" @@ -29,26 +30,27 @@ namespace lld { -bool Resolver::handleFile(File &file) { +llvm::Expected<bool> Resolver::handleFile(File &file) { + if (auto ec = _ctx.handleLoadedFile(file)) + return std::move(ec); bool undefAdded = false; - for (const DefinedAtom *atom : file.defined()) - doDefinedAtom(*atom); - for (const UndefinedAtom *atom : file.undefined()) { - if (doUndefinedAtom(*atom)) { + for (auto &atom : file.defined().owning_ptrs()) + doDefinedAtom(std::move(atom)); + for (auto &atom : file.undefined().owning_ptrs()) { + if (doUndefinedAtom(std::move(atom))) undefAdded = true; - maybePreloadArchiveMember(atom->name()); - } } - for (const SharedLibraryAtom *atom : file.sharedLibrary()) - doSharedLibraryAtom(*atom); - for (const AbsoluteAtom *atom : file.absolute()) - doAbsoluteAtom(*atom); + for (auto &atom : file.sharedLibrary().owning_ptrs()) + doSharedLibraryAtom(std::move(atom)); + for (auto &atom : file.absolute().owning_ptrs()) + doAbsoluteAtom(std::move(atom)); return undefAdded; } -void Resolver::forEachUndefines(File &file, bool searchForOverrides, - UndefCallback callback) { +llvm::Expected<bool> Resolver::forEachUndefines(File &file, + UndefCallback callback) { size_t i = _undefineIndex[&file]; + bool undefAdded = false; do { for (; i < _undefines.size(); ++i) { StringRef undefName = _undefines[i]; @@ -60,190 +62,120 @@ void Resolver::forEachUndefines(File &file, bool searchForOverrides, _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); + auto undefAddedOrError = callback(undefName); + if (auto ec = undefAddedOrError.takeError()) + return std::move(ec); + undefAdded |= undefAddedOrError.get(); } } while (i < _undefines.size()); _undefineIndex[&file] = i; + return undefAdded; } -bool Resolver::handleArchiveFile(File &file) { +llvm::Expected<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)) { + return forEachUndefines(file, + [&](StringRef undefName) -> llvm::Expected<bool> { + if (File *member = archiveFile->find(undefName)) { member->setOrdinal(_ctx.getNextOrdinalAndIncrement()); - member->beforeLink(); - updatePreloadArchiveMap(); - undefAdded = handleFile(*member) || undefAdded; + return handleFile(*member); } + return false; }); - return undefAdded; } -void Resolver::handleSharedLibrary(File &file) { +llvm::Error 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); - }); + auto undefAddedOrError = handleFile(*sharedLibrary); + if (auto ec = undefAddedOrError.takeError()) + return ec; + undefAddedOrError = + forEachUndefines(file, [&](StringRef undefName) -> llvm::Expected<bool> { + auto atom = sharedLibrary->exports(undefName); + if (atom.get()) + doSharedLibraryAtom(std::move(atom)); + return false; + }); + + if (auto ec = undefAddedOrError.takeError()) + return ec; + return llvm::Error(); } -bool Resolver::doUndefinedAtom(const UndefinedAtom &atom) { +bool Resolver::doUndefinedAtom(OwningAtomPtr<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); + << llvm::format("0x%09lX", atom.get()) + << ", name=" << atom.get()->name() << "\n"); // tell symbol table - bool newUndefAdded = _symbolTable.add(atom); + bool newUndefAdded = _symbolTable.add(*atom.get()); 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; -} + _undefines.push_back(atom.get()->name()); -/// \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"); - } + // add to list of known atoms + _atoms.push_back(OwningAtomPtr<Atom>(atom.release())); - 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); - } - } + return newUndefAdded; } // 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) { +void Resolver::doDefinedAtom(OwningAtomPtr<DefinedAtom> atom) { DEBUG_WITH_TYPE("resolver", llvm::dbgs() << " DefinedAtom: " - << llvm::format("0x%09lX", &atom) + << llvm::format("0x%09lX", atom.get()) << ", file=#" - << atom.file().ordinal() + << atom.get()->file().ordinal() << ", atom=#" - << atom.ordinal() + << atom.get()->ordinal() << ", name=" - << atom.name() + << atom.get()->name() << ", type=" - << atom.contentType() + << atom.get()->contentType() << "\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); + if (_ctx.deadStrip() && + atom.get()->deadStrip() == DefinedAtom::deadStripNever) { + _deadStripRoots.insert(atom.get()); } + + // add to list of known atoms + _symbolTable.add(*atom.get()); + _atoms.push_back(OwningAtomPtr<Atom>(atom.release())); } -void Resolver::doSharedLibraryAtom(const SharedLibraryAtom &atom) { +void Resolver::doSharedLibraryAtom(OwningAtomPtr<SharedLibraryAtom> atom) { DEBUG_WITH_TYPE("resolver", llvm::dbgs() << " SharedLibraryAtom: " - << llvm::format("0x%09lX", &atom) + << llvm::format("0x%09lX", atom.get()) << ", name=" - << atom.name() + << atom.get()->name() << "\n"); - // add to list of known atoms - _atoms.push_back(&atom); - // tell symbol table - _symbolTable.add(atom); + _symbolTable.add(*atom.get()); + + // add to list of known atoms + _atoms.push_back(OwningAtomPtr<Atom>(atom.release())); } -void Resolver::doAbsoluteAtom(const AbsoluteAtom &atom) { +void Resolver::doAbsoluteAtom(OwningAtomPtr<AbsoluteAtom> atom) { DEBUG_WITH_TYPE("resolver", llvm::dbgs() << " AbsoluteAtom: " - << llvm::format("0x%09lX", &atom) + << llvm::format("0x%09lX", atom.get()) << ", name=" - << atom.name() + << atom.get()->name() << "\n"); - // add to list of known atoms - _atoms.push_back(&atom); - // tell symbol table - if (atom.scope() != Atom::scopeTranslationUnit) - _symbolTable.add(atom); -} + if (atom.get()->scope() != Atom::scopeTranslationUnit) + _symbolTable.add(*atom.get()); -// 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); + // add to list of known atoms + _atoms.push_back(OwningAtomPtr<Atom>(atom.release())); } // Returns true if at least one of N previous files has created an @@ -276,23 +208,6 @@ File *Resolver::getFile(int &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() { @@ -315,10 +230,17 @@ bool Resolver::resolveUndefines() { } DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "Loaded file: " << file->path() << "\n"); - file->beforeLink(); - updatePreloadArchiveMap(); switch (file->kind()) { - case File::kindObject: + case File::kindErrorObject: + case File::kindNormalizedObject: + case File::kindMachObject: + case File::kindCEntryObject: + case File::kindHeaderObject: + case File::kindEntryObject: + case File::kindUndefinedSymsObject: + case File::kindStubHelperObject: + case File::kindResolverMergedObject: + case File::kindSectCreateObject: { // 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. @@ -327,17 +249,41 @@ bool Resolver::resolveUndefines() { seen.insert(file); assert(!file->hasOrdinal()); file->setOrdinal(_ctx.getNextOrdinalAndIncrement()); - undefAdded = handleFile(*file); + auto undefAddedOrError = handleFile(*file); + if (auto EC = undefAddedOrError.takeError()) { + // FIXME: This should be passed to logAllUnhandledErrors but it needs + // to be passed a Twine instead of a string. + llvm::errs() << "Error in " + file->path() << ": "; + logAllUnhandledErrors(std::move(EC), llvm::errs(), std::string()); + return false; + } + undefAdded = undefAddedOrError.get(); break; - case File::kindArchiveLibrary: + } + case File::kindArchiveLibrary: { if (!file->hasOrdinal()) file->setOrdinal(_ctx.getNextOrdinalAndIncrement()); - undefAdded = handleArchiveFile(*file); + auto undefAddedOrError = handleArchiveFile(*file); + if (auto EC = undefAddedOrError.takeError()) { + // FIXME: This should be passed to logAllUnhandledErrors but it needs + // to be passed a Twine instead of a string. + llvm::errs() << "Error in " + file->path() << ": "; + logAllUnhandledErrors(std::move(EC), llvm::errs(), std::string()); + return false; + } + undefAdded = undefAddedOrError.get(); break; + } case File::kindSharedLibrary: if (!file->hasOrdinal()) file->setOrdinal(_ctx.getNextOrdinalAndIncrement()); - handleSharedLibrary(*file); + if (auto EC = handleSharedLibrary(*file)) { + // FIXME: This should be passed to logAllUnhandledErrors but it needs + // to be passed a Twine instead of a string. + llvm::errs() << "Error in " + file->path() << ": "; + logAllUnhandledErrors(std::move(EC), llvm::errs(), std::string()); + return false; + } break; } _newUndefinesAdded[file] = undefAdded; @@ -350,8 +296,8 @@ void Resolver::updateReferences() { DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "******** Updating references:\n"); ScopedTask task(getDefaultDomain(), "updateReferences"); - for (const Atom *atom : _atoms) { - if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom)) { + for (const OwningAtomPtr<Atom> &atom : _atoms) { + if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom.get())) { for (const Reference *ref : *defAtom) { // A reference of type kindAssociate should't be updated. // Instead, an atom having such reference will be removed @@ -359,7 +305,7 @@ void Resolver::updateReferences() { // go away as a group. if (ref->kindNamespace() == lld::Reference::KindNamespace::all && ref->kindValue() == lld::Reference::kindAssociate) { - if (_symbolTable.isCoalescedAway(atom)) + if (_symbolTable.isCoalescedAway(atom.get())) _deadAtoms.insert(ref->target()); continue; } @@ -391,8 +337,7 @@ void Resolver::markLive(const Atom *atom) { 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); + return (ref->kindValue() == lld::Reference::kindLayoutAfter); } // remove all atoms not actually used @@ -408,19 +353,19 @@ void Resolver::deadStripOptimize() { // 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 OwningAtomPtr<Atom> &atom : _atoms) { + if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom.get())) for (const Reference *ref : *defAtom) if (isBackref(ref)) - _reverseRef.insert(std::make_pair(ref->target(), atom)); - if (const AbsoluteAtom *absAtom = dyn_cast<AbsoluteAtom>(atom)) + _reverseRef.insert(std::make_pair(ref->target(), atom.get())); + if (const AbsoluteAtom *absAtom = dyn_cast<AbsoluteAtom>(atom.get())) 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)) + for (const OwningAtomPtr<Atom> &atom : _atoms) + if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom.get())) if (defAtom->scope() == DefinedAtom::scopeGlobal) _deadStripRoots.insert(defAtom); @@ -436,8 +381,9 @@ void Resolver::deadStripOptimize() { 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.erase(std::remove_if(_atoms.begin(), _atoms.end(), + [&](OwningAtomPtr<Atom> &a) { + return _liveAtoms.count(a.get()) == 0; }), _atoms.end()); } @@ -496,8 +442,10 @@ void Resolver::removeCoalescedAwayAtoms() { DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "******** Removing coalesced away atoms:\n"); ScopedTask task(getDefaultDomain(), "removeCoalescedAwayAtoms"); - _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), [&](const Atom *a) { - return _symbolTable.isCoalescedAway(a) || _deadAtoms.count(a); + _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), + [&](OwningAtomPtr<Atom> &a) { + return _symbolTable.isCoalescedAway(a.get()) || + _deadAtoms.count(a.get()); }), _atoms.end()); } @@ -505,7 +453,6 @@ void Resolver::removeCoalescedAwayAtoms() { bool Resolver::resolve() { DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "******** Resolving atom references:\n"); - updatePreloadArchiveMap(); if (!resolveUndefines()) return false; updateReferences(); @@ -524,15 +471,16 @@ bool Resolver::resolve() { return true; } -void Resolver::MergedFile::addAtoms(std::vector<const Atom *> &all) { +void Resolver::MergedFile::addAtoms( + llvm::MutableArrayRef<OwningAtomPtr<Atom>> all) { ScopedTask task(getDefaultDomain(), "addAtoms"); DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "Resolver final atom list:\n"); - for (const Atom *atom : all) { + for (OwningAtomPtr<Atom> &atom : all) { #ifndef NDEBUG - if (auto *definedAtom = dyn_cast<DefinedAtom>(atom)) { + if (auto *definedAtom = dyn_cast<DefinedAtom>(atom.get())) { DEBUG_WITH_TYPE("resolver", llvm::dbgs() - << llvm::format(" 0x%09lX", atom) + << llvm::format(" 0x%09lX", definedAtom) << ", file=#" << definedAtom->file().ordinal() << ", atom=#" @@ -544,13 +492,13 @@ void Resolver::MergedFile::addAtoms(std::vector<const Atom *> &all) { << "\n"); } else { DEBUG_WITH_TYPE("resolver", llvm::dbgs() - << llvm::format(" 0x%09lX", atom) + << llvm::format(" 0x%09lX", atom.get()) << ", name=" - << atom->name() + << atom.get()->name() << "\n"); } #endif - addAtom(*atom); + addAtom(*atom.release()); } } |