summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRui Ueyama <ruiu@google.com>2013-09-12 19:14:05 +0000
committerRui Ueyama <ruiu@google.com>2013-09-12 19:14:05 +0000
commite5416ec2d21854f34801c33ef567072d3e647f6f (patch)
treef216f2c3028f202636221ce64abf9cf5a3dbfeb3
parent1e2e3ea584121f523aa4118f383927ed6b73246c (diff)
downloadbcm5719-llvm-e5416ec2d21854f34801c33ef567072d3e647f6f.tar.gz
bcm5719-llvm-e5416ec2d21854f34801c33ef567072d3e647f6f.zip
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
-rw-r--r--lld/include/lld/Core/SymbolTable.h3
-rw-r--r--lld/include/lld/Core/UndefinedAtom.h8
-rw-r--r--lld/lib/Core/Resolver.cpp9
-rw-r--r--lld/lib/Core/SymbolTable.cpp11
-rw-r--r--lld/lib/ReaderWriter/Native/NativeFileFormat.h2
-rw-r--r--lld/lib/ReaderWriter/Native/ReaderNative.cpp13
-rw-r--r--lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp17
-rw-r--r--lld/test/core/undef-fallback.objtxt18
8 files changed, 72 insertions, 9 deletions
diff --git a/lld/include/lld/Core/SymbolTable.h b/lld/include/lld/Core/SymbolTable.h
index fac76d07507..0cf1e2e1048 100644
--- a/lld/include/lld/Core/SymbolTable.h
+++ b/lld/include/lld/Core/SymbolTable.h
@@ -67,6 +67,9 @@ public:
/// @brief count of by-name entries in symbol table
unsigned int size();
+ /// @brief add atom to replacement table
+ void addReplacement(const Atom *replaced, const Atom *replacement);
+
/// @brief if atom has been coalesced away, return replacement, else return atom
const Atom *replacement(const Atom *);
diff --git a/lld/include/lld/Core/UndefinedAtom.h b/lld/include/lld/Core/UndefinedAtom.h
index eec131c9208..8bfbedce1c6 100644
--- a/lld/include/lld/Core/UndefinedAtom.h
+++ b/lld/include/lld/Core/UndefinedAtom.h
@@ -56,6 +56,14 @@ public:
}
static inline bool classof(const UndefinedAtom *) { return true; }
+ /// Returns an undefined atom if this undefined symbol has a synonym. This is
+ /// mainly used in COFF. In COFF, an unresolved external symbol can have up to
+ /// one optional name (sym2) in addition to its regular name (sym1). If a
+ /// definition of sym1 exists, sym1 is resolved normally. Otherwise, all
+ /// references to sym1 refer to sym2 instead. In that case sym2 must be
+ /// resolved, or link will fail.
+ virtual const UndefinedAtom *fallback() const { return nullptr; }
+
protected:
UndefinedAtom() : Atom(definitionUndefined) {}
virtual ~UndefinedAtom() {}
diff --git a/lld/lib/Core/Resolver.cpp b/lld/lib/Core/Resolver.cpp
index d56f7d1067f..716f0d48d53 100644
--- a/lld/lib/Core/Resolver.cpp
+++ b/lld/lib/Core/Resolver.cpp
@@ -198,7 +198,7 @@ void Resolver::resolveUndefines() {
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 @@ void Resolver::resolveUndefines() {
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 3b43c2effa8..8fee4bb41e3 100644
--- a/lld/lib/Core/SymbolTable.cpp
+++ b/lld/lib/Core/SymbolTable.cpp
@@ -311,6 +311,11 @@ bool SymbolTable::isDefined(StringRef sym) {
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 @@ void SymbolTable::undefines(std::vector<const UndefinedAtom *> &undefs) {
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);
+ }
}
}
diff --git a/lld/lib/ReaderWriter/Native/NativeFileFormat.h b/lld/lib/ReaderWriter/Native/NativeFileFormat.h
index 5a715e54e37..6686eb340cd 100644
--- a/lld/lib/ReaderWriter/Native/NativeFileFormat.h
+++ b/lld/lib/ReaderWriter/Native/NativeFileFormat.h
@@ -164,10 +164,10 @@ struct NativeAtomAttributesV1 {
struct NativeUndefinedAtomIvarsV1 {
uint32_t nameOffset;
uint32_t flags;
+ uint32_t fallbackNameOffset;
};
-
//
// The NCS_SharedLibraryAtomsV1 chunk contains an array of these structs
//
diff --git a/lld/lib/ReaderWriter/Native/ReaderNative.cpp b/lld/lib/ReaderWriter/Native/ReaderNative.cpp
index 31024a06fab..0554dcecd1f 100644
--- a/lld/lib/ReaderWriter/Native/ReaderNative.cpp
+++ b/lld/lib/ReaderWriter/Native/ReaderNative.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "lld/ReaderWriter/Reader.h"
+#include "lld/ReaderWriter/Simple.h"
#include "lld/Core/Atom.h"
#include "lld/Core/Error.h"
@@ -134,10 +135,12 @@ public:
return (CanBeNull)(_ivarData->flags & 0x3);
}
+ virtual const UndefinedAtom *fallback() const;
private:
const File *_file;
const NativeUndefinedAtomIvarsV1 *_ivarData;
+ mutable std::unique_ptr<const SimpleUndefinedAtom> _fallback;
};
@@ -860,8 +863,14 @@ inline StringRef NativeUndefinedAtomV1::name() const {
return _file->string(_ivarData->nameOffset);
}
-
-
+inline const UndefinedAtom *NativeUndefinedAtomV1::fallback() const {
+ if (!_ivarData->fallbackNameOffset)
+ return nullptr;
+ if (!_fallback)
+ _fallback.reset(new SimpleUndefinedAtom(
+ *_file, _file->string(_ivarData->fallbackNameOffset)));
+ return _fallback.get();
+}
inline const lld::File& NativeSharedLibraryAtomV1::file() const {
return *_file;
diff --git a/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp b/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp
index 404bad73d99..5109097bd2f 100644
--- a/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp
+++ b/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "lld/ReaderWriter/Reader.h"
+#include "lld/ReaderWriter/Simple.h"
#include "lld/ReaderWriter/Writer.h"
#include "lld/Core/ArchiveLibraryFile.h"
@@ -957,10 +958,13 @@ template <> struct MappingTraits<const lld::UndefinedAtom *> {
class NormalizedAtom : public lld::UndefinedAtom {
public:
NormalizedAtom(IO &io)
- : _file(fileFromContext(io)), _name(), _canBeNull(canBeNullNever) {}
+ : _file(fileFromContext(io)), _name(), _canBeNull(canBeNullNever),
+ _fallback(nullptr) {}
+
NormalizedAtom(IO &io, const lld::UndefinedAtom *atom)
: _file(fileFromContext(io)), _name(atom->name()),
- _canBeNull(atom->canBeNull()) {}
+ _canBeNull(atom->canBeNull()), _fallback(atom->fallback()) {}
+
const lld::UndefinedAtom *denormalize(IO &io) {
ContextInfo *info = reinterpret_cast<ContextInfo *>(io.getContext());
assert(info != nullptr);
@@ -972,10 +976,11 @@ template <> struct MappingTraits<const lld::UndefinedAtom *> {
DEBUG_WITH_TYPE("WriterYAML",
llvm::dbgs() << "created UndefinedAtom named: '" << _name
- << "' (" << (void *)_name.data() << ", "
- << _name.size() << ")\n");
+ << "' (" << (void *)_name.data() << ", "
+ << _name.size() << ")\n");
return this;
}
+
// Extract current File object from YAML I/O parsing context
const lld::File &fileFromContext(IO &io) {
ContextInfo *info = reinterpret_cast<ContextInfo *>(io.getContext());
@@ -987,10 +992,12 @@ template <> struct MappingTraits<const lld::UndefinedAtom *> {
virtual const lld::File &file() const { return _file; }
virtual StringRef name() const { return _name; }
virtual CanBeNull canBeNull() const { return _canBeNull; }
+ virtual const UndefinedAtom *fallback() const { return _fallback; }
const lld::File &_file;
StringRef _name;
CanBeNull _canBeNull;
+ const UndefinedAtom *_fallback;
};
static void mapping(IO &io, const lld::UndefinedAtom *&atom) {
@@ -1000,6 +1007,8 @@ template <> struct MappingTraits<const lld::UndefinedAtom *> {
io.mapRequired("name", keys->_name);
io.mapOptional("can-be-null", keys->_canBeNull,
lld::UndefinedAtom::canBeNullNever);
+ io.mapOptional("fallback", keys->_fallback,
+ (const lld::UndefinedAtom *)nullptr);
}
};
diff --git a/lld/test/core/undef-fallback.objtxt b/lld/test/core/undef-fallback.objtxt
new file mode 100644
index 00000000000..8be4feef020
--- /dev/null
+++ b/lld/test/core/undef-fallback.objtxt
@@ -0,0 +1,18 @@
+# RUN: lld -core %s | FileCheck %s
+
+# Test that fallback atoms can be parsed by YAML reader and processed by the
+# core linker.
+
+---
+defined-atoms:
+ - name: bar
+ type: code
+
+undefined-atoms:
+ - name: foo
+ fallback:
+ name: bar
+...
+
+# CHECK: defined-atoms:
+# CHECK-NEXT: - name: bar
OpenPOWER on IntegriCloud