diff options
| author | Rui Ueyama <ruiu@google.com> | 2013-09-12 19:14:05 +0000 |
|---|---|---|
| committer | Rui Ueyama <ruiu@google.com> | 2013-09-12 19:14:05 +0000 |
| commit | e5416ec2d21854f34801c33ef567072d3e647f6f (patch) | |
| tree | f216f2c3028f202636221ce64abf9cf5a3dbfeb3 | |
| parent | 1e2e3ea584121f523aa4118f383927ed6b73246c (diff) | |
| download | bcm5719-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.h | 3 | ||||
| -rw-r--r-- | lld/include/lld/Core/UndefinedAtom.h | 8 | ||||
| -rw-r--r-- | lld/lib/Core/Resolver.cpp | 9 | ||||
| -rw-r--r-- | lld/lib/Core/SymbolTable.cpp | 11 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/Native/NativeFileFormat.h | 2 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/Native/ReaderNative.cpp | 13 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp | 17 | ||||
| -rw-r--r-- | lld/test/core/undef-fallback.objtxt | 18 |
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 |

