2011-12-18 16:27:59 +08:00
|
|
|
//===- 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"
|
2013-10-07 10:47:09 +08:00
|
|
|
#include "lld/Core/ArchiveLibraryFile.h"
|
2011-12-18 16:27:59 +08:00
|
|
|
#include "lld/Core/File.h"
|
2013-10-07 10:47:09 +08:00
|
|
|
#include "lld/Core/SharedLibraryFile.h"
|
2013-05-29 02:55:39 +08:00
|
|
|
#include "lld/Core/Instrumentation.h"
|
2012-04-04 02:39:40 +08:00
|
|
|
#include "lld/Core/LLVM.h"
|
2012-06-01 06:34:00 +08:00
|
|
|
#include "lld/Core/Resolver.h"
|
2011-12-18 16:27:59 +08:00
|
|
|
#include "lld/Core/SymbolTable.h"
|
2013-08-07 06:31:59 +08:00
|
|
|
#include "lld/Core/LinkingContext.h"
|
2011-12-18 16:27:59 +08:00
|
|
|
#include "lld/Core/UndefinedAtom.h"
|
|
|
|
|
2012-06-01 06:34:00 +08:00
|
|
|
#include "llvm/Support/Debug.h"
|
2013-01-23 04:49:42 +08:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
2012-06-01 06:34:00 +08:00
|
|
|
#include "llvm/Support/Format.h"
|
2011-12-18 16:27:59 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
#include <cassert>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
namespace lld {
|
|
|
|
|
2013-05-09 05:34:11 +08:00
|
|
|
namespace {
|
|
|
|
|
2012-04-04 02:40:27 +08:00
|
|
|
/// This is used as a filter function to std::remove_if to dead strip atoms.
|
2011-12-18 16:27:59 +08:00
|
|
|
class NotLive {
|
|
|
|
public:
|
2013-05-09 05:34:11 +08:00
|
|
|
explicit NotLive(const llvm::DenseSet<const Atom*>& la) : _liveAtoms(la) { }
|
2012-04-04 02:40:27 +08:00
|
|
|
|
2011-12-18 16:27:59 +08:00
|
|
|
bool operator()(const Atom *atom) const {
|
2012-01-11 09:06:19 +08:00
|
|
|
// don't remove if live
|
|
|
|
if ( _liveAtoms.count(atom) )
|
|
|
|
return false;
|
2012-02-07 10:59:54 +08:00
|
|
|
// don't remove if marked never-dead-strip
|
2012-04-04 02:39:40 +08:00
|
|
|
if (const DefinedAtom* defAtom = dyn_cast<DefinedAtom>(atom)) {
|
2012-01-11 09:06:19 +08:00
|
|
|
if ( defAtom->deadStrip() == DefinedAtom::deadStripNever )
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// do remove this atom
|
|
|
|
return true;
|
2011-12-18 16:27:59 +08:00
|
|
|
}
|
2012-04-04 02:40:27 +08:00
|
|
|
|
2012-01-11 09:06:19 +08:00
|
|
|
private:
|
|
|
|
const llvm::DenseSet<const Atom*> _liveAtoms;
|
2011-12-18 16:27:59 +08:00
|
|
|
};
|
|
|
|
|
2012-01-11 09:06:19 +08:00
|
|
|
|
2012-04-04 02:40:27 +08:00
|
|
|
/// This is used as a filter function to std::remove_if to coalesced atoms.
|
2011-12-18 16:27:59 +08:00
|
|
|
class AtomCoalescedAway {
|
|
|
|
public:
|
2013-05-09 05:34:11 +08:00
|
|
|
explicit AtomCoalescedAway(SymbolTable &sym) : _symbolTable(sym) {}
|
2011-12-18 16:27:59 +08:00
|
|
|
|
|
|
|
bool operator()(const Atom *atom) const {
|
|
|
|
const Atom *rep = _symbolTable.replacement(atom);
|
|
|
|
return rep != atom;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
SymbolTable &_symbolTable;
|
|
|
|
};
|
|
|
|
|
2013-05-09 05:34:11 +08:00
|
|
|
} // namespace
|
|
|
|
|
2013-10-07 10:47:09 +08:00
|
|
|
// called before the first atom in any file is added with doAtom()
|
|
|
|
void Resolver::doFile(const File &file) {}
|
|
|
|
|
|
|
|
void Resolver::handleFile(const File &file) {
|
2013-10-08 11:59:45 +08:00
|
|
|
uint32_t resolverState = Resolver::StateNoChange;
|
2013-10-07 10:47:09 +08:00
|
|
|
doFile(file);
|
|
|
|
for (const DefinedAtom *atom : file.defined()) {
|
|
|
|
doDefinedAtom(*atom);
|
|
|
|
resolverState |= StateNewDefinedAtoms;
|
|
|
|
}
|
|
|
|
for (const UndefinedAtom *undefAtom : file.undefined()) {
|
|
|
|
doUndefinedAtom(*undefAtom);
|
|
|
|
resolverState |= StateNewUndefinedAtoms;
|
|
|
|
}
|
|
|
|
for (const SharedLibraryAtom *shlibAtom : file.sharedLibrary()) {
|
|
|
|
doSharedLibraryAtom(*shlibAtom);
|
|
|
|
resolverState |= StateNewSharedLibraryAtoms;
|
|
|
|
}
|
|
|
|
for (const AbsoluteAtom *absAtom : file.absolute()) {
|
|
|
|
doAbsoluteAtom(*absAtom);
|
|
|
|
resolverState |= StateNewAbsoluteAtoms;
|
|
|
|
}
|
|
|
|
_context.setResolverState(resolverState);
|
|
|
|
}
|
2012-01-11 09:06:19 +08:00
|
|
|
|
2013-10-07 10:47:09 +08:00
|
|
|
void Resolver::handleArchiveFile(const File &file) {
|
|
|
|
const ArchiveLibraryFile *archiveFile = dyn_cast<ArchiveLibraryFile>(&file);
|
2011-12-18 16:27:59 +08:00
|
|
|
|
2013-10-07 10:47:09 +08:00
|
|
|
// Handle normal archives
|
|
|
|
int64_t undefineGenCount = 0;
|
|
|
|
do {
|
|
|
|
undefineGenCount = _symbolTable.size();
|
|
|
|
std::vector<const UndefinedAtom *> undefines;
|
|
|
|
_symbolTable.undefines(undefines);
|
|
|
|
for (const UndefinedAtom *undefAtom : undefines) {
|
|
|
|
StringRef undefName = undefAtom->name();
|
|
|
|
// load for previous undefine may also have loaded this undefine
|
|
|
|
if (!_symbolTable.isDefined(undefName)) {
|
2013-10-09 13:23:23 +08:00
|
|
|
if (const File *member = archiveFile->find(undefName, false)) {
|
|
|
|
member->setOrdinal(_context.getNextOrdinalAndIncrement());
|
2013-10-07 10:47:09 +08:00
|
|
|
handleFile(*member);
|
2013-10-09 13:23:23 +08:00
|
|
|
}
|
2013-10-07 10:47:09 +08:00
|
|
|
}
|
|
|
|
// 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 (!_symbolTable.isDefined(undefName)) {
|
|
|
|
if (const UndefinedAtom *fallbackUndefAtom = undefAtom->fallback()) {
|
|
|
|
_symbolTable.addReplacement(undefAtom, fallbackUndefAtom);
|
|
|
|
_symbolTable.add(*fallbackUndefAtom);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// search libraries for overrides of common symbols
|
|
|
|
if (_context.searchArchivesToOverrideTentativeDefinitions()) {
|
|
|
|
std::vector<StringRef> tentDefNames;
|
|
|
|
_symbolTable.tentativeDefinitions(tentDefNames);
|
|
|
|
for (StringRef tentDefName : tentDefNames) {
|
|
|
|
// 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) {
|
2013-10-09 13:23:23 +08:00
|
|
|
if (const File *member = archiveFile->find(tentDefName, true)) {
|
|
|
|
member->setOrdinal(_context.getNextOrdinalAndIncrement());
|
2013-10-07 10:47:09 +08:00
|
|
|
handleFile(*member);
|
2013-10-09 13:23:23 +08:00
|
|
|
}
|
2013-10-07 10:47:09 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} while (undefineGenCount != _symbolTable.size());
|
2011-12-18 16:27:59 +08:00
|
|
|
}
|
|
|
|
|
2013-10-07 10:47:09 +08:00
|
|
|
void Resolver::handleSharedLibrary(const File &file) {
|
|
|
|
const SharedLibraryFile *sharedLibrary = dyn_cast<SharedLibraryFile>(&file);
|
|
|
|
int64_t undefineGenCount = 0;
|
2011-12-18 16:27:59 +08:00
|
|
|
|
2013-10-07 10:47:09 +08:00
|
|
|
// Add all the atoms from the shared library
|
|
|
|
handleFile(*sharedLibrary);
|
|
|
|
do {
|
|
|
|
undefineGenCount = _symbolTable.size();
|
|
|
|
std::vector<const UndefinedAtom *> undefines;
|
|
|
|
_symbolTable.undefines(undefines);
|
|
|
|
for (const UndefinedAtom *undefAtom : undefines) {
|
|
|
|
StringRef undefName = undefAtom->name();
|
|
|
|
// load for previous undefine may also have loaded this undefine
|
|
|
|
if (!_symbolTable.isDefined(undefName)) {
|
|
|
|
if (const SharedLibraryAtom *shAtom =
|
|
|
|
sharedLibrary->exports(undefName, false))
|
|
|
|
doSharedLibraryAtom(*shAtom);
|
|
|
|
}
|
|
|
|
// 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 (!_symbolTable.isDefined(undefName)) {
|
|
|
|
if (const UndefinedAtom *fallbackUndefAtom = undefAtom->fallback()) {
|
|
|
|
_symbolTable.addReplacement(undefAtom, fallbackUndefAtom);
|
|
|
|
_symbolTable.add(*fallbackUndefAtom);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// search libraries for overrides of common symbols
|
|
|
|
if (_context.searchSharedLibrariesToOverrideTentativeDefinitions()) {
|
|
|
|
std::vector<StringRef> tentDefNames;
|
|
|
|
_symbolTable.tentativeDefinitions(tentDefNames);
|
|
|
|
for (StringRef tentDefName : tentDefNames) {
|
|
|
|
// 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) {
|
|
|
|
if (const SharedLibraryAtom *shAtom =
|
|
|
|
sharedLibrary->exports(tentDefName, true))
|
|
|
|
doSharedLibraryAtom(*shAtom);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} while (undefineGenCount != _symbolTable.size());
|
|
|
|
}
|
2012-01-11 09:06:19 +08:00
|
|
|
|
2013-06-22 03:59:15 +08:00
|
|
|
void Resolver::doUndefinedAtom(const UndefinedAtom& atom) {
|
2012-06-01 06:34:00 +08:00
|
|
|
DEBUG_WITH_TYPE("resolver", llvm::dbgs()
|
|
|
|
<< " UndefinedAtom: "
|
|
|
|
<< llvm::format("0x%09lX", &atom)
|
|
|
|
<< ", name="
|
|
|
|
<< atom.name()
|
|
|
|
<< "\n");
|
|
|
|
|
|
|
|
// add to list of known atoms
|
2012-01-11 09:06:19 +08:00
|
|
|
_atoms.push_back(&atom);
|
2012-04-04 02:40:27 +08:00
|
|
|
|
2012-01-11 09:06:19 +08:00
|
|
|
// tell symbol table
|
|
|
|
_symbolTable.add(atom);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-12-18 16:27:59 +08:00
|
|
|
// called on each atom when a file is added
|
2012-01-11 09:06:19 +08:00
|
|
|
void Resolver::doDefinedAtom(const DefinedAtom &atom) {
|
2012-06-01 06:34:00 +08:00
|
|
|
DEBUG_WITH_TYPE("resolver", llvm::dbgs()
|
|
|
|
<< " DefinedAtom: "
|
|
|
|
<< llvm::format("0x%09lX", &atom)
|
2013-01-24 06:32:56 +08:00
|
|
|
<< ", file=#"
|
|
|
|
<< atom.file().ordinal()
|
|
|
|
<< ", atom=#"
|
|
|
|
<< atom.ordinal()
|
2012-06-01 06:34:00 +08:00
|
|
|
<< ", name="
|
|
|
|
<< atom.name()
|
|
|
|
<< "\n");
|
|
|
|
|
2013-01-24 06:32:56 +08:00
|
|
|
// Verify on zero-size atoms are pinned to start or end of section.
|
|
|
|
switch ( atom.sectionPosition() ) {
|
2013-03-15 00:09:49 +08:00
|
|
|
case DefinedAtom::sectionPositionStart:
|
2013-01-24 06:32:56 +08:00
|
|
|
case DefinedAtom::sectionPositionEnd:
|
2013-11-13 11:30:29 +08:00
|
|
|
assert(atom.size() == 0);
|
2013-01-24 06:32:56 +08:00
|
|
|
break;
|
2013-03-15 00:09:49 +08:00
|
|
|
case DefinedAtom::sectionPositionEarly:
|
|
|
|
case DefinedAtom::sectionPositionAny:
|
2013-01-24 06:32:56 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2011-12-18 16:27:59 +08:00
|
|
|
// add to list of known atoms
|
|
|
|
_atoms.push_back(&atom);
|
2012-04-04 02:40:27 +08:00
|
|
|
|
2013-03-15 00:09:49 +08:00
|
|
|
// tell symbol table
|
2013-01-15 08:17:57 +08:00
|
|
|
_symbolTable.add(atom);
|
2012-06-01 06:34:00 +08:00
|
|
|
|
2013-08-07 06:31:59 +08:00
|
|
|
if (_context.deadStrip()) {
|
2011-12-18 16:27:59 +08:00
|
|
|
// add to set of dead-strip-roots, all symbols that
|
|
|
|
// the compiler marks as don't strip
|
2012-04-19 05:55:06 +08:00
|
|
|
if (atom.deadStrip() == DefinedAtom::deadStripNever)
|
2011-12-18 16:27:59 +08:00
|
|
|
_deadStripRoots.insert(&atom);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-23 05:56:59 +08:00
|
|
|
void Resolver::doSharedLibraryAtom(const SharedLibraryAtom& atom) {
|
2012-06-01 06:34:00 +08:00
|
|
|
DEBUG_WITH_TYPE("resolver", llvm::dbgs()
|
|
|
|
<< " SharedLibraryAtom: "
|
|
|
|
<< llvm::format("0x%09lX", &atom)
|
|
|
|
<< ", name="
|
|
|
|
<< atom.name()
|
|
|
|
<< "\n");
|
|
|
|
|
2012-02-23 05:56:59 +08:00
|
|
|
// add to list of known atoms
|
|
|
|
_atoms.push_back(&atom);
|
2012-04-04 02:40:27 +08:00
|
|
|
|
2012-02-23 05:56:59 +08:00
|
|
|
// tell symbol table
|
|
|
|
_symbolTable.add(atom);
|
|
|
|
}
|
2012-04-04 02:40:27 +08:00
|
|
|
|
2012-02-23 05:56:59 +08:00
|
|
|
void Resolver::doAbsoluteAtom(const AbsoluteAtom& atom) {
|
2012-06-01 06:34:00 +08:00
|
|
|
DEBUG_WITH_TYPE("resolver", llvm::dbgs()
|
|
|
|
<< " AbsoluteAtom: "
|
|
|
|
<< llvm::format("0x%09lX", &atom)
|
|
|
|
<< ", name="
|
|
|
|
<< atom.name()
|
|
|
|
<< "\n");
|
|
|
|
|
2012-02-23 05:56:59 +08:00
|
|
|
// add to list of known atoms
|
|
|
|
_atoms.push_back(&atom);
|
2012-04-04 02:40:27 +08:00
|
|
|
|
2012-02-23 05:56:59 +08:00
|
|
|
// tell symbol table
|
2012-11-06 03:13:54 +08:00
|
|
|
if (atom.scope() != Atom::scopeTranslationUnit) {
|
|
|
|
_symbolTable.add(atom);
|
|
|
|
}
|
2012-02-23 05:56:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-04 02:40:27 +08:00
|
|
|
|
2011-12-18 16:27:59 +08:00
|
|
|
// utility to add a vector of atoms
|
2012-01-11 09:06:19 +08:00
|
|
|
void Resolver::addAtoms(const std::vector<const DefinedAtom*>& newAtoms) {
|
2013-05-09 12:00:44 +08:00
|
|
|
for (const DefinedAtom *newAtom : newAtoms) {
|
|
|
|
this->doDefinedAtom(*newAtom);
|
2011-12-18 16:27:59 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-11 14:26:16 +08:00
|
|
|
// Keep adding atoms until _context.nextFile() returns an error. This function
|
|
|
|
// is where undefined atoms are resolved.
|
|
|
|
bool Resolver::resolveUndefines() {
|
2013-05-29 02:55:39 +08:00
|
|
|
ScopedTask task(getDefaultDomain(), "resolveUndefines");
|
2013-10-07 10:47:09 +08:00
|
|
|
|
2013-10-11 11:48:06 +08:00
|
|
|
for (;;) {
|
|
|
|
ErrorOr<File &> file = _context.nextFile();
|
2013-10-09 11:40:29 +08:00
|
|
|
_context.setResolverState(Resolver::StateNoChange);
|
2013-10-11 11:48:06 +08:00
|
|
|
if (error_code(file) == InputGraphError::no_more_files)
|
2013-10-11 14:26:16 +08:00
|
|
|
return true;
|
2013-10-11 11:48:06 +08:00
|
|
|
if (!file) {
|
|
|
|
llvm::errs() << "Error occurred in nextFile: "
|
|
|
|
<< error_code(file).message() << "\n";
|
2013-10-11 14:26:16 +08:00
|
|
|
return false;
|
2013-10-09 13:23:23 +08:00
|
|
|
}
|
2013-10-11 11:48:06 +08:00
|
|
|
|
|
|
|
switch (file->kind()) {
|
|
|
|
case File::kindObject:
|
|
|
|
assert(!file->hasOrdinal());
|
|
|
|
file->setOrdinal(_context.getNextOrdinalAndIncrement());
|
|
|
|
handleFile(*file);
|
|
|
|
break;
|
|
|
|
case File::kindArchiveLibrary:
|
|
|
|
if (!file->hasOrdinal())
|
|
|
|
file->setOrdinal(_context.getNextOrdinalAndIncrement());
|
|
|
|
handleArchiveFile(*file);
|
|
|
|
break;
|
|
|
|
case File::kindSharedLibrary:
|
|
|
|
if (!file->hasOrdinal())
|
|
|
|
file->setOrdinal(_context.getNextOrdinalAndIncrement());
|
|
|
|
handleSharedLibrary(*file);
|
|
|
|
break;
|
|
|
|
case File::kindLinkerScript:
|
|
|
|
llvm_unreachable("linker script should not be returned by nextFile()");
|
2013-10-09 13:23:23 +08:00
|
|
|
}
|
2013-10-07 10:47:09 +08:00
|
|
|
}
|
2011-12-18 16:27:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// switch all references to undefined or coalesced away atoms
|
|
|
|
// to the new defined atom
|
|
|
|
void Resolver::updateReferences() {
|
2013-05-29 02:55:39 +08:00
|
|
|
ScopedTask task(getDefaultDomain(), "updateReferences");
|
2012-04-09 07:52:13 +08:00
|
|
|
for(const Atom *atom : _atoms) {
|
|
|
|
if (const DefinedAtom* defAtom = dyn_cast<DefinedAtom>(atom)) {
|
|
|
|
for (const Reference *ref : *defAtom) {
|
2012-03-08 08:18:30 +08:00
|
|
|
const Atom* newTarget = _symbolTable.replacement(ref->target());
|
|
|
|
(const_cast<Reference*>(ref))->setTarget(newTarget);
|
|
|
|
}
|
2011-12-18 16:27:59 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-15 08:38:09 +08:00
|
|
|
|
2012-04-19 05:55:06 +08:00
|
|
|
// for dead code stripping, recursively mark atoms "live"
|
|
|
|
void Resolver::markLive(const Atom &atom) {
|
2011-12-18 16:27:59 +08:00
|
|
|
// if already marked live, then done (stop recursion)
|
2012-01-11 09:06:19 +08:00
|
|
|
if ( _liveAtoms.count(&atom) )
|
2011-12-18 16:27:59 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
// mark this atom is live
|
2012-01-11 09:06:19 +08:00
|
|
|
_liveAtoms.insert(&atom);
|
2011-12-18 16:27:59 +08:00
|
|
|
|
|
|
|
// mark all atoms it references as live
|
2012-04-04 02:39:40 +08:00
|
|
|
if ( const DefinedAtom* defAtom = dyn_cast<DefinedAtom>(&atom)) {
|
2012-04-09 07:52:13 +08:00
|
|
|
for (const Reference *ref : *defAtom) {
|
2012-04-19 05:55:06 +08:00
|
|
|
const Atom *target = ref->target();
|
|
|
|
if ( target != nullptr )
|
|
|
|
this->markLive(*target);
|
2012-03-08 08:18:30 +08:00
|
|
|
}
|
2011-12-18 16:27:59 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-19 05:55:06 +08:00
|
|
|
|
2011-12-18 16:27:59 +08:00
|
|
|
// remove all atoms not actually used
|
2013-10-17 03:21:50 +08:00
|
|
|
void Resolver::deadStripOptimize() {
|
2013-05-29 02:55:39 +08:00
|
|
|
ScopedTask task(getDefaultDomain(), "deadStripOptimize");
|
2011-12-18 16:27:59 +08:00
|
|
|
// only do this optimization with -dead_strip
|
2013-08-07 06:31:59 +08:00
|
|
|
if (!_context.deadStrip())
|
2013-10-17 03:21:50 +08:00
|
|
|
return;
|
2011-12-18 16:27:59 +08:00
|
|
|
|
|
|
|
// clear liveness on all atoms
|
2012-01-11 09:06:19 +08:00
|
|
|
_liveAtoms.clear();
|
2011-12-18 16:27:59 +08:00
|
|
|
|
2012-04-19 05:55:06 +08:00
|
|
|
// By default, shared libraries are built with all globals as dead strip roots
|
2013-08-07 06:31:59 +08:00
|
|
|
if (_context.globalsAreDeadStripRoots()) {
|
|
|
|
for (const Atom *atom : _atoms) {
|
2012-04-19 05:55:06 +08:00
|
|
|
const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom);
|
|
|
|
if (defAtom == nullptr)
|
|
|
|
continue;
|
|
|
|
if ( defAtom->scope() == DefinedAtom::scopeGlobal )
|
|
|
|
_deadStripRoots.insert(defAtom);
|
|
|
|
}
|
|
|
|
}
|
2012-06-01 06:34:00 +08:00
|
|
|
|
2012-04-19 05:55:06 +08:00
|
|
|
// Or, use list of names that are dead stip roots.
|
2013-08-07 06:31:59 +08:00
|
|
|
for (const StringRef &name : _context.deadStripRoots()) {
|
2012-04-19 05:55:06 +08:00
|
|
|
const Atom *symAtom = _symbolTable.findByName(name);
|
2013-10-17 03:21:50 +08:00
|
|
|
assert(symAtom);
|
|
|
|
if (symAtom->definition() == Atom::definitionUndefined)
|
|
|
|
// Dead-strip root atoms can be undefined at this point only when
|
|
|
|
// allowUndefines flag is on. Skip such undefines.
|
|
|
|
continue;
|
2011-12-18 16:27:59 +08:00
|
|
|
_deadStripRoots.insert(symAtom);
|
|
|
|
}
|
|
|
|
|
|
|
|
// mark all roots as live, and recursively all atoms they reference
|
2012-04-09 07:52:13 +08:00
|
|
|
for ( const Atom *dsrAtom : _deadStripRoots) {
|
2012-04-19 05:55:06 +08:00
|
|
|
this->markLive(*dsrAtom);
|
2011-12-18 16:27:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// now remove all non-live atoms from _atoms
|
|
|
|
_atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(),
|
2012-01-11 09:06:19 +08:00
|
|
|
NotLive(_liveAtoms)), _atoms.end());
|
2011-12-18 16:27:59 +08:00
|
|
|
}
|
|
|
|
|
2012-04-19 05:55:06 +08:00
|
|
|
|
2011-12-18 16:27:59 +08:00
|
|
|
// error out if some undefines remain
|
2013-04-05 02:59:24 +08:00
|
|
|
bool Resolver::checkUndefines(bool final) {
|
2011-12-18 16:27:59 +08:00
|
|
|
// when using LTO, undefines are checked after bitcode is optimized
|
|
|
|
if (_haveLLVMObjs && !final)
|
2013-04-05 02:59:24 +08:00
|
|
|
return false;
|
2011-12-18 16:27:59 +08:00
|
|
|
|
|
|
|
// build vector of remaining undefined symbols
|
2013-02-01 06:56:13 +08:00
|
|
|
std::vector<const UndefinedAtom *> undefinedAtoms;
|
2011-12-18 16:27:59 +08:00
|
|
|
_symbolTable.undefines(undefinedAtoms);
|
2013-08-07 06:31:59 +08:00
|
|
|
if (_context.deadStrip()) {
|
2012-04-19 05:55:06 +08:00
|
|
|
// When dead code stripping, we don't care if dead atoms are undefined.
|
2011-12-18 16:27:59 +08:00
|
|
|
undefinedAtoms.erase(std::remove_if(
|
|
|
|
undefinedAtoms.begin(), undefinedAtoms.end(),
|
2012-01-11 09:06:19 +08:00
|
|
|
NotLive(_liveAtoms)), undefinedAtoms.end());
|
2011-12-18 16:27:59 +08:00
|
|
|
}
|
|
|
|
|
2012-04-19 05:55:06 +08:00
|
|
|
// error message about missing symbols
|
2013-04-05 02:59:24 +08:00
|
|
|
if (!undefinedAtoms.empty()) {
|
2013-04-11 10:56:30 +08:00
|
|
|
// FIXME: need diagnostics interface for writing error messages
|
2013-04-05 02:59:24 +08:00
|
|
|
bool foundUndefines = false;
|
2013-02-01 06:56:13 +08:00
|
|
|
for (const UndefinedAtom *undefAtom : undefinedAtoms) {
|
2013-04-11 10:56:30 +08:00
|
|
|
const File &f = undefAtom->file();
|
2013-04-25 03:00:26 +08:00
|
|
|
|
|
|
|
// Skip over a weak symbol.
|
|
|
|
if (undefAtom->canBeNull() != UndefinedAtom::canBeNullNever)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// If this is a library and undefined symbols are allowed on the
|
|
|
|
// target platform, skip over it.
|
2013-08-07 06:31:59 +08:00
|
|
|
if (isa<SharedLibraryFile>(f) && _context.allowShlibUndefines())
|
2013-04-25 03:00:26 +08:00
|
|
|
continue;
|
|
|
|
|
2013-09-13 05:42:52 +08:00
|
|
|
// If the undefine is coalesced away, skip over it.
|
|
|
|
if (_symbolTable.replacement(undefAtom) != undefAtom)
|
|
|
|
continue;
|
|
|
|
|
2013-04-25 03:00:26 +08:00
|
|
|
// Seems like this symbol is undefined. Warn that.
|
|
|
|
foundUndefines = true;
|
2013-08-07 06:31:59 +08:00
|
|
|
if (_context.printRemainingUndefines()) {
|
2013-04-11 10:56:30 +08:00
|
|
|
llvm::errs() << "Undefined Symbol: " << undefAtom->file().path()
|
|
|
|
<< " : " << undefAtom->name() << "\n";
|
2013-02-01 06:56:13 +08:00
|
|
|
}
|
2012-04-19 05:55:06 +08:00
|
|
|
}
|
2013-04-05 02:59:24 +08:00
|
|
|
if (foundUndefines) {
|
2013-08-07 06:31:59 +08:00
|
|
|
if (_context.printRemainingUndefines())
|
2013-04-05 02:59:24 +08:00
|
|
|
llvm::errs() << "symbol(s) not found\n";
|
|
|
|
return true;
|
|
|
|
}
|
2012-04-19 05:55:06 +08:00
|
|
|
}
|
2013-04-05 02:59:24 +08:00
|
|
|
return false;
|
2011-12-18 16:27:59 +08:00
|
|
|
}
|
|
|
|
|
2012-04-19 05:55:06 +08:00
|
|
|
|
2011-12-18 16:27:59 +08:00
|
|
|
// remove from _atoms all coaleseced away atoms
|
|
|
|
void Resolver::removeCoalescedAwayAtoms() {
|
2013-05-29 02:55:39 +08:00
|
|
|
ScopedTask task(getDefaultDomain(), "removeCoalescedAwayAtoms");
|
2011-12-18 16:27:59 +08:00
|
|
|
_atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(),
|
|
|
|
AtomCoalescedAway(_symbolTable)), _atoms.end());
|
|
|
|
}
|
|
|
|
|
|
|
|
void Resolver::linkTimeOptimize() {
|
|
|
|
// FIX ME
|
|
|
|
}
|
|
|
|
|
2013-04-05 02:59:24 +08:00
|
|
|
bool Resolver::resolve() {
|
2013-10-11 14:26:16 +08:00
|
|
|
if (!this->resolveUndefines())
|
|
|
|
return false;
|
2011-12-18 16:27:59 +08:00
|
|
|
this->updateReferences();
|
2013-10-17 03:21:50 +08:00
|
|
|
this->deadStripOptimize();
|
2013-04-05 02:59:24 +08:00
|
|
|
if (this->checkUndefines(false)) {
|
2013-08-07 06:31:59 +08:00
|
|
|
if (!_context.allowRemainingUndefines())
|
2013-10-11 14:16:33 +08:00
|
|
|
return false;
|
2013-04-05 02:59:24 +08:00
|
|
|
}
|
2011-12-18 16:27:59 +08:00
|
|
|
this->removeCoalescedAwayAtoms();
|
|
|
|
this->linkTimeOptimize();
|
2013-10-29 13:12:14 +08:00
|
|
|
this->_result->addAtoms(_atoms);
|
2013-10-11 14:16:33 +08:00
|
|
|
return true;
|
2011-12-18 16:27:59 +08:00
|
|
|
}
|
|
|
|
|
2012-03-08 08:18:30 +08:00
|
|
|
void Resolver::MergedFile::addAtom(const Atom& atom) {
|
2012-04-04 02:39:40 +08:00
|
|
|
if (const DefinedAtom* defAtom = dyn_cast<DefinedAtom>(&atom)) {
|
2012-03-08 08:18:30 +08:00
|
|
|
_definedAtoms._atoms.push_back(defAtom);
|
2012-04-04 02:39:40 +08:00
|
|
|
} else if (const UndefinedAtom* undefAtom = dyn_cast<UndefinedAtom>(&atom)) {
|
2012-03-08 08:18:30 +08:00
|
|
|
_undefinedAtoms._atoms.push_back(undefAtom);
|
2012-04-03 07:56:36 +08:00
|
|
|
} else if (const SharedLibraryAtom* slAtom =
|
2012-04-04 02:39:40 +08:00
|
|
|
dyn_cast<SharedLibraryAtom>(&atom)) {
|
2012-03-08 08:18:30 +08:00
|
|
|
_sharedLibraryAtoms._atoms.push_back(slAtom);
|
2012-04-04 02:39:40 +08:00
|
|
|
} else if (const AbsoluteAtom* abAtom = dyn_cast<AbsoluteAtom>(&atom)) {
|
2012-03-08 08:18:30 +08:00
|
|
|
_absoluteAtoms._atoms.push_back(abAtom);
|
2012-04-03 07:56:36 +08:00
|
|
|
} else {
|
2012-06-16 04:37:24 +08:00
|
|
|
llvm_unreachable("atom has unknown definition kind");
|
2012-03-08 08:18:30 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-24 06:32:56 +08:00
|
|
|
|
|
|
|
MutableFile::DefinedAtomRange Resolver::MergedFile::definedAtoms() {
|
|
|
|
return range<std::vector<const DefinedAtom*>::iterator>(
|
|
|
|
_definedAtoms._atoms.begin(), _definedAtoms._atoms.end());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-03-08 08:18:30 +08:00
|
|
|
void Resolver::MergedFile::addAtoms(std::vector<const Atom*>& all) {
|
2013-05-29 02:55:39 +08:00
|
|
|
ScopedTask task(getDefaultDomain(), "addAtoms");
|
2012-06-01 06:34:00 +08:00
|
|
|
DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "Resolver final atom list:\n");
|
2012-04-09 07:52:13 +08:00
|
|
|
for ( const Atom *atom : all ) {
|
2012-06-01 06:34:00 +08:00
|
|
|
DEBUG_WITH_TYPE("resolver", llvm::dbgs()
|
|
|
|
<< llvm::format(" 0x%09lX", atom)
|
|
|
|
<< ", name="
|
|
|
|
<< atom->name()
|
|
|
|
<< "\n");
|
2012-04-09 07:52:13 +08:00
|
|
|
this->addAtom(*atom);
|
2012-03-08 08:18:30 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-12-18 16:27:59 +08:00
|
|
|
} // namespace lld
|