Add a fallback mechanism for undefined atom.
In COFF, an undefined symbol can have up to one alternative name. If a symbol
is resolved by its regular name, then it's linked normally. If a symbol is not
found in any input files, all references to the regular name are resolved using
the alternative name. If the alternative name is not found, it's a link error.
This mechanism is called "weak externals".
To support this mechanism, I added a new member function fallback() to undefined
atom. If an undefined atom has the second name, fallback() returns a new undefined
atom that should be used instead of the original one to resolve undefines. If it
does not have the second name, the function returns nullptr.
Differential Revision: http://llvm-reviews.chandlerc.com/D1550
llvm-svn: 190625
diff --git a/lld/lib/Core/Resolver.cpp b/lld/lib/Core/Resolver.cpp
index d56f7d1..716f0d4 100644
--- a/lld/lib/Core/Resolver.cpp
+++ b/lld/lib/Core/Resolver.cpp
@@ -198,7 +198,7 @@
undefineGenCount = _symbolTable.size();
std::vector<const UndefinedAtom *> undefines;
_symbolTable.undefines(undefines);
- for ( const Atom *undefAtom : undefines ) {
+ for (const UndefinedAtom *undefAtom : undefines) {
StringRef undefName = undefAtom->name();
// load for previous undefine may also have loaded this undefine
if (!_symbolTable.isDefined(undefName)) {
@@ -208,6 +208,13 @@
false, // dataSymbolOnly
*this);
}
+ // 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 (const UndefinedAtom *fallbackUndefAtom = undefAtom->fallback()) {
+ _symbolTable.addReplacement(undefAtom, fallbackUndefAtom);
+ _symbolTable.add(*fallbackUndefAtom);
+ }
}
// search libraries for overrides of common symbols
if (searchArchives || searchSharedLibs) {
diff --git a/lld/lib/Core/SymbolTable.cpp b/lld/lib/Core/SymbolTable.cpp
index 3b43c2e..8fee4bb 100644
--- a/lld/lib/Core/SymbolTable.cpp
+++ b/lld/lib/Core/SymbolTable.cpp
@@ -311,6 +311,11 @@
return true;
}
+void SymbolTable::addReplacement(const Atom *replaced,
+ const Atom *replacement) {
+ _replacedAtoms[replaced] = replacement;
+}
+
const Atom *SymbolTable::replacement(const Atom *atom) {
AtomToAtom::iterator pos = _replacedAtoms.find(atom);
if (pos == _replacedAtoms.end())
@@ -328,8 +333,12 @@
end = _nameTable.end(); it != end; ++it) {
const Atom *atom = it->second;
assert(atom != nullptr);
- if (const auto undef = dyn_cast<const UndefinedAtom>(atom))
+ if (const auto undef = dyn_cast<const UndefinedAtom>(atom)) {
+ AtomToAtom::iterator pos = _replacedAtoms.find(undef);
+ if (pos != _replacedAtoms.end())
+ continue;
undefs.push_back(undef);
+ }
}
}