diff options
Diffstat (limited to 'lld/lib/Core/Resolver.cpp')
-rw-r--r-- | lld/lib/Core/Resolver.cpp | 337 |
1 files changed, 337 insertions, 0 deletions
diff --git a/lld/lib/Core/Resolver.cpp b/lld/lib/Core/Resolver.cpp new file mode 100644 index 00000000000..b3be26bf188 --- /dev/null +++ b/lld/lib/Core/Resolver.cpp @@ -0,0 +1,337 @@ +//===- 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/Resolver.h" +#include "lld/Core/Atom.h" +#include "lld/Core/File.h" +#include "lld/Core/InputFiles.h" +#include "lld/Core/SymbolTable.h" +#include "lld/Core/UndefinedAtom.h" +#include "lld/Platform/Platform.h" + +#include "llvm/Support/raw_ostream.h" + +#include <algorithm> +#include <cassert> +#include <vector> + +namespace lld { + +class NotLive { +public: + bool operator()(const Atom *atom) const { + return !(atom->live() || !atom->deadStrip()); + } +}; + +class AtomCoalescedAway { +public: + AtomCoalescedAway(SymbolTable &sym) : _symbolTable(sym) {} + + bool operator()(const Atom *atom) const { + const Atom *rep = _symbolTable.replacement(atom); + return rep != atom; + } + +private: + SymbolTable &_symbolTable; +}; + +void Resolver::initializeState() { + _platform.initialize(); +} + +// add initial undefines from -u option +void Resolver::addInitialUndefines() { + +} + +// add all atoms from all initial .o files +void Resolver::buildInitialAtomList() { + // each input files contributes initial atoms + _atoms.reserve(1024); + _inputFiles.forEachInitialAtom(*this); + + _completedInitialObjectFiles = true; +} + + +// called before the first atom in any file is added with doAtom() +void Resolver::doFile(const File &file) { + // notify platform + _platform.fileAdded(file); +} + +// called on each atom when a file is added +void Resolver::doAtom(const Atom &atom) { + // notify platform + _platform.atomAdded(atom); + + // add to list of known atoms + _atoms.push_back(&atom); + + // adjust scope (e.g. force some globals to be hidden) + _platform.adjustScope(atom); + + // non-static atoms need extra handling + if (atom.scope() != Atom::scopeTranslationUnit) { + // tell symbol table about non-static atoms + _symbolTable.add(atom); + + // platform can add aliases for any symbol + std::vector<const Atom *> aliases; + if (_platform.getAliasAtoms(atom, aliases)) + this->addAtoms(aliases); + } + + if (_platform.deadCodeStripping()) { + // add to set of dead-strip-roots, all symbols that + // the compiler marks as don't strip + if (!atom.deadStrip()) + _deadStripRoots.insert(&atom); + + // add to set of dead-strip-roots, all symbols that + // the platform decided must remain + if (_platform.isDeadStripRoot(atom)) + _deadStripRoots.insert(&atom); + } +} + +// utility to add a vector of atoms +void Resolver::addAtoms(const std::vector<const Atom *> &newAtoms) { + for (std::vector<const Atom *>::const_iterator it = newAtoms.begin(); + it != newAtoms.end(); ++it) { + this->doAtom(**it); + } +} + +// ask symbol table if any definitionUndefined atoms still exist +// if so, keep searching libraries until no more atoms being added +void Resolver::resolveUndefines() { + const bool searchArchives = + _platform.searchArchivesToOverrideTentativeDefinitions(); + const bool searchDylibs = + _platform.searchSharedLibrariesToOverrideTentativeDefinitions(); + + // keep looping until no more undefines were added in last loop + unsigned int undefineGenCount = 0xFFFFFFFF; + while (undefineGenCount != _symbolTable.size()) { + undefineGenCount = _symbolTable.size(); + std::vector<const Atom *> undefines; + _symbolTable.undefines(undefines); + for (std::vector<const Atom *>::iterator it = undefines.begin(); + it != undefines.end(); ++it) { + llvm::StringRef undefName = (*it)->name(); + // load for previous undefine may also have loaded this undefine + if (!_symbolTable.isDefined(undefName)) { + _inputFiles.searchLibraries(undefName, true, true, false, *this); + + // give platform a chance to instantiate platform + // specific atoms (e.g. section boundary) + if (!_symbolTable.isDefined(undefName)) { + std::vector<const Atom *> platAtoms; + if (_platform.getPlatformAtoms(undefName, platAtoms)) + this->addAtoms(platAtoms); + } + } + } + // search libraries for overrides of common symbols + if (searchArchives || searchDylibs) { + std::vector<const Atom *> tents; + for (std::vector<const Atom *>::iterator ait = _atoms.begin(); + ait != _atoms.end(); ++ait) { + const Atom *atom = *ait; + if (atom->definition() == Atom::definitionTentative) + tents.push_back(atom); + } + for (std::vector<const Atom *>::iterator dit = tents.begin(); + dit != tents.end(); ++dit) { + // load for previous tentative may also have loaded + // this tentative, so check again + llvm::StringRef tentName = (*dit)->name(); + const Atom *curAtom = _symbolTable.findByName(tentName); + assert(curAtom != NULL); + if (curAtom->definition() == Atom::definitionTentative) { + _inputFiles.searchLibraries(tentName, searchDylibs, true, true, + *this); + } + } + } + } +} + +// switch all references to undefined or coalesced away atoms +// to the new defined atom +void Resolver::updateReferences() { + for (std::vector<const Atom *>::iterator it = _atoms.begin(); + it != _atoms.end(); ++it) { + const Atom *atom = *it; + for (Reference::iterator rit = atom->referencesBegin(), + end = atom->referencesEnd(); rit != end; ++rit) { + rit->target = _symbolTable.replacement(rit->target); + } + } +} + +// for dead code stripping, recursively mark atom "live" +void Resolver::markLive(const Atom &atom, WhyLiveBackChain *previous) { + // if -why_live cares about this symbol, then dump chain + if ((previous->referer != NULL) && _platform.printWhyLive(atom.name())) { + llvm::errs() << atom.name() << " from " << atom.file()->path() << "\n"; + int depth = 1; + for (WhyLiveBackChain *p = previous; p != NULL; + p = p->previous, ++depth) { + for (int i = depth; i > 0; --i) + llvm::errs() << " "; + llvm::errs() << p->referer->name() << " from " + << p->referer->file()->path() << "\n"; + } + } + + // if already marked live, then done (stop recursion) + if (atom.live()) + return; + + // mark this atom is live + const_cast<Atom *>(&atom)->setLive(true); + + // mark all atoms it references as live + WhyLiveBackChain thisChain; + thisChain.previous = previous; + thisChain.referer = &atom; + for (Reference::iterator rit = atom.referencesBegin(), + end = atom.referencesEnd(); rit != end; ++rit) { + this->markLive(*(rit->target), &thisChain); + } +} + +// remove all atoms not actually used +void Resolver::deadStripOptimize() { + // only do this optimization with -dead_strip + if (!_platform.deadCodeStripping()) + return; + + // clear liveness on all atoms + for (std::vector<const Atom *>::iterator it = _atoms.begin(); + it != _atoms.end(); ++it) { + const Atom *atom = *it; + const_cast<Atom *>(atom)->setLive(0); + } + + // add entry point (main) to live roots + const Atom *entry = this->entryPoint(); + if (entry != NULL) + _deadStripRoots.insert(entry); + + // add -exported_symbols_list, -init, and -u entries to live roots + for (Platform::UndefinesIterator uit = _platform.initialUndefinesBegin(); + uit != _platform.initialUndefinesEnd(); ++uit) { + llvm::StringRef sym = *uit; + const Atom *symAtom = _symbolTable.findByName(sym); + assert(symAtom->definition() != Atom::definitionUndefined); + _deadStripRoots.insert(symAtom); + } + + // add platform specific helper atoms + std::vector<const Atom *> platRootAtoms; + if (_platform.getImplicitDeadStripRoots(platRootAtoms)) + this->addAtoms(platRootAtoms); + + // mark all roots as live, and recursively all atoms they reference + for (std::set<const Atom *>::iterator it = _deadStripRoots.begin(); + it != _deadStripRoots.end(); ++it) { + WhyLiveBackChain rootChain; + rootChain.previous = NULL; + rootChain.referer = *it; + this->markLive(**it, &rootChain); + } + + // now remove all non-live atoms from _atoms + _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), + NotLive()), _atoms.end()); +} + +// error out if some undefines remain +void Resolver::checkUndefines(bool final) { + // when using LTO, undefines are checked after bitcode is optimized + if (_haveLLVMObjs && !final) + return; + + // build vector of remaining undefined symbols + std::vector<const Atom *> undefinedAtoms; + _symbolTable.undefines(undefinedAtoms); + if (_platform.deadCodeStripping()) { + // when dead code stripping we don't care if dead atoms are undefined + undefinedAtoms.erase(std::remove_if( + undefinedAtoms.begin(), undefinedAtoms.end(), + NotLive()), undefinedAtoms.end()); + } + + // let platform make error message about missing symbols + if (undefinedAtoms.size() != 0) + _platform.errorWithUndefines(undefinedAtoms, _atoms); +} + +// remove from _atoms all coaleseced away atoms +void Resolver::removeCoalescedAwayAtoms() { + _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), + AtomCoalescedAway(_symbolTable)), _atoms.end()); +} + +// check for interactions between symbols defined in this linkage unit +// and same symbol name in linked dynamic shared libraries +void Resolver::checkDylibSymbolCollisions() { + for (std::vector<const Atom *>::const_iterator it = _atoms.begin(); + it != _atoms.end(); ++it) { + const Atom *atom = *it; + if (atom->scope() == Atom::scopeGlobal) { + if (atom->definition() == Atom::definitionTentative) { + // See if any shared library also has symbol which + // collides with the tentative definition. + // SymbolTable will warn if needed. + _inputFiles.searchLibraries(atom->name(), true, false, false, *this); + } + } + } +} + +// get "main" atom for linkage unit +const Atom *Resolver::entryPoint() { + llvm::StringRef symbolName = _platform.entryPointName(); + if (symbolName != NULL) + return _symbolTable.findByName(symbolName); + + return NULL; +} + +// give platform a chance to tweak the set of atoms +void Resolver::tweakAtoms() { + _platform.postResolveTweaks(_atoms); +} + +void Resolver::linkTimeOptimize() { + // FIX ME +} + +std::vector<const Atom *> &Resolver::resolve() { + this->initializeState(); + this->addInitialUndefines(); + this->buildInitialAtomList(); + this->resolveUndefines(); + this->updateReferences(); + this->deadStripOptimize(); + this->checkUndefines(false); + this->removeCoalescedAwayAtoms(); + this->checkDylibSymbolCollisions(); + this->linkTimeOptimize(); + this->tweakAtoms(); + return _atoms; +} + +} // namespace lld |