forked from OSchip/llvm-project
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
This commit is contained in:
parent
1e2e3ea584
commit
e5416ec2d2
|
|
@ -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 *);
|
||||
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
//
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
Loading…
Reference in New Issue